Skip to content

reflow paragraphs to use 80-character gutter #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 25, 2016
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
95 changes: 77 additions & 18 deletions 01-default-static-interface-methods.md
Original file line number Diff line number Diff line change
@@ -1,11 +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)**. 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 one general purpose interface. Interface design is the key to clean and effective API's for your libraries and applications.
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)**.
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
one general purpose interface. Interface design is the key to clean and
effective API's 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 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.***
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
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.***

```java
public interface Calculator {
Expand All @@ -20,7 +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 @@ -52,7 +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.
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.

```java
Calculator calculator = new BasicCalculator();
Expand All @@ -62,17 +78,24 @@ 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 factory class that will take care of providing the `Calculator` implementation. Let's improve the code to handle this.
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
factory class that will take care of providing the `Calculator` implementation.
Let's improve the code to handle this.

First, we will make `BasicCalculator` package protected so that users can't access the class directly.
First, we will make `BasicCalculator` package protected so that users can't
access the class directly.

```java
class BasicCalculator implements Calculator {
// rest remains same
}
```

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

```java
public abstract class CalculatorFactory {
Expand All @@ -83,13 +106,26 @@ 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 `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 learn about one more class before they can use the API effectively. This was the only solution available before Java 8.
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
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 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.

The above code can be improved in Java 8 by adding a static `getInstance` method in the `Calculator` interface itself.
The above code can be improved in Java 8 by adding a static `getInstance` method
in the `Calculator` interface itself.

```java
public interface Calculator {
Expand All @@ -111,7 +147,11 @@ 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` 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.
Some of the consumers decided to either extend the `Calculator` API by adding
methods like `remainder` or write their own implementation of `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.

```java
public interface Calculator {
Expand All @@ -132,9 +172,21 @@ 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.

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`.
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.

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`.

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

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.
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.

```java
default int remainder(int number, int divisor) {
Expand All @@ -156,7 +210,11 @@ 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 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:

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

Expand All @@ -179,7 +237,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 class have precedence over
methods declared in interfaces.

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

Expand Down