Should variables always be declared with the Java interface?

advertisements

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<>();


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