DEV Community

Cover image for Annotations, Functional Interfaces, and Lambdas in Java
Adesola
Adesola

Posted on

Annotations, Functional Interfaces, and Lambdas in Java

These three concepts build on each other more than they seem to at first glance: annotations give the compiler metadata to act on, one specific annotation (@FunctionalInterface) marks a particular kind of interface, and that kind of interface is exactly what makes lambda expressions possible. This post walks through all three, in that order.

Annotations

Metadata(s) for the compiler.

An annotation in Java is metadata attached to code — a class, method, field, or interface — that doesn't change what the code does, but gives instructions to the compiler, a tool, or the JVM about how to treat it. You've probably already used a few without thinking about it: @override, @deprecated, @SuppressWarnings.

@Override
public String toString() {
    return "example";
}
Enter fullscreen mode Exit fullscreen mode

@override doesn't add behavior — it just tells the compiler "check that this method actually overrides something in the superclass, and fail if it doesn't." That's the general pattern: annotations are instructions about the code, not part of its logic.

One of the most useful annotations for modern Java is @FunctionalInterface, which brings us to the next concept.

Functional interfaces

A functional interface is an interface with exactly one abstract method. This single-method shape is also called a SAM interface — Single Abstract Method.

interface A {
    void show();
}
Enter fullscreen mode Exit fullscreen mode

To make Java enforce that an interface stays this way, you annotate it:

@FunctionalInterface
interface A {
    void show();
}
Enter fullscreen mode Exit fullscreen mode

Now, if a second abstract method sneaks in, it's going to give a compile-time error instead of a bug which you will see later:

@FunctionalInterface
interface A {
    void show();
    void play(); // compile error: not a functional interface anymore
}
Enter fullscreen mode Exit fullscreen mode

Note that this restriction only applies to abstract methods. A functional interface can still have any number of default or static methods, since those already have a body and don't count toward the "single abstract method" rule:

@FunctionalInterface
interface A {
    void show();

    default void log() {
        System.out.println("Logging from A");
    }
}
Enter fullscreen mode Exit fullscreen mode

Implementing a functional interface with an anonymous class

Before lambdas, this is what implementing a small interface inline looked like:

public class StoreApplication {
    public static void main(String[] args) {
        A obj = new A() {
            @Override
            public void show() {
                System.out.println("implementing interface directly....");
            }
        };

        obj.show();
    }
}
Enter fullscreen mode Exit fullscreen mode

It works, but it's verbose for something this simple — which is exactly the problem lambda expressions were introduced to solve.

Lambda expressions

Functional interfaces are what make lambda expressions possible in Java 8+: since a functional interface guarantees there's exactly one method to implement, Java can let you skip the class name, the method name, and the boilerplate, and just write the method body.

Implementing a functional interface with a lambda

@FunctionalInterface
interface A {
    void show();
}
Enter fullscreen mode Exit fullscreen mode
public class StoreApplication {
    public static void main(String[] args) {
        A obj = () -> System.out.println("implementing interface using lambda....");
        obj.show();
    }
}
Enter fullscreen mode Exit fullscreen mode

Passing an argument via lambda

@FunctionalInterface
interface A {
    void show(int i);
}

public class StoreApplication {
    public static void main(String[] args) {
        A obj = (i) -> System.out.println("implementing interface using lambda...." + i);
        obj.show(45);
    }
}
Enter fullscreen mode Exit fullscreen mode

A functional interface that returns a value


@FunctionalInterface
interface A {
    int add(int a, int b);
}

public class StoreApplication {
    public static void main(String[] args) {
        A calculator = (i, j) -> {
            System.out.println("Performing addition of numbers " + i + " and " + j);
            return i + j;
        };

        System.out.println("The sum is equal to " + calculator.add(45, 30));
    }
}
Enter fullscreen mode Exit fullscreen mode

Same contract, same enforcement from @FunctionalInterface — just far less ceremony to implement it.

Types of interfaces, at a glance

Now that we've covered the functional/SAM interface in depth, it's worth placing it alongside the other interface types you'll run into:

Normal interface — two or more methods, no restrictions on count.

Functional / SAM interface — exactly one abstract method; can be
implemented with a lambda.

Marker interface — has no methods at all. It exists purely to "tag" a class with metadata that other code can check via instanceof, so the JVM or a framework can treat tagged classes differently. Serializable and Cloneable are the classic examples — implementing Serializable doesn't add any methods, but it tells the JVM "this object is allowed to be serialized."

That last one brings things full circle: marker interfaces were Java's original way of attaching metadata to a class before annotations existed. Today, annotations have largely taken over that role — which is exactly where this post started.

Wrapping up

Annotations give the compiler instructions, @FunctionalInterface uses that mechanism to enforce a single-method contract, and lambdas exist to make implementing that contract painless. Once you see the chain connecting them, a lot of modern Java code (streams, Comparator, Runnable, custom callbacks) starts making a lot more sense.

Got a favorite use of lambdas or functional interfaces in your own code? Drop it in the comments.

Top comments (2)

Collapse
 
deyems_adesola profile image
Adesola •

Dear dev supports, that link is fraudulent.