Sunday, December 13, 2009

Common Java Implementations

Java makes a lot of tasks more difficult than they should be. For example, checking if 2 objects differ can be cumbersome when you take into consideration that values could be null. Consider the following example implementing equals for a Name object (yes, some of that duplication could be simplified, but ignore that for now):

public class Name {
private String first;
private String middle;
private String last;

...

@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof Name)) {
return false;
}

Name otherName = (Name) other;

if ((first == null) != (otherName.first == null) {
return false;
}

if ((middle == null) != (otherName.middle == null) {
return false;
}

if ((last == null) != (otherName.last == null) {
return false;
}

return first.equals(otherName.first) &&
middle.equals(otherName.middle) &&
last.equals(otherName.last);
}
}


Now consider the task of reading all the lines of a file:

File file = ...;
BufferedReader br = new BufferedReader(new FileReader(file));
String line = br.readLine();
List<String> lines = new ArrayList<String>();

while (line != null) {
lines.add(line);
line = br.readLine();
}


Maybe you need to build a string that is a colon delimited list of the items in a list:

if (list.isEmpty()) {
return "";
}

String result = "";
result += list.get(0);

for (int i = 1; i < list.size(); i++) {
result += ":";
result += list.get(i);
}

return result;


Well, whenever you start cracking your knuckles, preparing to dig in and write a bit of code that you feel should be easier, stop. Take a deep breath. Consider who might have solved this problem first. It has likely been done before, so you can bank on another's implementation, with the benefit of it being thoroughly tested and likely highly performant.

In particular, the Apache Commons projects has a suite of useful tools to bank on. The equals example can be simplified to the following (thanks to the lang commons project):

@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof Name)) {
return false;
}

Name otherName = (Name) other;
return new EqualsBuilder()
.append(first, otherName.first)
.append(middle, otherName.middle)
.append(last, otherName.last)
.isEquals();
}


While the reading of lines can be simplified to (thanks to the IO commons project):

File file = ...;
List<String> lines = (List<String>) FileUtils.readLines(file);


Besides the Apache Commons projects, you could try out the Google Collection Library to solve the colon delimited list:

return Joiner.on(":").join(list);


You may also want to browse Google's Guava Libraries project.

Whenever these libraries can be applied, you can be sure to cut the amount of code you are writing to a fraction of what it would have been, and likely a lot easier to understand and maintain.

No comments: