Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Java: Missing Features (infoq.com)
35 points by henrik_w on Nov 26, 2015 | hide | past | favorite | 50 comments


Apart from primitive specialization the biggest omission in my opinion is the lack of value types ("structs"). It's almost impossible to write code that is heap allocation free or allows reasoning about cache locality.


Just yesterday I've watched this: https://www.youtube.com/watch?v=88-szpeNfrU

Long story short: keep the traditional getters and setters but have just a byte[] field to store the object state. For example If you need just the date (without the time) you can store it in 2 bytes, say 7 and 8, and in getDate() method you do

    public Date getDate() {
         int day = bytes[8] * 256 + bytes[9]
         return new Date(day * MILLIS_PER_DAY);
    }
Some of the improvements are amazing


If you're familiar with the JVM's "escape analysis" then it is at least possible to write allocation-free code. But keeping a mental model of the JIT's optimizer in your head does not make for fun or easy programming. It's so much nicer to work with value types such as those found in C#.


http://objectlayout.org/ is a possible solution. But currently it and panama and JEP 169 are still forming into a hopefully coherent gestalt :(


What I would love to come over from C# is:

* Auto-Properties - Get rid of all those ugle getters and setters cluttering up POJOs

* Object and Collection Initialisers - https://msdn.microsoft.com/en-us/library/bb384062.aspx


If there's no logic in the getter and setters, just make the properties public.


That works until you want to add logic without breaking existing interfaces.


Or until you need to use them in beans and the like.


Play!Framework 2 for Java is awesome in this matter. You write public members, but at compilation it transforms them into private members with getters and setters (if not final). It means if you write the setter, it overrides the default one.


Lombok does the same ;)


But then you're using Lombok...


Can you clarify? I've heard similar negative feelings from devs. What's wrong with lombok?


Huh? Then they're just fields and not properties, maybe I'm misunderstanding what you're trying to say. And there are numerous reasons that Properties are preferable to Fields.

Unless someone else can help me, I think this is really bad advice for a C# developer.


>Huh? Then they're just fields and not properties

Nomenclature schmomenclature.

They're variables with object scope.


might want to checkout lombok. https://projectlombok.org/


Just keep in mind that some of the features are a bit iffy. If you use their vals IntelliJ will syntax highlight it as an error in red for the simple reason that it's non-compliant with the Java language spec. Also, you'll usually need a new version on Lombok every time a new version of Java comes out, otherwise what used to compile with the previous java version will no longer compile. If you use the auto constructor you're going to have fun finding usages since there's nothing to click on, and changing the order of fields in your class will silently change the ordering of parameters in your constructor - double the fun of the fields are of the same type. You'll also be left wondering why you went to all the trouble of adding dodgy language extensions instead of just using a language which provides those features anyway. That and your code (subjectively) looks really ugly plastered with annotations everywhere. Some people like Lombok, just make sure it's a choice you make going in with your eyes open.


We use Lombok heavily where I work, on > 5 projects and have yet to run into any problems like you describe. Everyone use IntelliJ apart from myself and haven't heard any issues with using 'val'. We started off just using it in tests but it's now spread throughout the code base, I can't imagine going back to pre Java 8 sans Lombok.


> If you use their vals IntelliJ will syntax highlight it as an error in red for the simple reason that it's non-compliant with the Java language spec.

There's a free plugin that adds Lombok support to Intellij. You will be able to use getters/setters/builders etc. as if they were compiled.


Builders etc. work fine, it's the vals that are permanently underlined in red, even with the plug in. It compiles OK with vals, but still highlights it as an error in red in the editor.


True. I've seen multiple teams putting a lot of effort into removing Lombok from their codebases after all the trouble it caused.


Lombok's val is the only thing I don't use in the Lombok library.


Isn't that just a boilerplate generator? I think the point is to have sane defaults and shorthand for common tasks so boilerplate generation isn't needed.


If I'm not mistaken, Lombok generates the boilerplate at the bytecode level, not at the source code level. Which makes it much more like a language feature, and while I haven't used it extensively seems like a decent library solution to what is normally considered a language problem.


I just stumbled on this today (before coming here), looks really nice to rid some boilerplate. Regardless for some reason I still love Java...


Some of those missing features are being worked on for Java 10 and can be tested already from the early prototype that is available.

JVMLS 2015:

https://www.youtube.com/playlist?list=PLX8CzqL3ArzUo2dtMurvp...

Technical Keynote at JavaOne 2015

https://www.oracle.com/javaone/on-demand/index.html

Of course, first we still need to get Java 9.

And then when Java 10 with value types, reiffed generics, new FFI API, long Arrays is available, one can write blog posts about being forced to use Java 7 with these missing features on Android.


> The issue of primitive specialisation of generics is only tangentially related to type erasure, and run-time visible generics are actually much less useful than Java folk wisdom insists.

Run-time visible generics are pretty important because it lets us avoid boxing everything. In .NET, they don't have this problem, and as a result primitive dictionaries are ~17x faster [0]. Java folk wisdom seems pretty accurate to me in this case.

[0] - http://fsharpnews.blogspot.com/2010/05/java-vs-f.html


He's talking about reification versus specialization. The .NET runtime is specializing generics for value types and that's how you avoid boxing. For normal classes though, specialization would not have any benefit and the boxing argument goes away.

Interestingly, specialization can be done at compile-time and doesn't necessarily have to be a runtime feature. Here's a Scala compiler plugin doing that: http://scala-miniboxing.org/


> He's talking about reification versus specialization.

It's neither according to the usual (C++-inherited) lingo where specialisation is the userland override of generics reification. Refinement may be a better term for what the article is talking about (runtime-optimised instances without reified types).

And refinements should already be doable in java today with no static type information, Pypy does it with list strategies, I expect Objective-C's hidden classes could also enable it (though I'm not aware of such a use).

> Interestingly, specialization can be done at compile-time

That's where they started...


Did you read any of the comments? I did and I am certainly not qualified enough to know if the 17x faster claim holds up at all.


I did now, and the only relevant retort I saw to this specific claim was that it is possible to work around it by using cern.colt.map.OpenIntDoubleHashMap (third party) instead of java.util.HashMap. So someone has worked around the problem by creating an implementation for a specific value type, but as the author explains, that comes with a big loss of genericity compared to the .NET solution.


The author of the article seems to be essentially looking for Kotlin (except for the structural typing part, which is a terrible idea and which Kotin thankfully ignored).


Structural typing is actually very useful when you need it occasionally, which is one of the reasons I've largely ignored Kotlin so far. The jury is still out on that one.


Ok weird, as a scala programmer these aren't the main pain points when I go to a less powerful language. I miss monadic comprehension, implicit parameters/higher kinded types (for type classes) and inference the most.


Moving from C# to Java 3 years ago was a painful experience in language expression.

However, IntelliJ, Java8 Streams, and Google Guava made the process tolerable.

I've grown to begrudgingly tolerate the weak Generics support, but the one thing absolutely still drives me insane is that I cannot have a method overload for a different generic parameter

i.e.

    public void do(List<ABC> abcs);

    public void do(List<DEF> defs);

