Thursday 29 June 2017

Programming to Interfaces


Most of the time we create LinkedList or ArrayList like below,

LinkedList<String> list = new LinkedList<>();
ArrayList<String> list = new ArrayList<>();

This is fine when we are at the learning phase. But in real time it's better to follow best practices of Java coding which enable robustness and efficiency of the code. If we have to follow best practices then the above line will change to, 


List<String> list = new LinkedList<>();
List<String> list = new ArrayList<>();

Let's see why:

According to LinkedList and ArrayList implementation, both inherits the AbstractList class and implements List. In Java there is a saying which highlights one of the best practices.

"programming to interface, not implementation"

Means the second has the advantage that the implementation of the List can change (to a LinkedList for example), without affecting the rest of the code. This is difficult to do with an ArrayList, not only because you will need to change ArrayList to LinkedList everywhere, but also because you may have used ArrayList specific methods.

Let's try to understand above situation with an example, in this example we program to implementation means we create LinkedList variable with LinkedList class itself but not to it's Interface called List.



import java.util.LinkedList;

public class LinkedListDemo {

  public static void printLinkedList(final LinkedList<String> linkedList) {
    for (final String item : linkedList) {
      System.out.println(item);
    }
  }

  public static void main(final String[] args) {
    final LinkedList<String> list = new LinkedList<>();
    list.add("Audi");
    list.add("BMW");
    list.add("Benz");

    printLinkedList(list);
  }
}

Output:
Audi
BMW
Benz

All of sudden I want to change from LinkedList to ArrayList due to some design change in the application. Let's see, in how many places we have to make the code changes.


import java.util.ArrayList;

public class ArrayListDemo {

  //Change here
  public static void printArrayList(final ArrayList<String> arrayList) {
    for (final String item : arrayList) {
      System.out.println(item);
    }
  }

  public static void main(final String[] args) {
    //change here
    final ArrayList<String> list = new ArrayList<>();
    list.add("Audi");
    list.add("BMW");
    list.add("Benz");

    printArrayList(list);
  }
}

Output:
Audi
BMW
Benz

In a small example we changed the code in couple of places. Assume in a large applications where thousand to million lines of code exists, it's very hard to change.

Let's consider the second way where program to an interface means creating your variable with List interface. Let's first create an ArrayList which is assigned to a List interface.



import java.util.ArrayList;
import java.util.List;

public class ArrayListDemo {

  public static void printList(final List<String> list) {
    for (final String item : list) {
      System.out.println(item);
    }
  }

  public static void main(final String[] args) {
    final List<String> list = new ArrayList<>();
    list.add("Audi");
    list.add("BMW");
    list.add("Benz");

    printList(list);
  }
}

Output:
Audi
BMW
Benz

Now let's make the changes in the code to use LinkeLlist,


import java.util.LinkedList;
import java.util.List;

public class LinkedListDemo {

  //no need to Change here. Remains same as above
  public static void printList(final List<String> list) {
    for (final String item : list) {
      System.out.println(item);
    }
  }

  public static void main(final String[] args) {
    //change here. This is only place you change 
    final List<String> list = new LinkedList<>();
    list.add("Audi");
    list.add("BMW");
    list.add("Benz");

    printList(list);
  }
}

Output:
Audi
BMW
Benz

In above example when you decided to use LinkedList instead ArrayList, you are changing the code at one place where you create a list. This gives you a flexibility to change to any implementation class i.e ArrayList, LinkedList or any class that implements the List interface safely without affecting your code. So use Interfaces instead direct implementation class.

Not only in case of List, it also applicable in terms of any interface which has many implementation classes. For example,

  • Set is an Interface and it has HashSet, TreeSet and LinkedHashSet classes which implement Set.
  • Map is an Interface and it has HashMap, TreeMap and LinkedHashMap classes which implement Set. or
  • It can be customer created Interface and it's implementations.


No comments:

Post a Comment