This is an article for new Java developers. New Java developers have a tendency to write methods that take ArrayList as a parameter, return it as a type, and use them on the left hand side of assignments. Doing this violates Java best practices and I’m going to teach you what you should do instead and why.
Your method signature should not have ArrayList as a parameter
Here’s an example of what you shouldn’t do:
1 2 3 4 5 |
public List<String> badCopyThenSort(ArrayList<String> input) { List<String> clone = new ArrayList<>(input); Collections.sort(clone); return clone; } |
The problem is that the input parameter is an ArrayList . There is no point in using an ArrayList here. You should use a List instead:
1 2 3 4 5 |
public List<String> goodCopyThenSort(List<String> input) { List<String> clone = new ArrayList<>(input); Collections.sort(clone); return clone; } |
This method is better because it is more flexible. The bad method says, “you must pass me in an ArrayList “. The good method says, “you can pass in anything that is a List type”. Let me elaborate with a specific example:
If you decided that you wanted to call the bad method on a LinkedList object, you would not be able to pass it in because a LinkedList is not an ArrayList . But, you could pass it into the good method. In fact, you can pass in an ArrayList and a LinkedList because they are both List s.
If you use the good method, you get the benefit of flexible code with no downside. So, you should get into the habit of doing this every time.
The only time you would want a method to take an ArrayList is if you are using a method that exists in ArrayList and doesn’t exist in the List type. As a specific example, if you had code that called input.trimToSize() , you would need to pass in an ArrayList : The List class does not have a trimToSize() method. So, this wouldn’t even compile:
1 2 3 |
public void badTrimToSize(List<String> input) { input.trimToSize(); //ERROR! This method doesn't exist on a java.util.List } |
Your method signature should not return ArrayList
Here’s an example of what you should not do:
1 2 3 4 5 |
public ArrayList<String> badCopyThenSort(List<String> input) { ArrayList<String> clone = new ArrayList<>(input); Collections.sort(clone); return clone; } |
Instead, you should do this:
1 2 3 4 5 |
public List<String> goodCopyThenSort(List<String> input) { List<String> clone = new ArrayList<>(input); Collections.sort(clone); return clone; } |
The reason you don’t want to do this is it makes the logic in your method less flexible. What if you realize later that you want this method to return a LinkedList instead of an ArrayList ? What you’ll have to do is change all the places that call this method from this:
1 |
ArrayList<String> list = badCopyThenSort(aList); //after the change, this code no longer compiles :( |
To this:
1 |
LinkedList<String> list = badCopyThenSort(aList); //I had to change a 100 places like this :( |
You could have prevented all this work if your method returned a List from the beginning. If it did that from the start, your code would call it like this:
1 |
List<String> list = goodCopyThenSort(aList); //If I return a different List type, nobody has to know! |
That brings us to the next topic…
Your variable assignments should not have ArrayList on the left hand side
Here’s an example of what you should not do:
1 |
ArrayList<String> list = returnAList(); |
Instead, you should do this:
1 |
List<String> list = returnAList(); |
One of the reasons you should do this is addressed at the end of the previous section. If returnAList() returned an ArrayList (a bad practice), you wouldn’t be effected if someone fixes it later and decides to return a List like they should have from the beginning.
It also makes your code subtly easier to read. If you’re using an ArrayList instead of a List , I’m going to think you have a very specific reason for doing that and I’m going to wonder what that reason is. Are you using an ArrayList specific method somewhere in this code? For example, do you call trimToSize() somewhere? If you use a List , I know that’s not the case.
Another reason is that it helps complex tools like your IDE in extracting methods. Watch what happens if you follow the bad practice:
The getStrings() method follows the bad practice we talked about above. It returns an ArrayList instead of a List . It would be better if we could automate our IDE to extract methods in a way that we should be writing them. If you use a List on the left hand side of the assignment, it will do just that:
As you can see, the getStrings() method returns a List here instead of an ArrayList .
This doesn’t just apply to ArrayList
I am using an ArrayList as an example for this article because it is a very common Collection , but this best practice applies to all of the Collection types. See this table for more info:
Instead of this | Use This |
---|---|
ArrayList | List |
LinkedList | List |
Vector | List |
HashMap | Map |
TreeMap | Map |
HashSet | Set |
SortedSet | Set |
Conclusion
I hope this article helps you improve your code in the future. Considering going back to your old code and updating it. If you follow the best practices laid out in this article, the quality of your code will improve by being more flexible.