问题
Java 8 gave us many fun ways to use functional interfaces and with them a new annotation: @FunctionalInterface. Its job is to tell the compiler to yell at us if we fail to stick to the rules of a functional interface (only one abstract method that needs overriding please).
There are 43 interfaces in the java.util.function package with this annotation. A search of jdk.1.8.0/src for @FunctionalInterface
only turns up 57 hits. Why are the other interfaces (such as AutoCloseable) that could have added @FunctionalInterface
still missing it?
There is a bit of a vague hint in the annotations documentation:
"An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface"
Is there any good reason NOT to intend that an interface I've designed (that may simply happen to be a functional interface) not be used as one? Is leaving it off an indication of anything besides not realizing it could have been added?
Isn't adding abstract methods to any published interface going to screw anyone implementing it, functional or not? I feel cynical assuming they just didn't bother to hunt them all down but what other explanation is there?
Update: After looking over "Should 'Comparable' be a 'Functional interface'?" I find I still have nagging questions. When a Single Method Interface and a Functional Interface are structurally identical what's left to be different? Is the difference simply the names? Comparable and Comparator are close enough to the same semantically. Turns out they are different structurally though so still not the best example...
Is there a case when an SMI is structurally fine to use as a Functional Interface but still discouraged over the semantic meaning of the name of the interface and the method? Or perhaps the contract implied by the Javadocs?
回答1:
Well, an annotation documenting an intention would be useless if you assume that there is always that intention given.
You named the example AutoCloseable
which is obviously not intended to be implemented as a function as there’s Runnable
which is much more convenient for a function with a ()->void
signature. It’s intended that a class implementing AutoCloseable
manages an external resource which anonymous classes implemented via lambda expression don’t do.
A clearer example is Comparable
, an interface
not only not intended to be implemented as a lambda expression, it’s impossible to implement it correctly using a lambda expression.
Possible reasons for not marking an interface
with @FunctionalInterface
by example:
- The
interface
has programming language semantics, e.g.AutoClosable
orIterable
(that’s unlikely to happen for your own interfaces) - It’s not expected that the
interface
has arbitrary implementations and/or is more an identifier than the actual implementation, e.g.java.net.ProtocolFamily
, orjava.lang.reflect.GenericArrayType
(Note that the latter would also inherit adefault
implementation forgetTypeName()
being useless for lambda implementations as relying ontoString()
) The instances of this
interface
should have an identity, e.g.java.net.ProtocolFamily
,java.nio.file.WatchEvent.Modifier
, etc. Note that these are typically implemented by anenum
Another example is
java.time.chrono.Era
which happens to have only a singleabstract
method but its specification says “Instances ofEra
may be compared using the==
operator.”- The
interface
is intended to alter the behavior of an operation for which an implementation of theinterface
without inheriting/implementing anything else makes no sense, e.g.java.rmi.server.Unreferenced
- It’s an abstraction of common operations of classes which should have more than just these operations, e.g.
java.io.Closeable
,java.io.Flushable
,java.lang.Readable
- The expected inheritance is part of the contract and forbids lambda expression implementations, e.g. in
java.awt
:ActiveEvent
should be implemented by anAWTEvent
,PrinterGraphics
by aGraphics
, the same applies tojava.awt.print.PrinterGraphics
(hey, twointerface
s for exactly the same thing…), wherasjavax.print.FlavorException
should be implemented by ajavax.print.PrintException
subclass - I don’t know whether the various event listener interfaces aren’t marked with
@FunctionalInterface
for symmetry with other multi-method event listener that can’t be functional interfaces, but actually event listeners are good candidates for lambda expressions. If you want remove a listener at a later time, you have to store the instance but that’s not different to, e.g. inner class listener implementations. The library maintainer has a large codebase with more than 200 candidate types and not the resources to discuss for every
interface
whether it should be annotated and hence focuses on the primary candidates for being used in a functional context. I’m sure, that, e.g.java.io.ObjectInputValidation
,java.lang.reflect.InvocationHandler
, jucRejectedExecutionHandler
&ThreadFactory
wouldn’t be bad as@FunctionalInterface
but I have no idea whether, e.g.java.security.spec.ECField
makes a good candidate. The more general the library is, the more likely users of the library will be able to answer that question for a particularinterface
they are interested in but it would be unfair to insist on the library maintainer to answer it for all interfaces.In this context it makes more sense to see the presence of a
@FunctionalInterface
as a message that aninterface
is definitely intended to be usable together with lambda expressions than to treat the absence of the annotation as an indicator for it’s being not intended to be used this way. This is exactly like the compiler handles it, you can implement every single abstract methodinterface
using a lambda expression, but when the annotation is present it will ensure that you can use thisinterface
in this way.
回答2:
Planned expansion. Just because an interface matches the requirements of an SMI now doesn't mean that expansion isn't needed later.
回答3:
In java 8, functional interface is an interface having exactly one abstract method called functional method to which the lambda expression’s parameter and return types are matched.
The java.util.function
contains general purpose functional interfaces used by JDK and also available for end users. While they are not the complete set of funtional interfaces to which lambda expressions might be applicable, but they provide enough to cover common requirements. You are free to create your own functional interfaces whenever existing set are not enough.
There are many such interfaces available which deserves to be designated as functional interface but java.util.function
package already provides functional interfaces for our almost all purposes.
For example look into following code.
public interface Comparable<T> {
public int compareTo(T o);
}
@FunctionalInterface
public interface ToIntFunction<T> {
int applyAsInt(T value);
}
public static void main(String[] args){
ToIntFunction<String> f = str -> Integer.parseInt(str);
Comparable<String> c = str -> Integer.parseInt(str);
}
Comparable
can also take an object and derive some int type value but there is a more general dedicated interface ToIntFunction
is provided to perform this task. There is no such hard rule that all the deserving interfaces should be annotated with @FunctionalInterface
but to gain the advantage of lambda feature, the interface should fulfill all criterias defined by FunctionalInterface.
来源:https://stackoverflow.com/questions/28166187/why-isnt-functionalinterface-used-on-all-the-interfaces-in-the-jdk-that-qualif