6

In java, you can add Type parameters to static methods, to create methods that handle generics. Can you do the same with lambdas?

In my code I have

final private static <K,V> Supplier<Map<K, List<V>> supplier=HashMap::new;

I'm trying to do type parameters like it's a function, but it won't let me.

And if I do:

    final private static Supplier<Map<?, List<?>>> supplier=HashMap::new;

It doesn't accept the argument where I try to use it. What can I do?

6
  • 1
    That cannot be a variable. In fact, it's useless to declare a variable like WhateverClassThatSupportsGenerics<?> var = ...; unless it's a parameter of a method. Commented Aug 23, 2015 at 14:48
  • Where do you try to use the second declaration? (The first, as you've likely discovered, is syntatically invalid.) Commented Aug 23, 2015 at 14:56
  • 1
    It is not possible to construct a bounded generic object. Your line of code fails for the same reason new HashMap<Integer, List<?>> is legal, but new HashMap<?, List<?>> is not. ? means "I don't know what type this HashMap uses," but when you create a HashMap, you always know what you intend to put in it (even if you decide it's java.lang.Object). Commented Aug 23, 2015 at 16:37
  • 1
    @VGR: thanks to the “diamond operator”, that rule is obsolete. You can say HashMap<?, ?> map=new HashMap<>(); without specifying actual type arguments. Though such a map would not be of much use… Commented Aug 24, 2015 at 8:18
  • @Holger Interesting. I didn't know that was possible. I've always assumed the diamond operator was just a convenience that saved a bit of typing. Commented Aug 24, 2015 at 18:44

1 Answer 1

8

One workaround for this may be to wrap the method reference into a method, so that target type deduction resolves the type at the call site:

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

public class GenericLambda
{
    // Syntactically invalid
    //final private static <K,V> Supplier<Map<K, List<V>> supplier=HashMap::new;

    final private static Supplier<Map<?, List<?>>> supplier=HashMap::new;

    // A workaround
    private static <K,V> Supplier<Map<K, List<V>>> supplier()
    {
        return HashMap::new;
    }


    public static void main(String[] args)
    {
        // Does not work
        //useSupplier(supplier);

        // Works
        useSupplier(supplier());
    }

    private static <K, V> void useSupplier(Supplier<Map<K, List<V>>> s)
    {
        System.out.println(s.get());
    }
}
Sign up to request clarification or add additional context in comments.

10 Comments

@NoDataFound Not sure what you mean, but here, no cast is required (although a brutal cast might be safe as well in this case, as all type parameters turn into Object anyhow when they are compiled...)
Though there is not much benefit in writing supplier() as a method argument instead of directly writing HashMap::new at that place…
That would imply that all call sites similarly agree that such a switch of the implementation class is acceptable and even intended. Otherwise, you have to go through all place and verify this assumption. And while the possibility of changing HashMap::new to LinkedHashMap::new at a single method sounds like a huge advantage from a pure OO view, it isn’t in a world where we have decent search-and-replace tools which can not only replace all occurrences of HashMap::new to LinkedHashMap::new but also show each place to allow the programmer’s intervention…
@Holger: I'm not sure what you are questioning here: All this is known as the factory method pattern. And according to Lishkov, everything that works with a HashMap also works with a LinkedHashMap. However, I just wanted to sketch a workaround to achieve the goal that the OP described.
There must be a reason why not everyone is using LinkedHashMap instead of HashMap all the time… Nevertheless, you just wanted to sketch a workaround to achieve the goal that the OP described, assuming that this is what the OP wanted, as I can’t really deduce from the question why he tries what he tries, and I only wanted to mention that I don’t see a real benefit of wrapping an expression as simple as HashMap::new in a factory method (especially a private one). Not without a specified purpose for the factory method. But maybe the OP will come back and tell us a bit more about it…
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.