Issue
Is there a way in Java to create Objects inline, like in TypeScript using square brackets, and use them in an Iterable?
If this isn't possible, which one is the best way to implement this functionality?
Example:
public Iterable<{ "month" : String, "hours" : double }> getHoursGroupByMonth(int userId);
Solution
At the first glance, TypeScript might look similar to Java, but it's a delusion. TypeScript is a superset of JavaScript. These languages are very different from Java.
In Java, everything is build around classes. To create an object in Java you always need a class (or enum, or record, which are basically special kinds of classes), the only exception is an array (they are build into the language, and you don't refer to any class to instantiate them, but nevertheless arrays are objects and instances of the Object
type). You can not create a custom object inline in Java.
Conversely, in TypeScript and JavaScript everything is build around objects. You can create objects inline, in TypeScript you can define a type inline. Inheritance is based on the prototype chain (each object has a private property which holds a link to another object). All these mechanisms are alien to Java. And yes, classes exists in TypeScript and the latest versions of JavaScript, but they are only syntactic sugar over the constructor functions.
Let's get to the point. You need a type that has the following shape:
{ "month" : String, "hours" : double }
By the way: there's an enum Month
in the java.time
package, it's a good practice to favor enum
s over strings (because enum provedes you a behaviour that a plain string can't offer and guards you from making typo).
Java is statically typed. And everything needs to have a type at the moment of compilation. The "shape" of each object should exist somewhere, so that the compiler can verify that it's being treated correctly in your code, and you're not expecting from the object something that it's not capable of (JavaScript forgive you such thing, but Java not). And every type would eventually reside in a .class
file which can be used by the JVM at runtime.
As I've already said, you can't define the type inline. But it doesn't mean that you need to create a separate file for every type. In Java, we have a notion of nested classes. Note, that it's not a good idea to nest two unrelated classes into each other, by declaring a class inside another you're saying that the enclosing class uses somehow the nested class (or least the reader of the code would expect that).
That's how you can define such a type using Java 16 records:
public record MonthHours(Month month, double hours) {}
And it would be an equivalent of the following class:
public class MonthHours {
private Month month;
private double hours;
public MonthHours(Month month, double hours) {
this.month = month;
this.hours = hours;
}
// getters, equals/hashCode, toString
}
Answered By - Alexander Ivanchenko
Answer Checked By - David Goodson (JavaFixing Volunteer)