3 reasons to start using Java interfaces
Tags: java, webdev, programming, tutorial
Published: 2021-03-19 06:17:06



# what is an interface? 🚪
Oracle says: *"an interface is a group of related methods with empty bodies"*

I think of interfaces as a contract that a class promises the compiler to fulfill. If the class doesn't do what's promised the compiler will complain and give an error.

# why use one?  
**Why bind myself to this contract** and allow the compiler to yell at me about an unfulfilled promise?   
**Why don't I just write the methods** inside the class and be done with it?

After spending some time in the industry I started to form an understanding of why we use them. I will list the most important **three** reasons from my point of view.


# 1 - Document APIs 📜

Let's say your team is writing a new service to be added to the poll of services your company offers, and other teams will write some other services that are going to use your service.

How will they know what method to call? what parameters to pass? what return type to expect? 

Well, you guessed it, it's **interfaces**, the contract that ensures that those methods will always do as they describe in the interface.

Here is an interface that documents how to communicate with a registration service
```java
public interface IRegistrationService {
    void registerNewUser(String userName);
    boolean userIsRegistered(String userName);
    void cancelRegistration(int registrationId);
    void cancelRegistration(String userName);
}
```
You would write your own implementation of this interface, and other developers will take a look at the interface and understand what to do.

```java
public class RegistrationService implements IRegistrationService {
    public void registerNewUser(String userName) {
        // production code
    }
    public boolean userIsRegistered(String userName) {
        // production code
        return false; // the result of prod code
    }
    public void cancelRegistration(int registrationId) {
        // production code
    }
    public void cancelRegistration(String userName) {
        // production code
    }
}
```

# 2 - Write specifications 🖋

Imagine we want to write a specification of **what something should do, but not write how it should be done**, and leave that detail to whoever wishes to make it happen.
  
Perhaps the most famous example of this is the ***JPA (Java Persistence API)***  
**JPA** is a set of interfaces that defines how database persistence should look in Java applications. There are a couple of implementations of these interfaces  

 - Hibernate
 - Toplink
 - EclipseLink 
 - Apache OpenJPA 
 - and many more

Let's provide an example on *"How to use a car"* specification
```java
public interface CarDrivingSpecification {  
	    void startEngine();  
	    void pressGas();  
	    int getGasLeftInTank();  
	    // can the car go for the kilometers provided, taking into consideration the gas left in the tank   
	    boolean canGoForGivenKms(float kms);
    }
 ```
  Here we only specify what will the class that implements this interface do, and not the actual implementation of how it does it.
  
  

# 3- Polymorphism 💡

The third and most important use-case of interfaces is the fact that they allow us to leverage the powerful concept of **Polymorphism**.  

 - Inheritance also allows Polymorphism. However, a class can only extend one superclass, while a class can implement as many interfaces as needed. That's why it's far more flexible.

This can make our code much more elegant and clean. But first, **what was Polymorphism**?  
It allows us to say a thing like: "A student object can be treated as a Human Object" or "A Car object can be treated as a Vehicle object".

But, how can Polymorphism help us write clean code? Let's write some code that **DOESN'T** use Polymorphism.

Let's start by declaring the entity classes 
***Bicycle class*** 🚲
```java
import lombok.AllArgsConstructor;  
@AllArgsConstructor  
public class Bicycle {  
     private final int Id;  
      
     public void goForward(){  
         System.out.println("Bike forward");  
      }  
}
``` 
   
   ***Car class*** 🚘
