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: https://blog.jooq.org/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! :-)

13 thoughts on “Array, list, set, map, tuple, record literals in Java

  1. 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.

    1. 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!

      1. 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.

        1. In this discussion, we’re looking into compile-time typesafety. Runtime checks do not provide the same safety, in my opinion.

  2. 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

    1. 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. You can use guava: https://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.

    1. 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…

    1. 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