10

I'm having a hard time sorting out why lambda expressions are assignable to some functional interfaces, but not others. An example, using some functional interfaces from the Metrics library:

Gauge<Double> foo = () -> { return null; };
RatioGauge bar = () -> { return null; };

The second statement has a compile error (in Eclipse):

The target type of this expression must be a functional interface

As far as I can tell, RatioGauge is a functional interface. Am I missing something?

0xced
  • 25,219
  • 10
  • 103
  • 255
Josh Stone
  • 4,328
  • 7
  • 29
  • 37

2 Answers2

24

An abstract class (even if it only has one abstract method) is not a functional interface. Only an interface can be one.

From JLS 9.8:

A functional interface is an interface that has just one abstract method (aside from the methods of Object)... (emphasis added)

The original idea was to let abstact classes be expressed as a lambda; they were called "SAM types," which stood for "single abstract method." That turned out to be a difficult problem to solve efficiently. This thread talks a bit about why; basically, the base class's constructor made it difficult.

yshavit
  • 42,327
  • 7
  • 87
  • 124
  • 1
    That's a real shame since lambda expressions were basically intended to replace anonymous classes and one can create an anonymous class from an interface or an abstract class. – Josh Stone Apr 01 '14 at 19:09
  • 4
    @JoshStone Well, lambda expressions were never intended to replace Anonymous classes completely, but just for certain scenarios. – Rohit Jain Apr 01 '14 at 19:14
  • @RohitJain Is there a workaround where a lambda can be used in conjunction with an abstract class (with a single abstract method) ? – Josh Stone Apr 01 '14 at 19:15
  • 3
    @JoshStone Not anything clever. You can make a concrete class that takes a functional interface, and uses that to implement the abstract method. ThreadLocal does that, for instance ([withInitial](http://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html#withInitial-java.util.function.Supplier-)) – yshavit Apr 01 '14 at 19:16
  • 1
    @yshavit Thanks a lot for that link to the discussion. Great info. – Josh Stone Apr 01 '14 at 19:17
  • @JoshStone No, I don't think they were intended to replace _all_ anonymous classes. There are plenty of anonymous classes that have multiple methods that have to be overridden (or at least I've used plenty), and lambda expressions can't work at all for those. Anyway, `RatioGauge` appears to have two methods, so a lambda doesn't at all seem appropriate. – ajb Apr 01 '14 at 19:18
  • @ajb RatioGauge only has one abstract method – Josh Stone Apr 01 '14 at 19:26
1

A function interface can have only ONE abstract method (besides the methods from Object class).

Source code for Gauge.java= http://grepcode.com/file/repo1.maven.org/maven2/com.codahale.metrics/metrics-core/3.0.0/com/codahale/metrics/Gauge.java#Gauge

Source code for RatioGauge.java= http://grepcode.com/file/repo1.maven.org/maven2/com.codahale.metrics/metrics-core/3.0.0/com/codahale/metrics/RatioGauge.java

Notice that Gauge.java only has one abstract method while RatioGauge has many methods.

Gene
  • 10,819
  • 1
  • 66
  • 58