Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 59 additions & 57 deletions 01-default-static-interface-methods.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
Default and Static Methods for Interfaces
--------

We all understand that we should code to interfaces. Interfaces give client a
contract which they should use without relying on the implementation details
(i.e. classes). Hence, promoting **[loose coupling](https://en.wikipedia.org/wiki/Loose_coupling)**.
We all understand that we should code to interfaces. Interfaces give the client
a contract which they should use without relying on implementation details (i.e.
classes). Hence, promoting **[loose coupling](https://en.wikipedia.org/wiki/Loose_coupling)**.
Designing clean interfaces is one of the most important aspect of API design.
One of the SOLID principle **[Interface segregation](https://en.wikipedia.org/wiki/Interface_segregation_principle)**
talks about designing smaller client-specific interfaces instead of designing
talks about designing smaller client-specific interfaces, instead of designing
one general purpose interface. Interface design is the key to clean and
effective API's for your libraries and applications.
effective APIs for your libraries and applications.

> Code for this section is inside [ch01 package](https://github.com/shekhargulati/java8-the-missing-tutorial/tree/master/code/src/main/java/com/shekhargulati/java8_tutorial/ch01).

If you have designed any API then with time you would have felt the need to add
new methods to the API. Once API is published it becomes impossible to add
new methods to the API. Once an API is published, it becomes difficult to add
methods to an interface without breaking existing implementations. To make this
point clear, let's suppose you are building a simple `Calculator` API that
supports `add`,`subtract`, `divide`, and `multiply` operations. We can write
`Calculator` interface as shown below. ***To keep things simple we will use
int.***
point clear, suppose you are building a simple `Calculator` API that supports
`add`,`subtract`, `divide`, and `multiply` operations. We can write a
`Calculator` interface, as shown below. ***To keep things simple we will use
`int`.***

```java
public interface Calculator {
Expand All @@ -33,8 +33,8 @@ public interface Calculator {
}
```

To back this `Calculator` interface you created a `BasicCalculator`
implementation as shown below.
To back this `Calculator` interface, you created a `BasicCalculator`
implementation, as shown below.

```java
public class BasicCalculator implements Calculator {
Expand Down Expand Up @@ -66,9 +66,9 @@ public class BasicCalculator implements Calculator {

## Static Factory Methods

Calculator API turned out to be very useful and easy to use. Users just have to
create an instance of `BasicCalculator` and then they can use the API. You start
seeing code like the one shown below.
Suppose the Calculator API turned out to be very useful and easy to use. Users
just have to create an instance of `BasicCalculator`, and then they can use the
API. You start seeing code like that shown below.

```java
Calculator calculator = new BasicCalculator();
Expand All @@ -78,10 +78,10 @@ BasicCalculator cal = new BasicCalculator();
int difference = cal.subtract(3, 2);
```

Oh no!! Users of the API are not coding to `Calculator` interface instead they
are coding to implementation. Your API didn't enforced users to code to
interfaces as the `BasicCalculator` class was public. If you make
`BasicCalculator` package protected then you would have to provide a static
Oh no! Users of the API are not coding to `Calculator` interface -- instead,
they are coding to its implementation. Your API didn't enforce users to code to
interfaces, as the `BasicCalculator` class was public. If you make
`BasicCalculator` package protected, then you would have to provide a static
factory class that will take care of providing the `Calculator` implementation.
Let's improve the code to handle this.

Expand All @@ -94,7 +94,7 @@ class BasicCalculator implements Calculator {
}
```

Next, we will write a factory class that will give us the `Calculator` instance
Next, we will write a factory class that will give us the `Calculator` instance,
as shown below.

```java
Expand All @@ -106,23 +106,23 @@ public abstract class CalculatorFactory {
}
```

Now, users will be forced to code to `Calculator` interface and they will not
have access to implementation details.
Now, users will be forced to code to the `Calculator` interface, and they will
not have access to implementation details.

Although we have achieved our goal but we have increased the surface area of our
API by adding a new class `CalculatorFactory`. Now users of the API have to
Although we have achieved our goal, we have increased the surface area of our
API by adding the new class `CalculatorFactory`. Now users of the API have to
learn about one more class before they can use the API effectively. This was the
only solution available before Java 8.

**Java 8 allows you to declare static methods inside an interface**. This will
allow API designers to define static utility methods like `getInstance` in the
interface itself. Hence keeping API short and lean. The static methods inside an
interface could be used to replace static helper classes(`CalculatorFactory`)
that we normally create to define helper methods associated with a type. For
example, `Collections` class is a helper class that defines various helper
methods to work with Collection and associated interfaces. The methods defined
in `Collections` class could easily be added to `Collection` or any of its child
interface.
**Java 8 allows you to declare static methods inside an interface**. This allows
API designers to define static utility methods like `getInstance` in the
interface itself, hence keeping the API short and lean. The static methods
inside an interface could be used to replace static helper classes
(`CalculatorFactory`) that we normally create to define helper methods
associated with a type. For example, the `Collections` class is a helper class
that defines various helper methods to work with Collection and its associated
interfaces. The methods defined in the `Collections` class could easily be added
to `Collection` or any of its child interfaces.

The above code can be improved in Java 8 by adding a static `getInstance` method
in the `Calculator` interface itself.
Expand All @@ -148,10 +148,10 @@ public interface Calculator {
## Evolving API with time

Some of the consumers decided to either extend the `Calculator` API by adding
methods like `remainder` or write their own implementation of `Calculator`
methods like `remainder`, or write their own implementation of the `Calculator`
interface. After talking to your users you came to know that most of them would
like to have a `remainder` method added to `Calculator` interface. It looked a
very simple API change so you added one more method to the API.
like to have a `remainder` method added to the `Calculator` interface. It looked
a very simple API change, so you added one more method to the API.

```java
public interface Calculator {
Expand All @@ -174,19 +174,20 @@ public interface Calculator {

Adding a method to an interface broke the source compatibility of the API. This
means users who were implementing `Calculator` interface would have to add
implementation for `remainder` method otherwise their code will not compile.
This is a big problem for API designers as it makes API difficult to evolve.
Prior to Java 8, it was not possible to have method implementations inside
interfaces. This often becomes a problem when it was required to extend an API
i.e. adding one or more methods to the interface definition.
implementation for the `remainder` method, otherwise their code would not
compile. This is a big problem for API designers, as it makes APIs difficult to
evolve. Prior to Java 8, it was not possible to have method implementations
inside interfaces. This often became a problem when it was required to extend an
API, i.e. adding one or more methods to the interface definition.

To allow API's to evolve with time, Java 8 allows users to provide default
implementations to methods defined in the interface. These are called
**default** or **defender** methods. The class implementing the interface is not
required to provide implementation of these methods. If implementing class
provides the implementation then implementing class method implementation will
be used else default implementation will be used. `List` interface has few
default methods defined like `replaceAll`, `sort`, and `splitIterator`.
**default**, or **defender** methods. The class implementing the interface is not
required to provide an implementation of these methods. If an implementing class
provides the implementation, then the implementing class method implementation
will be used -- otherwise the default implementation will be used. The `List`
interface has a few default methods defined, like `replaceAll`, `sort`, and
`splitIterator`.

```java
default void replaceAll(UnaryOperator<E> operator) {
Expand All @@ -198,9 +199,9 @@ default void replaceAll(UnaryOperator<E> operator) {
}
```

We can solve our API problem by defining a default method as shown below.
We can solve our API problem by defining a default method, as shown below.
Default methods are usually defined using already existing methods --
`remainder` is defined using `subtract`, `multiply`, and `divide` methods.
`remainder` is defined using the `subtract`, `multiply`, and `divide` methods.

```java
default int remainder(int number, int divisor) {
Expand All @@ -210,13 +211,13 @@ default int remainder(int number, int divisor) {

## Multiple inheritance

A class can extend a single class but can implement multiple interfaces. Now
that it is feasible to have method implementation in interfaces Java has
multiple inheritance of behavior. Java already had multiple inheritance at type
level but now it also has multiple inheritance at behavior level. There are
three resolution rules that help decide which method will be picked:
A class can extend a single class, but can implement multiple interfaces. Now
that it is feasible to have method implementation in interfaces, Java has
multiple inheritance of behavior. Java already had multiple inheritance at the
type level, but now it also has multiple inheritance at the behavior level.
There are three resolution rules that help decide which method will be picked:

**Rule 1: Methods declared in classes win over method defined in interfaces.**
**Rule 1: Methods declared in classes win over methods defined in interfaces.**

```java
interface A {
Expand All @@ -237,8 +238,8 @@ class App implements A{
}
```

This will print `inside App` as methods declared in class have precedence over
methods declared in interfaces.
This will print `inside App`, as methods declared in the implementing class have
precedence over methods declared in interfaces.

**Rule 2: Otherwise, the most specific interface is selected**

Expand All @@ -264,7 +265,8 @@ class App implements C, B, A {

This will print `inside C`.

**Rule 3: Otherwise, class has to call the desired implementation explicitly**
**Rule 3: Otherwise, the class has to call the desired implementation
unambiguously**

```java
interface A {
Expand Down