Functional Interfaces and Lambda Expressions
A default method is declared inside an interface with the modifier default and carries a working implementation.
Why Interfaces Used to Be Limited
Until Java 8, an interface could only declare methods without bodies. Any class that implemented the interface was required to supply a body for every one of them. An interface was therefore a promise of behavior, never a source of working code. This article looks at the feature that changed that rule: the default method.
A default method is a method declared inside an interface that comes with its own implementation. Because the interface now carries working code, a class that implements the interface can receive that code without writing it. The rest of this article explains how such methods are declared, inherited, overridden, and combined, and it begins with a prediction you can test for yourself.
A Prediction About readLine()
Consider an interface named Readable. It declares an abstract method readChar() and a default method readLine(). A class named FileSource implements Readable, provides a body for readChar(), and says nothing about readLine(). Before reading on, decide what happens when a caller invokes readLine() on a FileSource object.
What do you think happens?
What happens when you call readLine() on a new FileSource object?
Reveal answer
The default body in Readable runs, and it calls FileSource's readChar().
FileSource inherits readLine() from Readable without writing it. The inherited body calls readChar(), and because FileSource supplies that method, the call reaches FileSource's own code. Each call to readChar() returns the next character, so new FileSource().readLine() returns "[ab]".
The prediction works out this way because of the central idea of the topic. The interface carries working code, not just a promise of code. The class did not write readLine(), yet the method is still callable on its objects, and its body runs.
Recognizing the default Modifier
A default method is written in the body of an interface and follows a fixed pattern. The word default must appear in the declaration. That keyword is the element that separates a default method from an ordinary abstract method. Without it, a method inside an interface is abstract and has no body, so a method that has a body but lacks default is not a valid interface method.
- default: marks the method as a default method with a body
- public: allowed but optional, because everything in an interface is automatically public
- String: the return type, following the same rules as any other method
readLine(): the method name- { ... }: the block that holds the implementation
The access modifier public can be dropped in real code. The return type, the method name, and the parameter list follow the same conventions as any other method. What makes the method a default method is the default keyword together with the braces that enclose its body.
Functional Interfaces and Default Methods
A functional interface is an interface that specifies a single abstract method. It may also include default methods alongside that one abstract method.
The abstract method is still the only one a lambda or implementing class must supply, because the default methods already have bodies. A functional interface can therefore offer helper behavior built on top of its single required method without making the implementer write that helper. This is why default methods matter to the functional interface idea: they add capability without adding to the required work.
Inherited or Overridden: Which Body Runs?
A class that implements an interface with default methods has two possible relationships to each default method. It can leave the method alone, in which case it inherits the interface's version. Or it can write its own body, which overrides the interface's version. The inheritance works the same way a subclass receives an ordinary method from a parent class. When the class's own version exists, it takes priority.
Follow the flowchart with the FileSource class. FileSource does not write readLine(), so the decision branch labeled no is taken. The interface's body runs, and when it reaches readChar(), it uses the version FileSource supplied. Now change the scenario: if a class supplies its own readLine(), the decision branch labeled yes is taken, the interface's default body is skipped entirely, and readChar() is never called by that path.
new ReverseSource().readLine() returns "custom"; readChar() is not called by readLine()Calling Abstract Methods from a Default Body
A default method is allowed to call the abstract methods declared in its own interface. In the Readable example, readLine() calls readChar(), which has no body in the interface. That call is valid because every concrete class that implements Readable must supply readChar(), so the call always reaches real code at run time.
Read the sequence top to bottom. The inherited default body is the only code that calls readChar(), yet the code that answers that call belongs to FileSource. The interface can therefore describe a procedure in terms of an operation it does not implement, and each class supplies the operation in its own way.
What a Default Method Cannot Reach
A default method cannot refer to instance variables. Interfaces do not hold instance variables at all, so there is no per-object state a default method could read or change. A regular class method, by contrast, can see the fields of the object it belongs to. The comparison below shows the difference.
| Feature | Regular class method | Default method in an interface |
|---|---|---|
| Where it is declared | Inside a class | Inside an interface |
| Can read instance variables | Yes, the fields of its object | No, interfaces hold no instance variables |
| Can call abstract methods | Yes, when a superclass declares them | Yes, abstract methods of its own interface |
| What it depends on for state | Fields stored by the object | Only methods the implementing class is required to supply |
Default methods gain behavior but no stored state
Mixing Behavior from Several Interfaces
Other programming languages offer a feature called a mixin, which lets a class take in functionality from another source. Default methods give Java a similar capability. Because a class can implement several interfaces, it can mix in functionality from several different sources. The result is not multiple inheritance in the full sense, since interfaces still store no instance variables, but a class can combine behaviors that were defined separately.
LOG: start
savingThe Report class did not have to write either method body. Each interface supplies one behavior, and the class combines them through its implements clause. Writing its own body for log() or save() would override the corresponding default, following the same priority rule covered earlier. The source pack does not cover how Java resolves a conflict in which two interfaces supply default methods with the same signature, so that case should be studied separately.
Mistakes With Default Methods
Common mistake Writing a method body in an interface without the default keyword
What it looks likeinterface Readable { String readLine() { return "x"; } }Why it failsWithout default, a method inside an interface is abstract and has no body.
Do this insteadinterface Readable { default String readLine() { return "x"; } }Common mistake Expecting a default body to read a field of the implementing class
What it looks likedefault String readLine() { return text; } where text is a field of FileSource
Why it failsInterfaces hold no instance variables, so a default method has no per-object state to read.
Do this insteadCall a method that the implementing class supplies, such as readChar(), instead of reading a field.
Common mistake Assuming a class must write every default method it inherits
What it looks likeWriting a readLine() in FileSource just to make it workWhy it failsDefault methods already carry a body, so a class that leaves them alone inherits working behavior.
Do this insteadWrite an override only when the class needs different behavior.
Common mistake Assuming an overriding body is also called by the interface: the interface's default body is skipped when the class has its own version.
Practice: Predict Before You Run
Using the Readable interface and the ReverseSource class above, what does new ReverseSource().readLine() return, and is readChar() called during that call? Write your prediction first, then check it against the explanation in the section on inheritance and overriding.
Hints
- Ask first whether ReverseSource supplies its own
readLine(). - If it does, the interface's default body is not run.
- Remember that the return value comes from the body that runs.
Key Takeaways
- A default method is declared inside an interface with the modifier default and carries a working implementation; without default, an interface method has no body.
- A class that implements an interface inherits each default method unless it writes its own body, and the class's version takes priority when present.
- A default method can call abstract methods of its interface, because every concrete implementing class must supply them, but it cannot use instance variables because interfaces hold none.
- A class implementing several interfaces can mix in default behavior from each, combining separately defined behaviors without gaining stored state.
- A functional interface has one abstract method and may also include default methods, which add helper behavior without adding to the implementer's required work.