0

Let's say I have a simple interface:

interface IGroupBy {
  String getGroupById();
}

Say I have a list of this:

List<IGroupBy> v = List.of();

But this means that the list has to implement that interface by name. But what if I am willing to accept any object that had a method that returns a string with that name?

Is there a way to get structural typing in Java using generics somehow?

List<T> v = List.of();

and then tell the Java compiler about T? Something like:

<T hasInterface:IGroupBy>

I suppose one way to get part of the way there is using generics like this:

   interface IGroupBy<T> {
      T getGroupById();
   }

the remaining part is the method name. But that still means you have to reference the same exact interface by name/package.

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • 1
    What is the problem to inherit that interface? – Vlad Hanzha Feb 17 '19 at 08:35
  • @VladHanzha not a huge problem, but the motivations for structural typing instead of nominative typing are the reasons why we wouldn't want to use the interface by name – Alexander Mills Feb 17 '19 at 08:37
  • In that case I'd suggest you to take a look at functional interfaces, if I understand you correctly it can work for you. – Vlad Hanzha Feb 17 '19 at 08:44
  • @VladHanzha cool if you can post an answer - I think it would be one of the first answers on SO talking about *java+structural typing+functional interfaces* – Alexander Mills Feb 17 '19 at 08:46
  • maybe this helps (not sure if this may be a duplicate): https://stackoverflow.com/questions/1079785/whats-an-example-of-duck-typing-in-java I think it is as close as you can get to that in Java – user140547 Feb 17 '19 at 08:54

2 Answers2

1

I am not sure if this is what you are asking for, but I believe that you are talking about java covariance.

Basically, lets say that you have the following class:

class  TestClass implements IGroupBy { 
    private String id; 
    TestClass(String id) {
        this.id = id;
    }   
    @Override
    public String getGroupById() {
        return id;
    }
}

And now, if you have the following list:

 List<TestClass> list = List.of(
                new TestClass("test1"),
                new TestClass("test2")
        );

You would like to be able to write something like:

List<IGroupBy> interfaceList = list;

This is supported in java by using a wildcard and can be done like this :

List<? extends IGroupBy> interfaceList = list;
Dimitar Spasovski
  • 2,023
  • 9
  • 29
  • 45
  • yeah I've never understood the difference in this case between `List extends IGroupBy>` and simply `List` – Alexander Mills Feb 17 '19 at 08:47
  • 2
    I believe that Jon Skeet explains that fairly well as an answer on this question https://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-are-java-generics-not-implicitly-po – Dimitar Spasovski Feb 17 '19 at 08:54
1

I think the closest thing in Java for what you want to achieve is lambdas and functional interfaces. That's a good article to read about it: https://www.baeldung.com/java-8-functional-interfaces

    List<Function<Integer, Object>> calculators = new ArrayList<>();

    calculators.add((number) -> externalCalculator.calculate(number));
    calculators.add((number) -> number * number);

    calculators.forEach(c -> c.apply(1));

In this example you can see how you can add different logic without any common interfaces to one list(Basically we have Function interface, but I think it's not a problem in this case).

To sum up, Java isn't the best language for such things.

Vlad Hanzha
  • 464
  • 3
  • 11