Code Duplication

Donald Raab
Javarevisited
Published in
7 min readMay 1, 2019

Duplicate code makes me itch, until I scratch it away.

Itchy scratchy hay!

I hate code duplication

Nothing bothers me quite like code duplication. I get an unbearable itch every time I spot some duplication in a code base. The only way to make the itch go away is to find a suitable way to remove the duplication.

I am always reminded of this quote from a Yahoo Groups post from Ryan King many years ago when I spot code duplication.

So, duplication sucks. The more rabidly a person hates duplication, the more I trust their opinions on managing information. A programmer, upon noticing some redundancy, should be thrown into a panic, begin hyperventilating, and stammer something about “¡El diablo! !El diablo está en mi software!”.

— Ryan King

So what can we do when we find code duplication? We can learn ways to remove it. Google and StackOverflow are great resources for finding answers to solving many common programming problems. They can be your first port of call for discovering and learning new APIs that may help reduce some of the duplicate code you may have written previously.

Simple patterns of duplication

Sometimes code duplication is easy to spot and to remove. I will start by describing some very simple common patterns of duplication I spot in code bases all the time.

Boolean Test Pattern

Testing a boolean value and returning true or false. I’ve seen this pattern of code more than you might imagine over the years.

public boolean isSomething()
{
if (!this.calculateSomeBooleanValue())
{
return true;
}
else
{
return false;
}
}

Write this instead.

public boolean isSomething()
{
return !this.calculateSomeBooleanValue();
}

Collection Factory Pattern

Here’s another simple pattern that can be fixed easily. This kind of code is very commonly written in test cases. It is important to address code duplication issues across your entire code base, including tests.

List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");

This code can be replaced as follows using Eclipse Collections mutable factory pattern.

List<String> list = Lists.mutable.with("one", "two", "three");

Here’s an answer on StackOverflow that show different ways to initialize a List, Set, and Bag in one line with Eclipse Collections.

Unmodifiable Static Collection Initializer Pattern

The following code used to be common in Java versions prior to Java 9, for creating a static unmodifiable List.

public static final List<String> LIST;

static
{
List<String> newList = new ArrayList<>();
newList.add("one");
newList.add("two");
newList.add("three");
LIST = Collections.unmodifiableList(newList);
}

This can be written more simply as follows using plain old Java.

public static final List<String> LIST =
Collections.unmodifiableList(
Arrays.asList("one", "two", "three"));

This can also be replaced as follows using Eclipse Collections.

public static final List<String> LIST =
Lists.mutable.with("one", "two", "three").asUnmodifiable();

As of Java 9, you can also write the following. The method List.of() returns an unmodifiable List.

public static final List<String> LIST = 
List.of("one", "two", "three");

You can also use an ImmutableList from Eclipse Collections if you want to have a contractually immutable interface like ImmutableList which has no mutating methods.

public static final ImmutableList<String> LIST = 
Lists.immutable.with("one", "two", "three");

Static Map Initializer Pattern

Initializing a static Map can be a bit more challenging, if you have more than three or four key/value pairs in the Map.

public static final Map<Integer, String> MAP;

static
{
Map<Integer, String> newMap = new HashMap<>();
newMap.put(1, "one");
newMap.put(2, "two");
newMap.put(3, "three");
newMap.put(4, "four");
newMap.put(5, "five");
MAP = Collections.unmodifiableMap(newMap);
}

Refactored to use an Eclipse collections unmodifiable Map.

public static final Map<Integer, String> MAP =
Maps.mutable.<Integer, String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.withKeyValue(3, "three")
.withKeyValue(4, "four")
.withKeyValue(5, "five")
.asUnmodifiable();

Refactored to use an Eclipse collections ImmutableMap which also has no mutating methods in its interface.

public static final ImmutableMap<Integer, String> MAP =
Maps.mutable.<Integer, String>empty()
.withKeyValue(1, "one")
.withKeyValue(2, "two")
.withKeyValue(3, "three")
.withKeyValue(4, "four")
.withKeyValue(5, "five")
.toImmutable();

Here’s a an answer on StackOverflow that shows various ways to initialize a static map with Eclipse Collections.

Iteration Patterns

One of the primary reasons I started building Eclipse Collections was that I would see developers writing the same for-loops over and over again. Developers were constantly reimplementing collection iteration patterns in Java. I saw code duplication everywhere! Developers did this prior to Java 8 because the iteration patterns available to Java developers then were limited to what could be found on the Collections utility class. Eclipse Collections has been in development and used in production since JDK 1.4. Eclipse Collections has been my preferred solution for removing duplicate iteration pattern code for the past fifteen years in Java.