FFS Java, come on. (Yes, I know, type erasure, it's still humiliating)


>For example, it was only with C++14 that lambda expressions finally arrived.

nope.


I've been bitten by the "Long indices for arrays" lack once before. But then again, I had no reason for storing a String of length greater than MAX_INT in memory in the first place. Streaming it was the better approach in my case.

Honest question: is there ever an acceptable case for having such a long String in memory?


So would this affect all flat memory allocation? Say if you wanted to allocate 100GB for a bloom filter, would you need to break it into chunks?


Yes, you'd need 6 arrays of 2147483648 longs (max int), plus one array of 536870912 longs, so a total of 7 arrays. Not that bad really.


Yes, I have code like that and its annoying and bug prone. Even if its a write one exercise :( Would be nice if could just avoid that exercise in bit shifting and anding.


Maybe some large data structure in memory based on a flat array and indices underneath?


Some of these, like reified generics, would be great, and it's sad it's too late to add them to the JVM. Some of these, like more expressive imports, seem pretty pointless given that we use IDE's. But some of these are quite un-Javaish.

Structural typing would really go against the grain of the language, and i have a very hard time believing it would actually be useful. What method name is currently widely used with the same semantics across many classes, without being specified by an interface or base class? I can't think of one. There used to be close(), but that's been dealt with. Are there others?

Collection literals seem like a poor idea when there are so many different collection implementations. If i say:

  List<Integer> list = {1, 2, 3};
What kind of list do i get? ArrayList, as that's the usual go-to? A foot-shooting opportunity for anyone doing concurrent programming! And a frustrating missed chance for anyone with a functional bent who would prefer an immutable list. Moreover, it seems unnecessary when you could easily just add constructors or factory methods like:

  List<Integer> list = new ArrayList(1, 2, 3);
  List<Integer> list = ArrayList.of(1, 2, 3);
Which leave the choice in the hands of the programmer for only a minimum of extra syntax.

Maps are a bit harder, because you need a way to describe pairs. In most projects i work on, i end up creating some helper methods that let me write:

  Map<String, Boolean> map = map(entry("Java", true), entry("Go", false));
And i wish there was a better syntax for that.

Something like algebraic data types would be good, though. You can already implement un-extendable classes using mild hacks:

    public abstract class Shape {
    
        private Shape() {}
    
        public static class Circle {
            public static Circle of(int radius) {
                return new Circle(radius);
            }
    
            public final int radius;
    
            private Circle(int radius) {
                this.radius = radius;
            }
        }
    
        public static class Rectangle {
            public static Rectangle of(int width, int height) {
                return new Rectangle(width, height);
            }
    
            public final int width, height;
    
            private Rectangle(int width, int height) {
                this.width = width;
                this.height = height;
            }
        }
    
    }
Because the constructors are all private, so putative subclass can't call them. But you don't get pattern matching, and of course it's all rather verbose.

There are various madmen out on the edge of town trying to create terse approaches to this by meddling with forces beyond mortal knowledge:

https://github.com/poetix/mtuples

But i can't see that going mainstream.


The visitor pattern essentially gives you pattern matching for your example. It can even give you destructuring pattern matching, if you wish. With a fixed hierarchy, each visit method handles one concrete case, and its signature can destructure fields and pass them individually. It's a hoop to jump through but not so bad.


Very true, but you have to write it all by hand, so it's the usual tedious and error-prone boilerplate until IDEs learn to autogenerate it. It would be nice to have an automatic solution like you get with real ADTs.


FYI Guava gives you those constructors, the map is:

ImmutableMap.of(Key, Value, Key, Value...);

For ones with more than 4 values you will need:

ImmutableMap<String, Integer> WORD_TO_INT = new ImmutableMap.Builder<String, Integer>() .put("one", 1) .put("two", 2) .put("three", 3) .build();


Yes, that's the most orthodox Java solution to this.

It's not hard to do slightly better (IMHO!), though:

 	public class MapBuilder<K, V> {
		public static <K, V> MapBuilder<K, V> with(K key, V value) {
			return new MapBuilder<K, V>().and(key, value);
		}

		private List<Map.Entry<K, V>> entries = new ArrayList<>();
	
		public MapBuilder<K, V> and(K key, V value) {
			entries.add(new AbstractMap.SimpleEntry<>(key, value));
			return this;
		}
	
		public Map<K, V> build(Map<K, V> map) {
			for (Map.Entry<K, V> entry : entries) {
				map.put(entry.getKey(), entry.getValue());
			}
			return map;
		}
	
		public Map<K, V> build(Supplier<Map<K, V>> mapSupplier) {
			return build(mapSupplier.get());
		}
	}
Which lets you write:

 	Map<String, Boolean> map = with("Java", true).and("Go", false).build(new HashMap<String, Boolean>());
	Map<String, Boolean> map2 = with("Java", true).and("Go", false).build(Map::new);
I don't have Java 8 on the machine i'm on right now, so apologies if the second example doesn't compile; it might need more manifest types on it.


Things that would be good to add in Java are:

- Collection and map literal.

- Value type.

- Multiple return values.

- Destructure.

- Pattern matching.


that multiple return values got me interested. I can see this exploding complexity/unreadability of the code at first glance.

honest question - what would be real added value compared to dedicated wrapper type holding all you need for return?


1. Not having to declare a pointless wrapper class.

2. Tuples support pattern matching.

3. For simple cases the return type is clearer, no need to dig up another class declartion to figure out what the field types are.


It actually makes the code concise and clearer. e.g.

  (int, float, float) calcPosition(...) {
       ...
       return (type, x, y);
  }

  var (type, x, y) = calcPosition(...);
  if (type)
     move(x, y);
or

  var (int type, float x, float y) = calcPosition(...);
I would prefer the first case with automatic type inference.


I would like to see support for json and regex, similar to JavaScript.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: