Home > Mobile >  Java: specific Object as a generic type in Iterable
Java: specific Object as a generic type in Iterable

Time:06-22

Is there a way like in typescript, to create Objects with 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);

CodePudding user response:

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 enums 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 runetime.

As I've already said, you can't define the type inline. But 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 on 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
}

CodePudding user response:

Java doesn't support this type of anonymous object types. You'd have to create a class for that.

However, your method name seems to indicate that the months will be unique. That makes a Map<String, Double> a possible alternative. The map keys are the months, the values are the hours.

Iterating over the map can be done in a few ways:

  1. Use Map.forEach:

    hoursByMonth.forEach((month, hours) -> { ... });
    
  2. Use Map.entrySet:

    // you can also use entrySet().stream, or entrySet().iterator()
    for (Map.Entry<String, Double> entry : hoursByMonth.entrySet()) {
        String month = entry.getKey();
        double hours = entry.getValue();
    }
    

CodePudding user response:

Beside the class and map approach I would also suggest the interface approach - depending on your needs:

public interface MonthHoursProvider {
    String month();
    double hours();
}

Or you use something like a generic tuple.

  • Related