20

I learn new features of Java 8.

I am playing with different examples and I have found a strange behaviour:

public static void main(String[] args) {       
    method(Test::new);
}
static class Test{
}

private static void method(Supplier<Test> testSupplier){
    Test test = testSupplier.get();
}

This code compiles successfully but I have no idea how it works.

Why is Test::new acceptable as Supplier?

Supplier interface looks very simple:

@FunctionalInterface
public interface Supplier<T> {    
    T get();
}
Tunaki
  • 132,869
  • 46
  • 340
  • 423
gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • 2
    For dynamically implementing which sort of happens AFAIK there is this beast: [`java.lang.invoke.LambdaMetafactory`](https://docs.oracle.com/javase/8/docs/api/java/lang/invoke/LambdaMetafactory.html) – zapl Sep 21 '15 at 20:36
  • 3
    Note that an "empty" class declaration, such as for your `class Test`, implicitly has a no-arg constructor. That's why you can write `new Test()` and have it work, any why a lambda or method reference to this constructor works. – Stuart Marks Sep 21 '15 at 20:39
  • @Sotirios Delimanolis maybe first comment to linked question is more relevant – gstackoverflow Sep 21 '15 at 21:05

3 Answers3

19

The Supplier interface has a single (functional) method that:

  • does not take any parameters;
  • returns an object.

Therefore, any method that comply with those two points, comply with the functional contract of Supplier (because the methods will have the same signature).

Here, the method in question is a method reference. It takes no parameters and returns a new instance of Test. You could rewrite it to:

method(() -> new Test());

Test::new in syntactic sugar for this lambda expression.

Tunaki
  • 132,869
  • 46
  • 340
  • 423
11

Test::new is a method reference. Rather than adding a new explanation it's worth taking a look at the tutorial for method references as it explains them pretty well.

The direct answer to your question is that Supplier is a functional interface - meaning that it has a single non-default method. The constructor for Test has exactly the same signature (no arguments, returns Test) and so can be directly referenced to create an anonymous Supplier.

There are four flavours of method references: check out the tutorial to understand them all.

sprinter
  • 27,148
  • 6
  • 47
  • 78
  • Thus this feature allow that old classes can implement newly created interface. WoW! – gstackoverflow Sep 21 '15 at 20:54
  • 1
    @gstackoverflow Yes that's correct. As long as the signatures match you can refer to the method to create an instance of the interface. When used well it can substantially improve the readability of code. – sprinter Sep 21 '15 at 20:56
3

It might be a Function, rather than a supplier, if an argument is required. But method references can refer to constructors in the same way they refer to methods; they just have a funny name (new).

From the Java Tutorial, there are four kinds of method references:

Kind                              Example
-------------------------------   ------------------------------------
Reference to a static method      ContainingClass::staticMethodName
Reference to an instance method   containingObject::instanceMethodName
of a particular object  
Reference to an instance method   ContainingType::methodName
of an arbitrary object of a 
particular type
Reference to a constructor        ClassName::new
erickson
  • 265,237
  • 58
  • 395
  • 493