```java
import lombok.AllArgsConstructor;  
@AllArgsConstructor  
public class Car {  
     private final int Id;  
      
     public void goForward(){  
          System.out.println("Car forward");  
      }  
     public void checkEngine(){  
         System.out.println("Checking Car engine");  
       }  
}
```    
***Truck class*** 🚚
```java
import lombok.AllArgsConstructor;  
@AllArgsConstructor  
public class Truck {  
     private final int Id;  
      
     public void goForward(){  
          System.out.println("Truck forward");  
     }  
     public void checkEngine(){  
         System.out.println("Checking Truck engine");  
       }  
 }
```
Now let's write the service that will utilize those classes and run the methods of every object
```java
   public class TrafficService {  
    private List<Bicycle> getBicyclesFromMap(){  
        return Arrays.asList(new Bicycle(1), new Bicycle(2));  
    }  
    private List<Car> getCarsFromMap(){  
        return Arrays.asList(new Car(1), new Car(2));  
    }  
    private List<Truck> getTrucksFromMap(){  
        return Arrays.asList(new Truck(1), new Truck(2));  
    }  
    
    public void goForward(List<Bicycle> bicycles, List<Car> cars, List<Truck> trucks){  
        bicycles.forEach(Bicycle::goForward);  
        cars.forEach(Car::goForward);  
        trucks.forEach(Truck::goForward);  
    }  
    
    public void checkEngine(List<Car> cars, List<Truck> trucks){  
        cars.forEach(Car::checkEngine);  
        trucks.forEach(Truck::checkEngine);  
    }  
    
    public void makeAllTransportGoForward(){  
        goForward(getBicyclesFromMap(), getCarsFromMap(), getTrucksFromMap());  
    }  
    public void makeAllEnginesStart(){  
        checkEngine(getCarsFromMap(), getTrucksFromMap());  
    }  
}
```

First of all, we had to specify a method for each class of objects to get its instances from the map.  Also, note that in the ***goForward*** method we had to pass as parameters the three types of objects (Bicycle, Car, Truck), and we had to call the ***goForward*** method for each class of objects.  
Now, for three entities that isn't a big problem. However, when you have 10 or even a 100 ones, that quickly becomes a problem.

## Let's apply interfaces and Polymorphism and see the results

We start by defining the interfaces,
The **Transport** interface
```java
public interface Transport {  
      void goForward();  
}
```
The **Vehicle** interface which extends the Transport interface
```java
public interface Vehicle extends Transport{
     void checkEngine();
}
```
The entities classes note that we **make the classes implement the interfaces**.
🚲 🚘 🚚
```java
import lombok.AllArgsConstructor;  
@AllArgsConstructor
public class Bicycle implements Transport{
    private final int id;
    public void goForward() {
        System.out.println("Bike forward");
    }
}
// other class
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class Car implements Vehicle{
    private final int id;
    public void checkEngine() {
        System.out.println("Checking Car engine");
    }
    public void goForward() {
        System.out.println("Car forward");
    }
}
// other class
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class Truck implements Vehicle{
    private final int id;
    public void checkEngine() {
        System.out.println("Checking Truck engine");
    }
    public void goForward() {
        System.out.println("Truck forward");
    }
}
```
The service that utilizes the classes **Polymorphismly**
```java
public class TrafficService {
    List<Transport> getTransportFromMap(){
        return Arrays.asList(
                new Bicycle(1), new Bicycle(2),
                new Car(1), new Car(2),
                new Truck(1), new Truck(2));
    }

    List<Vehicle> getVehicleFromMap(){
        return Arrays.asList(
                new Car(1), new Car(2),
                new Truck(1), new Truck(2));
    }

    public void goForward(List<Transport> transports){
        transports.forEach(Transport::goForward);
    }

    public void checkEngine(List<Vehicle> vehicles){
        vehicles.forEach(Vehicle::checkEngine);
    }

    public void makeAllTransportGoForward(){
        goForward(getTransportFromMap());
    }
    public void makeAllEnginesStart(){
        checkEngine(getVehicleFromMap());
    }
}
```
## What did the interface and Polymorphism help us do? 💪

 - Gather those objects that are of the compatible interface (Vehicle,
   Transport) in a single List data structure.
   
  - The goForward method handles all objects that implement the interface Transport in a single command and triggers the specific implementation of each one.
  - The same goes for the checkEngine method, which handles all objects that implements the Vehicle interface.
  - Our code got much cleaner this way!!!

# Conclusion 👇🏻

**Interfaces have three main usages**  

 1. building and documenting APIs
 2. writing specification for other people to implement  
 3. making use of Polymorphism to write readable clean code.


# Source code 👨‍💻
[GitHub] (https://github.com/Jarjanazy/java-interface-tutorial)