views:

529

answers:

10

One of the things that can be a little annoying about Java is the amount of code you need to express concepts. I am a believer in the "less code is better" philosophy, and I'd like to know how I can write Java without being so frustratingly verbose. Recently, I read the Hidden Features of Java question and was introduced to using double-brace initialization to simulate a List or Map literal. There are, of course, drawbacks to using this method, but it does allow you to do certain things with significantly fewer characters and (if you format it right) make the code a lot cleaner and clearer. I'm wondering if there aren't other clever tricks and lesser known language features which could make my code more concise.

I'd like to see answers with an explanation of the technique, the more verbose way which it replaces, and any potential drawbacks to using the technique.

+6  A: 

A similar one you probably already know about, using the "varargs" feature:

String[] array = new String[] {"stack", "over", "flow"};
List<String> list = Arrays.asList(array);

can be abbreviated

List<String> list = Arrays.asList("stack", "over", "flow");

Admittedly not a huge savings, but it does reduce the verbosity a little bit. As Thomas notes, the list will be immutable, so watch out for that. Actually, you can modify the list, you just can't change its length. Thanks to pimlottc for pointing that out.

MatrixFrog
Even without varargs that first example could easily have been 22 characters shorter. :-)
Laurence Gonsalves
Yes! I have used varargs in my own functions, but for some reason I have overlooked the fact that Arrays.asList uses varargs. Thanks!
A. Levy
But careful, the list will be immutable.
Thomas Kappler
That's not true, the list is mutable; you just can't change its length. You can replace any value within the list, e.g. Arrays.asList("1", "2", "3").set(0, "a") is valid.
pimlottc
+7  A: 

Static factory methods for creating generic types can reduce verbosity by reducing the need to repeat the type parameter. (This is because Java never infers the type parameter on constructors, but it will on methods calls.) Google Collections uses this technique, so you can write:

Set<MyClassWithALongName> set = Sets.newHashSet();

instead of:

Set<MyClassWithALongName> set = new HashSet<MyClassWithALongName>();

Look in the Lists, Sets and Maps classes of Google Collections for methods starting with "new" for more examples of this.

Laurence Gonsalves
Cool! I'll look for opportunities to use return type inference to my advantage.
A. Levy
A: 

Static initialisers

Example 1 (Map):

Map<String, String> myMap = new HashMap<String, String>() {{
    put ("a", "b");
    put ("c", "d");
}};

Example 2(List):

List<String> myList = new ArrayList<String>() {{
    add("a");
    add("b");
    add("c");
}};
idrosid
Yup. I use these to make up for the fact that Java doesn't have a Map literal syntax.
A. Levy
I don't like the fact that this creates an anonymous class.
Ravi Wallau
Why don't you like anonymous classes Ravi? One of the downsides that I know about this technique is that if you use the resulting Map or List outside its enclosing object, you are passing an implicit reference to the enclosing object. This can cause memory leaks. But as long as you understand that and are careful, I don't see the problem. Perhaps this caveat should be added to the answer as a drawback.
A. Levy
Yes this is less verbose, but junior members of your team could get confused. Plus it gives a compiler warning.
mR_fr0g
@mR_frOg, I really disagree with this sentiment. I've heard the argument so many times that "we can't use that advanced technique because it might confuse less experienced developers". How do you propose that the neophytes gain the experience and skills to become an advanced developer? They have to see advanced techniques to learn them. The argument should be on the merits of the coding style, and not on whether a newbie can grasp it easily. If you feel that others may be confused as to what is going on, leave a comment in your code describing what you are doing.
A. Levy
Those are **not** static initializers. Those are double brace initializers, yes, exactly that which the topicstarter already mentioned himselves in the topicstart.
BalusC
@BalusC a double brace initializer IS a static initializer! It is a static initializer inside of an anonymous class.
A. Levy
A. Levy: No, it lacks the keyword static, so it is an instance initializer, see http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#246032
Christoffer Hammarström
Ah! Silly me! Thanks for correcting me Christoffer!
A. Levy
+2  A: 

Fluent interfaces can help - using builders and method chaining to make something resembling a DSL in java. The code you end up with can be a little harder to read though as it breaks Java's normal coding conventions such as removing the set / get from properties.

So in a fake Swing fluent interface you might define a button thus:

JButton button = Factory.button().icon(anIcon).tooltip("Wow").swing();

Another approach is to use another language there are many that integrate well with the JVM such as:


Cal

Tom
Do you have an example of a Java API that provides a fluent interface? I'm familiar with the concept from RoR and have also looked at FluentNHibernate but I'd like to see how this "feels" in the Java world. Anyways, +1 for mentioning Scala. A nice language that integrates excellently with Java and the JVM. I have yet to try it in a real project though.
Robert Petermeier
+6  A: 

Use a dependency injection framework like spring. I'm almost always amazed at how much code construction logic produces.

krosenvold
Also try Guice. http://code.google.com/p/google-guice/ It produces shorter configurations than Spring (especially compared to Spring's XML configs) and you get compile-time type checking.
Esko Luontola
Well I'm all for annotation based spring config, with 5 lines of xml and no code.
krosenvold
+2  A: 

A "closeQuietly" method can be used in try/finally blocks in situations where IO exceptions on close are uninteresting (or impossible).

Closeable c = null;
try {
    ...
    c = openIt(...);
    ...
} finally {
    closeQuietly(c);
}

where:

/** Close 'c' if it is not null, squashing IOExceptions */
public void closeQuietly(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // log error 
        }
    }
}
Stephen C
+2  A: 

I've found that the most (only?) effective way to write concise java is to not write java at all. In cases where I needed to write something quickly that still interoperates with Java, I've found Groovy to be an excellent choice. Using a more concise language that still compiles to JVM bytecode can be an excellent solution. While I have no personal experiences with it, I've heard that Scala is an even better choice than Groovy in many cases.

Benson
Agreed. Groovy is the best way to write less java!
leebutts
A: 

I wrote a plugin to zip my java source as I write it, this has reduced it's size by several orders of magnitude.

Sneakyness
This doesn't reduce the amount of code you have to write, which was the point of the question.
A. Levy
You have no proof of that.
Sneakyness
@Sneakyness: No proof of *what*? That it doesn't reduce the amount of code you have to write **or** that the amount of code you have to write was the point of the question?
Adam Paynter
+3  A: 

Check out lambdaj. It has lots of features that can help to make your code more concise and readable.

Mario Fusco
Cool. Lambdaj looks really slick. Thanks!
A. Levy
+1  A: 

I found a blog post giving an interesting technique which allows for writing a map literal in Java like you would be able to do in Perl, Python, Ruby, etc: Building your own literals in Java - Tuples and Maps I really like this approach! I'll just summarize it here.

The basic idea is to create a generic pair class and define static functions that will construct a pair, and a map from a varargs array of pairs. This allows the following concise map literal definition:

Map(o("height", 3), o("width", 15), o("weight", 27));

Where o is the name of the static function to construct a pair of T1 and T2 objects, for any object types T1 and T2, and Map is the name of the static function to construct a Map. I'm not sure I like the choice of Map as the name of the map construction function because it is the same as the name of the Java interface, but the concept is still good.

A. Levy