163

Reading up on the Java-8 spec, I keep seeing references to 'SAM types'. I haven't been able to find a clear explanation of what this is.

What is a SAM type and what is an example scenario of when one might be used?

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Cody
  • 2,451
  • 2
  • 20
  • 19
  • 4
    See http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html (which I found after a single search, which took me to another SO question). – Jon Skeet Jul 28 '13 at 22:13
  • Thats exactly what I needed. Thanks! Just out of curiosity, what keyword did you use in your search? – Cody Jul 28 '13 at 22:33
  • 2
    Please don't refer people to out-of-date information. A slightly longer search would have taken you to the more up-to-date version: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html, which itself is 18 months old and now outdated in many places. The OP's question is answered at http://www.lambdafaq.org/what-is-a-functional-interface/, one page in an FAQ which I try to keep up to date in what has been until recently a rapidly-changing language and API development. – Maurice Naftalin Jul 28 '13 at 22:41
  • 1
    @MauriceNaftalin You could also just link [the Java trail](http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html), which is kept up to date by the development team. – Brian Jul 28 '13 at 22:52
  • 1
    The current term is "functional interface". – newacct Jul 29 '13 at 03:33
  • 1
    @MauriceNaftalin: Sorry, missed that one. Would certainly have linked to it if I'd found that. – Jon Skeet Jul 29 '13 at 05:41
  • the "final" state of the lambda link: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html – Amir Uval Jun 27 '17 at 11:08

1 Answers1

184

To summarize the link Jon posted1 in case it ever goes down, "SAM" stands for "single abstract method", and "SAM-type" refers to interfaces like Runnable, Callable, etc. Lambda expressions, a new feature in Java 8, are considered a SAM type and can be freely converted to them.

For example, with an interface like this:

public interface Callable<T> {
    public T call();
}

You can declare a Callable using lambda expressions like this:

Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"

Lambda expressions in this context are mostly just syntactic sugar. They look better in code than anonymous classes and are less restrictive on method naming. Take this example from the link:

class Person { 
    private final String name;
    private final int age;

    public static int compareByAge(Person a, Person b) { ... }

    public static int compareByName(Person a, Person b) { ... }
}

Person[] people = ...
Arrays.sort(people, Person::compareByAge);

This creates a Comparator using a specific method that doesn't share the same name as Comparator.compare, that way you don't have to follow the interface naming of methods and you can have multiple comparison overrides in a class, then create the comparators on the fly via the lambda expressions.

Going Deeper...

On a deeper level, Java implements these using the invokedynamic bytecode instruction added in Java 7. I said earlier that declaring a Lambda creates an instance of Callable or Comparable similar to an anonymous class, but that's not strictly true. Instead, the first time the invokedynamic is called, it creates a Lambda function handler using the LambdaMetafactory.metafactory method, then uses this cached instance in future invocations of the Lambda. More info can be found in this answer.

This approach is complex and even includes code that can read primitive values and references directly from stack memory to pass into your Lambda code (e.g. to get around needing to allocate an Object[] array to invoke your Lambda), but it allows future iterations of the Lambda implementation to replace old implementations without having to worry about bytecode compatibility. If the engineers at Oracle change the underlying Lambda implementation in a newer version of the JVM, Lambdas compiled on an older JVM will automatically use the newer implementation without any changes on the developer's part.


1 The syntax on the link is out of date. Take a look at the Lambda Expressions Java Trail to see the current syntax.

Brian
  • 17,079
  • 6
  • 43
  • 66