SAM = Single Abstract Method. It's just another way of saying FunctionalInterface (technically the latter is more correct too because an abstract class with a single abstract method doesnt qualify for a SAM type). So in Java instead of having T -> ()
we have Consumer<T>
. But nothing prevents me from writing an equivalent type:
interface MyDifferentConsumer<T> {
void consume(T t);
}
This also represents T-> ()
, it just has a different name. I think the best place we can see how this affects inference is with method references. In java, both of these are perfectly valid:
Consumer<String> c1 = System.out::println;
MyDifferentConsumer<String> c2 = System.out::println;
So then, a question you might ask is, "what is the type of the expression System.out::println
? It qualifies for both of these completely disparate types!" The answer is, essentially, it doesn't have one. There are special rules in the JLS for determining if a method reference expression is assignment compatible to any given SAM.
Because System.out::println
doesnt really have a type, the following is invalid:
var c1 = System.out::println;
var c2 = System.out::println;
and from my last example, it's easy to see why.
If java had actual function types, all of those special rules wouldnt be necessary and both of those would just infer to String -> ()
.