1

Recently I started in a new project where all the interfaces with a single abstract method are anotated with @FunctionalInterface. Constantly I see people removing the annotation after adding another abstract method in the interface. When did I ask why? They told me that someone that isn't in the company anymore told them to do it like that. Now I'm not sure if it's a good idea to annotate interfaces that obviously will not be used with lambdas.

Now I see that a piece of useful information is that people are using the anotation even in services in services. I just seemed a code like:

@FunctionalInterface
public interface SomeService {
    void doSomething();
}
  • 2
    https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html – matt Jan 21 '20 at 18:23
  • You have to remove the annotation if you add another method because the compile should complain. – matt Jan 21 '20 at 18:26
  • 2
    @matt More the point is that you should not be adding abstract methods to the interface if somebody else has marked it with that annotation. One of the main uses of that annotation (at least the way I use it) is for co-worker proofing. It says "I'm using this interface in a lambda somewhere, so don't add any methods." If somebody has been adding the annotation on interfaces where that's not the case, then that's one thing, but you'd better be really sure you're not breaking anything that depends on that interface. – mypetlion Jan 21 '20 at 18:28
  • 4
    The documentation was really helpful, now I feel like an idiot for asking it here without checking the docs first. I don't think the one who put the annotation knows how to use it, I think they see an interface with a single abstract method and automatically put the annotation. – Richard Marto Jan 21 '20 at 18:56

2 Answers2

4

I'm not sure if it's a good idea to annotate interfaces that obviously will not be used with lambdas

It's not. At best, it's a waste of time. At worst, it's actively misleading.

The documentation says

[Use to indicate that the type] is intended to be a functional interface

If you say it will "obviously not" be used in a lambda then using a annotation that marks that you do expect that usage is a clear contradiction.

Michael
  • 41,989
  • 11
  • 82
  • 128
1

Explanation

Every interface that only offers one (abstract) method, i.e. without implementation, is a so called functional interface.

Being it explicitly or implicitly.

The annotation @FunctionalInterface is, like @Override, optional, if you want to create a functional interface.

So if you declare an interface @FunctionalInterface, but it actually has more than just one such method, the compiler helps you and prevents compilation with an error. Telling you that you violated your own intention.

If you do not have the annotation, it will compile, but it is not a functional interface anymore. This could be a bug to you, because your intention was to create a functional interface. Note that if you are actually using the interface in an environment where a functional interface is actually required, like for a lambda, it would obviously not compile anymore as soon as another method is added to the interface.

Here are some examples:

// is a functional interface
interface Foo {
    void bar();
}

// is a functional interface
@FunctionalInterface
interface Foo {
    void bar();
}

// is not a functional interface
interface Foo {
    void bar();
    void baz();
}

// does not compile
@FunctionalInterface
interface Foo {
    void bar();
    void baz();
}

Use

It is to make your intention clear to the compiler, other team members and your future self. That way, the compiler can help you spot bugs in case you mess up.

Another scenario might be if you are working in a team and design an interface. If you do not clearly mark this interface as functional interface, either by the annotation or with a comment/documentation, another team member might not know your intention and add more methods to it.

This is especially important if you are a library designer, i.e. writing code that is to be used by other, external, people. If you mark your interface @FunctionalInterface, it is a promise to them that you intent to keep it like that. So they can safely use it for lambdas, for example. Without fearing that their code will break as soon as you ship an update to your library.

The opposite case is true as well. If they spot an interface of yours that only has one method, but is not explicitly annotated, they will understand that this is not meant to be used as functional interface, eventhough it currently is one. Thus, they will not use it for lambdas, although they could, since you might change it in a future update.


Details

You can read about the precise definitions in JLS§9.8. Functional Interfaces:

A functional interface is an interface that has just one abstract method (aside from the methods of Object), and thus represents a single function contract. This "single" method may take the form of multiple abstract methods with override-equivalent signatures inherited from superinterfaces; in this case, the inherited methods logically represent a single method.

And JLS§9.6.4.9. @FunctionalInterface:

The annotation type FunctionalInterface is used to indicate that an interface is meant to be a functional interface (§9.8). It facilitates early detection of inappropriate method declarations appearing in or inherited by an interface that is meant to be functional.

It is a compile-time error if an interface declaration is annotated with @FunctionalInterface but is not, in fact, a functional interface.

Because some interfaces are functional incidentally, it is not necessary or desirable that all declarations of functional interfaces be annotated with @FunctionalInterface.

The last paragraph here is especially important. I.e. you might have created a functional interface incidentally and plan to add more to it later. So people should not mistake this and use it with lambdas, otherwise their code will break later, when you add more methods.


Note

As mentioned before, the @Override tag works the same, but for overriding methods. So you can also override methods without it. But if you use it and maybe made a typo, i.e. you are not actually overriding something, the compiler will help you spot this issue immediately.

Community
  • 1
  • 1
Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • 2
    If the functional interface is being used as a lambda in your code, you'll get a compiler error anyway. The main advantage is for library code to document interfaces that are (and are likely to remain as) functional interfaces. In business code the annotation has little value. – Kayaman Jan 21 '20 at 18:40
  • @Kayaman You mentioned the value, and then followed up by saying that it has no value. The interface you're modifying may be used elsewhere, outside of your domain. The annotation shouldn't be used to "indicate" that the interface will remain functional, it should be used as a promise that it will remain functional. – mypetlion Jan 21 '20 at 18:46
  • So you think every interface with a single abstract method should be annotated? I mean, as @Michael pointed, the documentation says "Use to indicate that the type". – Richard Marto Jan 21 '20 at 19:13
  • 2
    No, please carefully read the full answer. Especially the last section in "details". It is a tool that should only be used if your intention is to create a functional interface. Not if you incidentally created one (but plan to change that later). – Zabuzard Jan 21 '20 at 19:15
  • 2
    @RichardMarto No, but you can use the annotation to indicate that no abstract method should be added. If somebody else has added the annotation, then you should not be adding abstract methods unless you have confidence that you're not going to break anything. Remember, the original question wasn't about whether OP should be adding the annotation, but about what to do when somebody else has applied it erroneously. You need to be very sure that it was actually erroneous before you try to correct the mistake. – mypetlion Jan 21 '20 at 19:17
  • 1
    I understand, thanks. – Richard Marto Jan 21 '20 at 19:21
  • 1
    “*(non-defaulted) method, i.e. without implementation*” is a long winded way to say *abstract* and it’s ambiguous, as static methods have an implementation but are not “defaulted”. So why not use the established simple term “abstract”? Besides that, adding more abstract methods to an interface will break all implementations, it doesn’t matter whether they have been implemented as lambda expression or ordinary class. – Holger Jan 22 '20 at 08:20