0

I am trying to implement a Map<String, Interface> where the interface in question takes in and returns a generic value, so that different functions in the map could have different return types but still using the same interface. I'm not quite sure how it would work but the goal would be to achieve something along these lines below.

// A generic interface of some kind
public interface Action {
    Object doAction(Object object);
}
// The class which implements the map
public class MyClass { 

    public void example() {
        HashMap<String, Action> map = new HashMap<>();

        // this takes in a boolean and returns the opposing value
        map.put("functionOne", (boolean bool) -> !bool);

        // this takes in an integer, increments it and returns it.
        map.put("functionTwo", (int integer) -> integer++);

        ...
    }
}

Obviously this pseudo code isn't right and I might be way off track but I hope it gives you an understanding of what I'm trying to achieve. Any help would be appreciated.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
eFlat
  • 182
  • 4
  • 15
  • 3
    You can't do this, at least not just like this. If you want something like, this you will need to jump through more hoops, where for example the key holds the type of the `Action`, and then you need to do more things to ensure type-safety. – Mark Rotteveel Dec 18 '19 at 14:22
  • 1
    For example, something like [How to create a generic typesafe HashMap by class type?](https://stackoverflow.com/questions/22941715/how-to-create-a-generic-typesafe-hashmap-by-class-type), but then your key would be an object that holds the `Class` for the type information, and I guess you will have to rely on unsafe casts to make things work. – Mark Rotteveel Dec 18 '19 at 14:28
  • 3
    Mark is right; one could create a map, but at the usage one has to know all, as java is typed. No primitive types, at the call site providing the right parameter and casting the result. And more. In fact such a map is not useful for heterogene dispatch.. – Joop Eggen Dec 18 '19 at 14:31
  • Is there a way which this would work without the interface? For example, have a map of type (not too sure what the correct type would be as Runnable is for void only right?). That way the map is just storing strings with functions as the key. – eFlat Dec 18 '19 at 14:51
  • 1
    @saxophonix Function, Callable (the standard interfaces) take parameters or return values of generic type, therefore they are generic interfaces. So there is no way to dodge the problem of type-safety in case of creating a map. Since Runnable does not take parameters, it is not what you are looking for also. – Steyrix Dec 18 '19 at 14:56

1 Answers1

0

First of all, your interface should be declared as FunctionalInterface. Second, since your doAction method takes Object as an argument, I see no point in returning it, unless you want to preserve the original object. You can just modify the object inside the method and make your method void. After invoking the method, your object, which was passed, will be modified. (you want to use objects like Int, Boolean and etc., which wrap up the primitive types)

But overall, this approach seems a little bit old styled and unreliable one. Since this will lead you to creating if statements to ensure you are operating the right type (As some of the colleagues have written in comments).

What I would do is to make Action generic.

@FunctionalInterface
public interface Action<T> {
    T doAction(T argument);
} 

Then just declare your functions like below and use them without creating a collection for them, because it will result in writing more code to ensure type-safety.

Action<Boolean> booleanFunc = (Boolean bool) -> {...};
Steyrix
  • 2,796
  • 1
  • 9
  • 23
  • Thank you, it's all making more sense to me now, think I was just over complicating things on my part but this solution will work for me! :) – eFlat Dec 18 '19 at 15:01
  • Your first sentence is incorrect. Any interface with exactly one abstract method is automatically considered a functional interface; `@FunctionalInterface` is just a formality and is not needed. – VGR Dec 18 '19 at 15:18
  • @VGR you are right :) I just used incorrect word. Sometimes it is really helpful to use annotation like this, since they increase readability of code, that is what I meant – Steyrix Dec 18 '19 at 15:21