21

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.

Community
  • 1
  • 1
A. Levy
  • 29,056
  • 6
  • 39
  • 56
  • 1
    For Double Brace Initialization, see: http://stackoverflow.com/questions/924285/efficiency-of-java-double-brace-initialization – Jim Ferrans Aug 09 '09 at 06:30

11 Answers11

9

Prior to the introduction of the diamond operator in Java 7, static factory methods for creating generic types could be used to reduce verbosity by reducing the need to repeat the type parameter. (This is because without the diamond operator, 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.

Unless you are writing for an old version of Java, as of Java 7 it is better to just use the diamond operator.

Community
  • 1
  • 1
Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
8

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.

Tyler
  • 21,762
  • 11
  • 61
  • 90
  • 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 Aug 09 '09 at 04:42
  • 1
    But careful, the list will be immutable. – Thomas Kappler Jan 21 '10 at 16:31
  • 1
    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 Jul 28 '10 at 16:40
7

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

krosenvold
  • 75,535
  • 32
  • 152
  • 208
  • 2
    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 Aug 09 '09 at 14:34
  • Well I'm all for annotation based spring config, with 5 lines of xml and no code. – krosenvold Aug 09 '09 at 17:06
  • Metaprogramming would more generic name for this technique. Project Lombok is another example of this approach. – user2418306 Mar 16 '16 at 15:25
4

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
  • 22,457
  • 2
  • 40
  • 49
3

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

Mario Fusco
  • 13,548
  • 3
  • 28
  • 37
  • This answer is too broad. Please give an example of verbose code and concise counterpart. If you alluding to lambda notation for closures, then this is obsolete since Java 8. – user2418306 Mar 16 '16 at 12:24
2

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:

Tom
  • 43,583
  • 4
  • 41
  • 61
  • 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 Jan 14 '10 at 14:31
  • Maybe you want `Hamcrest`? Take a look at the examples [here](https://code.google.com/p/hamcrest/wiki/Tutorial) and [here](http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html) – Ehtesh Choudhury Dec 05 '13 at 19:50
  • Using another language is avoiding, not reducing, verbosity of java. – user2418306 Mar 15 '16 at 17:01
2

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 
        }
    }
}

Note that with Java 7 and later, the new "try with resources" syntax makes this particular example redundant.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

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
  • 29,056
  • 6
  • 39
  • 56
0

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
  • 7,983
  • 5
  • 44
  • 41
  • 2
    I don't like the fact that this creates an anonymous class. – Ravi Wallau Aug 09 '09 at 05:12
  • 2
    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 Aug 09 '09 at 05:24
  • Yes this is less verbose, but junior members of your team could get confused. Plus it gives a compiler warning. – mR_fr0g Aug 09 '09 at 10:20
  • 2
    @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 Aug 10 '09 at 04:30
  • Those are **not** static initializers. Those are double brace initializers, yes, exactly that which the topicstarter already mentioned himselves in the topicstart. – BalusC Jan 14 '10 at 13:59
  • @BalusC a double brace initializer IS a static initializer! It is a static initializer inside of an anonymous class. – A. Levy Jan 14 '10 at 14:32
  • 1
    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 Jan 22 '10 at 11:26
  • Ah! Silly me! Thanks for correcting me Christoffer! – A. Levy Feb 18 '10 at 21:09
0

More Guave goodness to initialize immutable maps (which I'm finding to be a way more common case than initializing mutable maps): the ImmutableMap.of(...) variants

Map<Service, Long> timeouts = ImmutableMap.of(
    orderService, 1500, 
    itemService, 500);
oksayt
  • 4,333
  • 1
  • 22
  • 41
0

Ever have to iterate through a collection, just to map its elements by one of its properties? No more, thanks to Maps.uniqueIndex():

private void process(List<Module> modules) {

    Map<String, Module> byName = Maps.uniqueIndex(modules, new Function<Module, String>() {
            @Override public String apply(Module input) {
                return input.getName();
            }
        });

or if this is frequent enough, make the function a public static final member of Module so that the above is reduced to:

    Map<String, Module> byName = Maps.uniqueIndex(modules, Module.KEY_FUNCTION);
oksayt
  • 4,333
  • 1
  • 22
  • 41