Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should variables always be declared with interface in Java?

One often sees the advice that variables should be declared with some interface, not the implementing class. For example:

List<Integer> list = new ArrayList<>();

However, say I am using this list for an algorithm that really depended on the O(1) random access of an ArrayList (e.g. Fisher-Yates shuffling). In that case, the key abstraction that ArrayList represents for me is its array-like nature, not just its List nature. In other words, if someone came along and changed list to a LinkedList, this would be problematic, even though the code would compile. In such a case, is it considered ok to have the declaration use the implementation type?, e.g.:

ArrayList<Integer> list = new ArrayList<>(); 
like image 264
PeteyPabPro Avatar asked Nov 30 '14 16:11

PeteyPabPro


People also ask

Can variables be declared in an interface in Java?

Like a class, an interface can have methods and variables, but the methods declared in an interface are by default abstract (only method signature, no body).

What will happen if we not initialize variables in an interface?

If you declare a variable as final, it is mandatory to initialize it before the end of the constructor. If you don't you will get a compilation error.

Which variable declaration is proper for interface?

An interface is declared by using the interface keyword. It provides total abstraction; means all the methods in an interface are declared with the empty body, and all the fields are public, static and final by default.

Should you always use an interface Java?

No, every class should not have an interface. It's overkill squared. You use an interface when you need to abstract what's done from how it's done, and you're certain that the implementation can change.


2 Answers

To emphasize what Oliver Charlesworth said in the comment: The most crucial difference whether this information is public or not.

From the way how the question is written, it seems like you're talking about a field (and not a method parameter or return value). And a private field is, per definition, an implementation detail, and you may make it arbitrarily specific. So it would be feasible to declare it as an ArrayList - although, strictly speaking, this is not relevant. To phrase it that way: You said

if someone ... changed list to a LinkedList, this would be problematic,...

The one who can change the declaration from

private List<T> list = new ArrayList<T>();

to

private List<T> list = new LinkedList<T>();

can also change the declaration from

private ArrayList<T> list = new ArrayList<T>();

to

private LinkedList<T> list = new LinkedList<T>();

The only practical way to prevent this would be to add this (important) implementation detail as a comment, e.g.

/**
 * The list that stores ... whatever. 
 *
 * This list should have a complexity of O(1) for random access,
 * because ...
 */
private final List<T> list = new ArrayList<T>();

(This could also be enforced by internally passing the list to a method that expects it to be a RandomAccess. This was proposed by AlexR, but referring to public methods. For private methods, even this won't prevent someone from changing the method signature, if the intention and the reasons for requiring RandomAccess are not documented).

like image 107
Marco13 Avatar answered Oct 04 '22 00:10

Marco13


I think that using interfaces is still very important. You case is very special but there is a way to solve it without usage of concrete classes. There is interface named RandomAccess. It is tag interface that does not declare methods but it should be used by implementors or List that do provide randome access to elements.

So, you can define your method that requires random access list as following:

public <E, L extends List<E> & RandomAcess>void algorithm(L list);

You will not be able to pass linked list to this method, but ArrayList will work. As you an expect now you can change implemtation of list without changing your algorithm. For example you can use thread safe CopyOnWriteArrayList that will allow yo to make you processing multithreaded without explicit syncrhonized statements.

like image 25
AlexR Avatar answered Oct 03 '22 23:10

AlexR