Array, list, set, map, tuple, record literals in Java


Occasionally, when I’m thrilled by the power and expressiveness of JavaScript, I find myself missing one or two features in the Java world. Apart from lambda expressions / closures or whatever you want to call “anonymous functions”, it’s the use of advanced literals for common data types, such as arrays, lists, sets, maps, etc. In JavaScript, no one would think about constructing a constant Map like this:

var map = new Object();
map["a"] = 1;
map["b"] = 2;
map["c"] = 3;

Instead, you’d probably write

var map = { "a":1, "b":2, "c":3 };

Specifically, when passing complex parameters to an API function, this turns out to be a very handy syntax.

What about these things in Java?

I’ve recently posted about a workaround that you can use for creating a “List literal” using Arrays.asList(…) here:

http://blog.jooq.org/2011/10/28/javas-arrays-aslist-is-underused/

This is somewhat OK. You can also construct arrays when you assign them, using array literals. But you cannot pass an array literal to a method:

// This will work:
int[] array = { 1, 2, 3 };

// This won't:
class Test {
  public void callee(int[] array) {}
  public void caller() {
    // Compilation error here:
    callee({1, 2, 3});
  }
}

Brian Goetz’s mentioning of various literals on lambda-dev

Missing this feature for quite a while, I was very thrilled to read Brian Goetz’s mentioning of them on the lambda-dev mailing list:

http://mail.openjdk.java.net/pipermail/lambda-dev/2012-May/004979.html

The ideas he was listing were these:

#[ 1, 2, 3 ]                          // Array, list, set
#{ "foo" : "bar", "blah" : "wooga" }  // Map literals
#/(\d+)$/                             // Regex
#(a, b)                               // Tuple
#(a: 3, b: 4)                         // Record
#"There are {foo.size()} foos"        // String literal

Unfortunately, he also added the following disclaimer:

Not that we’d embrace all of these immediately (or ever)

Obviously, at this stage of current Java language evolvements for Java 8, he cannot make any guarantee whatsoever about what might be added in the future. But from a jOOQ perspective, the idea of being able to declare tuple and record literals (with the appropriate backing language-support for such types!) is quite thrilling. Imagine selecting arbitrary tuples / records with their associated index/type, column/type pairs. Imagine a construct like this one in Java or Scala (using jOOQ):

// For simplicity, I'm using Scala's val operator here,
// indicating type inference. It's hard to guess what true
// record support in the java language should look like
for (val record : create.select(
                           BOOK.AUTHOR_ID.as("author"), 
                           count().as("books"))
                        .from(BOOK)
                        .groupBy(BOOK.AUTHOR_ID)
                        .fetch()) {
  
   // With true record support, you could now formally extract
   // values from the result set being iterated on. In other
   // words, the formal column alias and type is available to
   // the compiler:
   int author = record.author;
   int books = record.books;
}

Obviously, this is only speculation, but you can see that with true tuple / record support in the Java language, a lot of features would be unleashed in the Java universe with a very high impact on all existing libraries and APIs

Stay tuned! :-)

Tags: , , , , , , , , , , , , , , , ,

13 responses to “Array, list, set, map, tuple, record literals in Java”

  1. ipolevoy says :

    ditto, I have been using a trick I developed a few years ago to initiate lists and maps. I goes like this:

    List names = list(“Joe”, “Mike”, etc.);

    and:

    Map person = map(“first_name”, “John”, “last_name”, “Doe”);

    While these are not real literals, the reduce amount of code a lot.

    Both methods are statically imported from Collections class of JavaLite Common package that is part of ActiveJDBC project. In fact, many APIs in ActiveJDBC and ActiveWeb are based on the same style.

    • lukaseder says :

      Yes, many libraries have introduced such methods. But as soon as you need just a little more complexity (such as a Map’s key value type association), you lose information. Your JavaLite map initialiser cannot be type-safe if implemented with a varargs parameter. If implemented with overloaded methods, there’s a limit in the number of arguments. So these solutions will always remain workarounds, before true literal language support is added…

      Let’s see when that happens!

      • Eleanor says :

        Surely it can be type safe by including in the methods code to explicitly check the type of each argument,perhaps using the dreaded instanceof operator.

  2. ipolevoy says :

    agree, there is no type safety with the map method, but how much of that do you get in JavaScript? :)
    Anyway, this is not a replacement for literals, as you say a temporary (hopefully) workaround

    • lukaseder says :

      Well, personally I prefer generic typesafety, also for maps. But I see your point and we won’t discuss typesafety (or lack thereof) any further ;-)

  3. Eric Giese says :

    You can use guava: http://code.google.com/p/guava-libraries/ which allows you to build (Immutable)Maps with up to five elements in a typesafe manner. Guavas factory methods are the best ones I know in java-land.

    I’ve create a simple import-me-static-class (called it Predefined.java) which delegates to guava and allows you to write list(xyz) map(xyz, up to ten values) just like mentioned above, In eclipse I included it as a static-favorite, so I’ve got it via content assist.

    Tuples? I don’t recommend them in java because of the verbose generics, Using project-lombok’s @Data annotation is nearly as concise and always better.

    Even in scala, where generics are not such pain and tuples are there, Case-Classes (which are effectively the same as @Data) are much more preferable since their explicit naming requires you to document the intention of the 1..n unrelated fields.

    Thats at least my experience after playing around with these issues for the last few years.

    • lukaseder says :

      Yes, I know Guava and several other useful libraries that take care of workarounds for this lack of language expressiveness. Nevertheless, I’d love to see a more powerful Java…

  4. Thrawn says :

    You actually *can* pass an array literal to a method. However, you need the ‘new’ operator:

    callee(new int[] {1, 2, 3});
    

    Mario Gleichmann has a cool blog post about making classes for literal tuples and maps:

    https://gleichmann.wordpress.com/2008/01/15/building-your-own-literals-in-java-tuples-and-maps/

    • lukaseder says :

      Thanks for that link. I’ve recently found this blog post as well. I personally think it’s a bad idea to let Tuple5 extend Tuple4 just to save some time when implementing tuples. The two types should be incompatible. But then those constructor methods are really useful. I have them as well in jOOQ.

      By “array literal”, I really meant what the JLS calls the Array Initializer (§ 10.6), not the Array Creation Expression (§ 15.10), which is much more verbose

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 2,190 other followers

%d bloggers like this: