What Java is Missing
What might Java look like if it added some much-needed features?
Java's syntax has been sitting dormant for years. I started writing Java over six years ago, and the major addition since then, as far as I can tell, are generics and the "for each" loop. I'm happy to have these, most of the time, but the more I program in other languages, the more things I miss when I'm back in Java. Some things, like pattern matching for function arguments, I'm never going to get. They just don't fit into the Java syntax, much less the way that Java's programming model works. But there are a few things that would be easy enough to integrate into Java that it's time to put them in.
List and Map Literals
This is one of the simplest features of other languages, because lists and maps (or dictionaries, or hashes) are built in as basic types. Unfortunately for Java, these fundamental types are tucked away in the java.util package. It's not like these are ever unavailable, but it is a serious problem that to use the types, you have to import them. And then there's the problem of multiple implementations of each. A Map is just an interface. It might be a HashMap, a TreeMap, or some other custom implementation. A List is also an interface, and in fact it's a subinterface of Collection, and Iterable. Do we ignore the other Collections such as Sets and Queues?
Let's assume a literal that essentially means an ordered collection and start from there.
["Alice", "Bob", "Charlie"]
This follows the example of many other popular languages to create a list. However, with Java, we don't have the option of just having the compiler choose a type for us. We've got to specify it directly.
new ArrayList<String>["Alice", "Bob", "Charlie"]
Instead of creating an empty ArrayList using parentheses to invoke the constructor, we use this new square-bracket list notation. The great thing about this notation is that it doesn't have to only specify a list. We can use the exact same syntax to specify a Set:
Set<String> names = new HashSet<String>["Alice", "Bob", "Charlie"];
There's not much magic required behind the scenes. You could say that any class<E> that has the add(E) method could take advantage of this. Suddenly every ad-hoc list you would want to create is a one-liner rather than an (n+1)-liner.
But what about maps? Maps are based on pairings rather than single items. Given what symbols are used in different places in Java, I'd say that adding some parentheses would be the best choice in this case.
Map<String, Integer> grades = new HashMap<String, Integer>[("Alice", 92),
("Bob", 79),
("Charlie", 98)];
As long as you're a class<K, V> that has the put(K, V) method, you're good to use this syntax too. Java loses no expressiveness, as far as I can see, and we as the programmers finally can implement our simple data structures, without having to resort to multi-line ugly hacks. This code makes a few other things a lot more simple, as well. If you're declaring some Collection or Map as final, then now your initialization code has been made significantly easier.
Tuples and Multiple Return Values
Tuples are a great feature of Python. They are at once overhyped and underused, but extremely powerful. When you're learning Python, you're likely to encounter this little gem, which allows you to swap two variables using the power of tuples:
var1, var2 = var2, var1
Awesomeness factor? Off the charts. Actual usefulness? Mediocre at best. But the underlying functionality is important and quite handy. The way the variable swapping works, as I understand it, is that we first evaluate the right hand side. It takes the values from var2 and var1 and puts them into a tuple of length 2 (a double), indicated by the comma. Based on that tuple, it uses auto-unpacking to take the values from the tuple formed on the right hand side and assign them to the variables on the left, which is also sort of a tuple. Another way to write this with more explicit tuples would be:
(var1, var2) = (var2, var1)
Tuples and this auto-unpacking make it easy to do all sorts of things, from extracting values of a list/tuple into separate variables, to essentially returning multiple values.
before_comma, after_comma = "Hello, World!".split(",")
first_value, second_value = ["Foo", "Bar"] # Only works if the list has 2 items
peanut_butter, jelly = retrieve_pb_and_j()
Tuples and auto-unpacking are sorely missing from Java. Say we're building the Dee-lish Peanut Butter and Jelly Sandwich Maker 9000™ machine, and we've decided to use Java. If we had this tuple functionality, we could just tell Java to go and get the peanut butter and jelly from the fridge like in the last Python example. Of course, we don't have that functionality.
Instead, our choices with Java are relatively poor. We can tell Java to get us the peanut butter, and afterwards, get us the jelly. We can also construct a special class to hold a peanut butter jar and a jelly jar.
class TwoGreatTastesBetterTogether {
private PeanutButter peanutButter;
private Jelly jelly;
// ...
}
Of course, if we've gone that far, we might as well construct a much more elaborate sandwich-makings housing. It can hold any number of sandwich ingredients. Whatever you want, however you want it. It's ready for professional kitchens!
class SandwichIngredientsMonstrosity<Ingredient> {
private Collection<Ingredient> ingredients;
// ...
}
Yikes. I really just wanted a PB & J maker.
public PeanutButter, Jelly getPbAndJ() {
// ...
return peanutButter, jelly;
}
// ...
PeanutButter pb, Jelly j = getPbAndJ();
Ahh. Much better. It doesn't quite have the dynamic qualities of the Python implementation, but it gets the job done.
Other people get this done with a generic Pair<A, B> class. Sure, we could do that. But then we also need a Triple<A, B, C> and a Quadruple<A, B, C, D>. And so on. This is not a good solution. What happens when we need just one more than people have included in the standard libraries? As a rule, when choosing how many of something we support, we should strive to either support zero, one, or n. Java has gotten down being able to return nothing or one thing, but returning more than one thing is the next step, not returning one thing that represents a predetermined number of other things.
First-class Functions and Lambdas
These are actually due to show up in the next version of Java. Or rather, they were until Oracle bought Sun and broke the schedule. Now they're due to ship in the version after next. But regardless, it's in the works. And thank goodness, because this is a big feature that I wouldn't try to pass off as a simple addition. Based on what we've seen so far, this actually shows that Java is capable of more guessing than it's letting on. The syntax available so far looks something like this:
// Type one
#()("No arguments").();
#(Object argument)("My argument: " + argument.toString()).(1);
// Type two
#(){ return "No arguments"; }.();
#(Object argument){ return "My argument: " + argument.toString(); }.(1);
The first type is exactly what we're looking for in a lambda. We specify the type of the arguments, but not the return type. We just write the one-liner as an expression. The second type has much more potential. Nothing here is limiting us to one-liners. These are full-fledged functions. Java, which previously was home only to methods, now would have first class functions. The type of these things has been hidden so far, but it was shown that a thing like the following would work:
Object myFun = #(){ return "Hello, World!"; };
If we're not lucky, the final syntax will be something like this:
Function<R><E, F> myFun = #(E arg1, F arg2){ return new R(); };
If we're lucky, we won't have to specify the argument types or return types using some sort of generics:
Function myFun = #(E arg1, F arg2){ return new R(); };
Either way, we'll now be able to pass functions around, create functions inside other functions, and generally do all sorts of other cool stuff. This would be the biggest leap in functionality for Java in a decade, far more than the minor proposals for tuples, literal collections, and literal maps above.
⋙
It's clear from the initiatives intended for Java 7, like Lambda, that Java's creators want it to prosper and gain back developer mindshare, so I just hope that they will be able to get these much-needed features in there soon. I'm generally fine with Java's horribly excessive syntax, as long as it's got the features that put it on par with other JVM languages.
In the meantime, it's Jython for me.