Filter Pattern

Prior to Java 8, the following was the usual way of filtering a source collection to a target collection based on some condition.

List<Integer> source = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> target = new ArrayList<>();
for (Integer value : source)
{
if (value % 2 == 0)
{
target.add(value);
}
}

Here’s the same code refactored using the Eclipse Collections select method.

MutableList<Integer> source = Lists.mutable.with(1, 2, 3, 4, 5);
MutableList<Integer> target = source.select(each -> each % 2 ==0);

Here’s an answer on StackOverflow to the question of “What is the best way to filter a Java Collection?”

Transform Pattern

Prior to Java 8, the following was the typical way of converting one collection type to another.

List<Integer> source = Arrays.asList(1, 2, 3, 4, 5);
List<String> target = new ArrayList<>();
for (Integer value : source)
{
target.add(value.toString());
}

Here’s the same code refactored using the Eclipse Collections collect method.

MutableList<Integer> source = Lists.mutable.with(1, 2, 3, 4, 5);
MutableList<String> target = source.collect(Object::toString);

Any / All / None Patterns

Prior to Java 8, you would either use a break statement with a boolean variable or a direct return from inside an if statement to see if any, all, or none of the elements of a collection match a given condition.

Any Pattern

List<Integer> source = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEvens = false;
for (Integer value : source)
{
if (value % 2 == 0)
{
anyEvens = true;
break;
}
}

Refactored with Eclipse Collections anySatisfy method.

MutableList<Integer> source = Lists.mutable.with(1, 2, 3, 4, 5);
boolean anyEvens = source.anySatisfy(each -> each % 2 == 0);

All Pattern

List<Integer> source = Arrays.asList(1, 2, 3, 4, 5);
boolean allEvens = true;
for (Integer value : source)
{
if (value % 2 != 0)
{
allEvens = false;
break;
}
}

Refactored with Eclipse Collections allSatisfy method.

MutableList<Integer> source = Lists.mutable.with(1, 2, 3, 4, 5);
boolean allEvens = source.allSatisfy(each -> each % 2 == 0);

None Pattern

List<Integer> source = Arrays.asList(1, 2, 3, 4, 5);
boolean noneEvens = true;
for (Integer value : source)
{
if (value % 2 == 0)
{
noneEvens = false;
break;
}
}

Refactored with Eclipse Collections noneSatisfy method.

MutableList<Integer> source = Lists.mutable.with(1, 2, 3, 4, 5);
boolean noneEvens = source.noneSatisfy(each -> each % 2 == 0);

Other Iteration Patterns

There are many other iteration patterns available in Eclipse Collections that can help you remove duplicate code. There are over one hundred variations of iteration patterns and other methods available on the RichIterable parent interface alone.

RichIterable APIs

Sometimes code duplication is necessary

Occasionally code duplication is the best available solution to solve a performance problem. A great example in Eclipse Collections is the primitive collections. Eclipse Collections has primitive collection support for Lists, Sets, Bags, Stacks and Maps for all eight primitive combinations (boolean, byte, char, double, float, int, long, short). The code to implement all of these container types is nearly identical. So if you read the code for an IntArrayList it will look eerily similar to the code in ShortArrayList and LongArrayList. What is important in cases where you want to provide library support for primitive types in Java is to leverage a code generation strategy wherever possible and to not duplicate the code by hand. With Eclipse Collections, we use the StringTemplate library and write templates once for each container type that are then used to generate the eight container types required to support all of the primitives.

In the future, if the work in Project Valhalla becomes part of a JDK release and we get support for generic specialization over primitive types, we may have new language level strategies in Java to reduce the amount of generated code we have to produce today to support primitive types. I am very excited to see how this support may potentially reduce our code duplication burden.

Additional Patterns of Duplication

There are a lot more patterns of duplication out there. Your IDE and various code analysis tools can sometimes help you find the obvious ones caused by copy and paste. Other times you may just need to read your code and see if you can recognize patterns where some code is going into too much detail about how to do something (for loops are sometimes a cue). Code that is written well should tell you clearly what it is doing, not how it is doing it.

Deleting duplicate code makes me feel very satisfied. It helps reduce the total cost of ownership for a an application or library. Less code to read, test, maintain, and deploy means less potential bugs to discover, debug and fix.

Eclipse Collections is open for contributions. If you like the library, you can let us know by starring it on GitHub.

--

--

Donald Raab
Javarevisited

Java Champion. Creator of the Eclipse Collections OSS Java library (https://github.com/eclipse/eclipse-collections). Inspired by Smalltalk. Opinions are my own.