You are on page 1of 1

Sign in Get started

ARCHIVE WRIT E FOR US S T YLE GUIDE ABOUT JOB BOARD

You have 2 free stories left this month. Sign up and get an extra one for free.

Returning Collections From Methods


in Java
Never return null in place of a collection
Dave Taubler Follow
Jan 17 · 6 min read

Photo by Ella Olsson on Unsplash

Writing software often means fetching and returning data. In an object-


oriented language like Java, we generally express data in terms of
properties of a class. Unlike many newer OO languages, Java doesn’t
offer properties as a first-class construct, so we instead use JavaBean
getters and setters, in order to maintain encapsulation. As a result, most
of us have grown accustomed to writing code like the following:

public class MyClass {


private String data;
public String getData() { return this.data; }
public void setData(String data) { this.data = data; }
}

In the example above, we see a simple class with a simple property: a


String called data. Of course, data can either contain a value, or it can
be null.

How do we deal with Collection -type properties? Let’s fabricate a simple


class that encapsulates a List :

public class MyClass {

private List<String> myStrings;

We have a field — a List of String s — called myStrings , which is


encapsulated in MyClass . Now, we need to provide accessor methods:

public class MyClass {

private List<String> myStrings;

public void setMyStrings(List<String> s) {


this.myStrings = s;
}

public List<String> getMyStrings() {


return this.myStrings;
}

Here we have a properly-encapsulated — if verbose — class. So we’ve


done good, right? Hold that thought.

. . .

Optional Lessons
Consider the Optional class, introduced in Java 8. By now, you’ve
probably heard the mantra that you should never return null from a
method that returns an Optional . Why? Consider the following contrived
example:

public class Foo {

private String bar;

public Optional<String> getBar() {


// don't actually ever do this
return (bar == null) ? null : Optional.of(bar);
}

Now clients can use the method like this and risk throwing a
NullPointerException :

foo.getBar().ifPresent(log::info);

Alternatively, they could perform a null check:

if (foo.getBar() != null) {
foo.getBar().ifPresent(log::info);
}

Of course, we’d never write a method like that. Doing so defeats the very
purpose of Optional s. In fact, it so defeats the purpose of Optional s that
it’s nothing short of a golden rule that any API that returns Optional will
never return a null value.

The drawer still exists even when all the socks are removed, right?

Back to Collection s. Collection s and Optional s are actually similar


beasts. They are both “container” objects designed to hold other values.
An Optional contains either none or one, while a Collection contains
either none or some. (Those familiar with functional programming might
think of Collection s and Optional s as monads, although Java 8’s
decision to use Stream s means that this is technically not true.)

As such, there should be no reason to return null Collection s. Simply


return an empty (zero-sized) Collection to indicate the lack of any
elements.

It’s for this reason that it’s becoming more common to ensure that
methods that return Collection types (including arrays) never return
null values, the same as methods that return Optional types. Perhaps you
or your organization have already adopted this rule in writing new code.
If not, you should. After all, would you (or your clients) rather do this?:

boolean isUnique = personDao.getPersonsByName(name).size() == 1;

Or have your code littered with the likes of this? :

List<Person> persons = personDao.getPersonsByName(name);


boolean isUnique = (persons == null) ? false : persons.size() == 1;

. . .

Keeping Control of our Collections


But there’s a little more to it. Let’s return to our MyClass class. As it is, an
instance of MyClass could easily return null from the getMyStrings()

method. In fact, a fresh instance would do just that. So, to adhere to our
new never-return-a-null-Collection guideline, we need to fix that:

public class MyClass {

private List<String> myStrings = new ArrayList<>();

public void setMyStrings(List<String> s) {


this.myStrings = s;
}

public List<String> getMyStrings() {


return this.myStrings;
}

Problem solved? Not exactly. Any client could call


aMyClass.setMyStrings(null) , in which case we’re back to square one. So
let’s expand the setMyStrings() method:

public void setMyStrings(List<String> s) {


if (s == null) {
this.myStrings.clear();
} else {
this.myStrings = s;
}
}

Now, even when null is passed to the setter, myStrings will retain a valid
reference. So are we all done?

Sort of. We could stop here. But really, there’s more we should do.

Consider that we are still replacing our private ArrayList with the List

passed to us by the caller. This has two problems. First, we no longer


control the specific List implementation used by myStrings . In theory,
this shouldn’t be a problem, right? However, consider this:

myClass.setMyStrings(Collections.unmodifiableList("Heh, gotcha!"));

If we ever update MyClass such that it attempts to modify the contents of


myStrings , bad things can start happening at runtime.

The second problem is that the caller retains a reference to MyClass ’s

underlying List . So now, that caller can now directly manipulate our
List .

What we should be doing is storing the elements passed to us in the


ArrayList to which myStrings was initialized. In addition, we should be
hiding the internals of our class from outside callers. The reality is that
callers of our classes shouldn’t care whether there’s an underlying List ,

or Set , or array, or some runtime dynamic code-generation voodoo


storing the String s that we pass to it. All they should care about is setting
and retrieving a group of String s. So let’s update the setMyStrings()

method:

public void setMyStrings(Collection<String> s) {


this.myStrings.clear();
if (s != null) {
this.myStrings.addAll(s);
}
}

This has the effect of ensuring that myStrings ends up with the same
elements contained within the input parameter (or is empty if null is
passed) while ensuring that the caller doesn’t have a reference to
myStrings .

Now that myStrings reference can’t be changed, let’s just make it a


constant:

public class MyClass {


private final List<String> myStrings = new ArrayList<>();
...
}

While we’re at it, we shouldn’t be returning our underlying List via our
getter. That too would leave the caller with a direct reference to
myStrings . To remedy this, recall the “defensive copy” mantra that
Effective Java beat into our heads (or should have):

public List<String> getMyStrings() {


// depending on what, exactly, we want to return
return new ArrayList<>(this.myStrings);
}

At this point, we have a well-encapsulated class that eliminates the need


for null-checking whenever its getter is called. We have, however, taken
some control away from our clients. Since they no longer have direct
access to our underlying List , they can no longer, say, add or remove
individual String s.

No problem — we can simply add methods like this:

public void addString(String s) {


this.myStrings.add(s);
}

And this:

public void removeString(String s) {


this.myStrings.remove(s);
}

Might our callers need to add multiple String s at once to a MyClass

instance? That’s fine as well:

public void addStrings(Collection<String> c) {


if (c != null) {
this.myStrings.addAll(c);
}
}

And so on:

public void clearStrings() {


this.myStrings.clear();
}

public void replaceStrings(Collection<String> c) {


clearStrings();
addStrings(c);
}

Collecting Our Thoughts


Here, then, is what our (admittedly contrived) class might ultimately look
like:

public class MyClass {

private final List<String> myStrings = new ArrayList<>();

public void setMyStrings(Collection<String> s) {


this.myStrings.clear();
if (s != null) {
this.myStrings.addAll(s);
}
}

public List<String> getMyStrings() {


return new ArrayList<>(this.myStrings);
}

public void addString(String s) {


this.myStrings.add(s);
}

public void removeString(String s) {


this.myStrings.remove(s);
}

// And maybe a few more helpful methods...

With this, we’ve achieved a class that:

is still a POJO that conforms to the JavaBean spec

fully encapsulates its private member(s)

Most importantly ensures that its method that returns a Collection

always does just that — returns a Collection — and never returns null .

T hanks to Zack Shapiro.

Java Programming Design Patterns Functional Programming Monad

211 claps 3 responses

WRIT T EN BY
Dave Taubler Follow

Software architect, engineering leader, musician, husband,


dad

Better Programming Follow

Advice for programmers.

More From Medium

Enough Vim to Be Create a Data Marvel : Outcome of Our First I Wrote a Python Web
Dangerous Develop a Full-Stack Call for Contributors for Scraper T hat Sends Me
Patrick Divine in Better Application with Spring DeckDeckGo Text Messages About
Programming and Neo4j—Part 1 David Dal Busco in Better Job Postings
Jennifer Reif in Neo4j Programming Zack Claar in Better
Developer Blog Programming

Learn Other Skills to Snippets About Exceptional Exceptions Why You Should Learn
Transform Your Code Concurrency for Coroutines made Flutter
Chris Cooney in Better Nicolas A Perez in easy…? Faisal Choura in Better
Programming HackerNoon.com Anton Spaans in T he Kotlin Programming
Chronicle

Discover Medium Make Medium yours Become a member


Welcome to a place where words matter. On Medium, Follow all the topics you care about, and we’ll deliver the Get unlimited access to the best stories on Medium — and
smart voices and original ideas take center stage - with no best stories for you to your homepage and inbox. Explore support writers while you’re at it. Just $5/month. Upgrade
ads in sight. Watch

About Help Legal

You might also like