Many companies and developers move away from Java to new languages: Ruby, Python, Groovy, Erlang, Scala. You might be trapped with Java.
Even if you’ve trapped, you can change your programming style and reap some of the benefits of those new languages. In the last 15 years Java programming style has changed significantly:
1. Final is your new love: More and more Java developers in the teams I’ve worked with, started to use final. Making variables final prevents changing those values. Most often, if you reasign a value, it’s a bug or you should use a new variable. Final prevents bugs and makes code easier to read and understand. Make everything immutable.
final Foo bar = new Foo();
I’ve written more about this topic in
“All variables in Java must be final”.
2. No setters. Many Java developers automatically – sometimes with the evil help of an IDE – write setters for all fields in their classes. You should not use setters. Think about each setter you want to write, are they really necessary for your fields? Better create new copies of your objects if values change. And try to write code without getters either.
Tell, don’t ask tells you more about the concept.
3. Do not use loops for list operations. Learning from functional languages, looping isn’t the best way to work on collections. Suppose we want to filter a list of persons to those who can drink beer. The loop versions looks like:
1 2 3 4 5 6
| List<Person> beerDrinkers = new ArrayList<Person>();
for (Person p: persons) {
if (p.getAge() > 16) {
beerDrinkers.add(p);
}
} |
This can – even in Java – be rewritten to a more a functional programming style. For example using
Google collections filter:
1 2 3 4 5 6 7
| Predicate<HasAge> canDrinkBeer = new Predicate<HasAge>() {
public boolean apply(HasAge hasAge) {
return hasAge.getAge() > 16;
}
};
List<Person> beerDrinkers = filter(persons, canDrinkBeer); |
As remarked by Dave Jarvis, I should have dropped the getter, and he’s right ;-)
1 2 3 4 5
| Predicate canDrinkBeer = new Predicate() {
public boolean apply(HasAge hasAge) {
return hasAge.isOlderThan( 16 );
}
}; |
which would lead to better code down the road:
1 2 3 4 5
| Predicate canDrinkBeer = new Predicate() {
public boolean apply( HasAge hasAge, HasAge otherAge ) {
return hasAge.isOlderThan( otherAge );
}
} |
The predicate version is slightly larger, but consists of two parts. Each one is easier to understand. While the loop version gets unreadable fast with new requirements, the functional version can easily be combined,
List beerDrinkers = filter(filter(persons, canDrinkBeer), isMale);
More on this at the
Metaphysical Developer.
4. Use one liners: Write concise code. Java is a noisy language. But don’t make it noiser as it needs to be. Instead of
1 2 3 4 5
| public int add(int a, int b)
{
int result = a + b;
return result;
} |
write
1 2
|
public int add(int a, int b) { return a + b; } |
IDEA and possibly other IDEs can keep oneliners formatted as oneliners, if you tell them so.
5. Use many, many objects with many interfaces. Domain driven design currently makes a big splash. A class should be splitted into many roles, implementing many interfaces. This way the class is reusable.
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Person implements Nameable, Hireable, LivesAt {
...
}
public interface Nameable {
String getName();
}
Methods should be written to only work on roles, not classes. This way methods can work on more objects. Another benefit is lower coupling.
public void print(Nameable name) {
System.out.println(name.getName());
} |
I’ve written more about that in
“Never, never, never use String in Java “.
6. Use Erlang-Style Concurrency. The Java concurrency primitives like locks and synchronized have been proven to be too low level and often to hard to use. There are better ways to write concurrent code. Erlang Style concurrency is one of them – in Java there are many ways to achive this in Java – I’ve written about them
here. Newer ones are
Akka and
Actorom. You can also use Join/Fork or the myriad of data structures in java.util.concurrent.
7. Use Fluent Interfaces. Fluent interfaces can make your code much more readable and shorter. A very good example is the MapMaker API in Google Collections:
1 2 3 4 5 6 7 8 9 10 11
| ConcurrentMap graphs = new MapMaker()
.concurrencyLevel(32)
.softKeys()
.weakValues()
.expiration(30, TimeUnit.MINUTES)
.makeComputingMap(
new Function() {
public Graph apply(Key key) {
return createExpensiveGraph(key);
}
}); |
8. Data Transfer Objects without setters and getters. If you have simple data holders or data transfer objects, don’t write boiler plate code with getters and setters. I know this is heresy in Java, but just use public fields. Instead of
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Point {
private int x;
private int y;
pulic Point(int x, int y) {
this.x = x;
this.y = y;
}
public int setX(int newX) {
x = newX;
}
public int getX() {
return x;
}
...
}
...
int x = p.getX();
int y= p.getY(); |
write
1 2 3 4 5 6 7 8 9 10 11 12
| public class Point {
public final int x;
public final int y;
pulic Point(int x, int y) {
this.x = x;
this.y = y;
}
}
...
int x = p.x;
int y = p.y; |
Refactoring is easy, should you need it. If you do not control all the code and it’s usage, you might need to be more careful though.
This tips lead to better Java code. Try them in your next Java class. What do you think? I’d like to hear how your Java coding style has changed in the last 10 years.
Update: Some thoughts to
Cedrics thoughts.
As the author of the post, your thoughts are appreciated, some of mine:
“Besides, it’s convenient to be able to mutate object if you want to use pools.”
No setters doesn’t mean you can’t mutate objects, it’s just that plain setters are not object oriented thinking. How about stop() vs. setStop(true);
“I think the first example is more readable than the second one that uses Predicates.”
Partager