Hacker News new | past | comments | ask | show | jobs | submit login

There are a few things, mostly due to the runtimes but also because the JVM bytecode assumption has real implications for system behavior.

Let's start with bytecode. It "requires" (except for AOT work) a warm-up / JIT phase that tends towards slower start times. This isn't hard and fast, but in practice it's true. (And when you search for "jvm startup", you end up at lots of pages about how to tune things to try to make this better). For some people, just as bad or even worse (remember, distributed system) is the impact that JIT-compilation and warm-up has on tail latencies. The static nature of most compiled languages mean this isn't a thing you worry about. You've got enough tail latency problems in your life, you don't need "oh hey, I just saw this loop for the Nth time, I took 10ms to hot compile it!".

That leads into the runtime and some of the language choices around it. Java GCs are generally fighting a harder problem than Go's GC, and with a very different tuning point. Java making everything an object and support classloading and so on, has real knock-on effects for the amount of work required to get high-quality, low-pause GC to work. This is much better today than it was in 2008 when the Go team started, but it's still the case that Go has an out-of-the-box better GC experience. Yes there exist special, tuned GCs (e.g., Azul's C4, Shenandoah) but Java GCs have to really be super clever compared to the fairly simple strategies that work in Go; I applaud the ingenuity in Java GC work, but if what you care about is "reasonably good at collecting memory, never pauses for long", the Go language decisions made the GC problem easier.

I think it's fair to ask "Shouldn't Google have just improved Java?", but I think you miss out on lots of the concurrency ergonomics. Again, this has to be compared to a decade ago. Especially post 2010 (Oracle acquisition) it was super unclear that you'd want to attempt to "bet on Java".

To be clear, I do think Go is at the wrong point on the language/type-system sophistication curve for my tastes. That said, I find myself shaking my head at most Java code, while looking at the Go code and thinking "sigh, lots of repetition. I hope one day that gets better, but at least it's obvious".




> Yes there exist special, tuned GCs (e.g., Azul's C4, Shenandoah) but Java GCs have to really be super clever compared to the fairly simple strategies that work in Go;

It doesn't matter at the end, when those GCs work. There's also ZGC by the way, which has been consistently improving release over release, with sub ms pauses in the latest release for TB sized heaps, something that golang's gc cannot match.

> I applaud the ingenuity in Java GC work, but if what you care about is "reasonably good at collecting memory, never pauses for long", the Go language decisions made the GC problem easier.

Now if you want to have high throughput and willing to sacrifice some latency, Java's GC selection allows you to do that. Where as in golang you're stuck with the single gc implementation and have to resort to finicky code changes.


I have barely touched Go, but, from what I've seen, I think I might be able to add a couple more to that:

Java is more intimidating to get in to. It starts with "Oh dear, which JDK do I use?", proceeds to, "Oh dear, now I have to pick a build tool and every single one has a near-vertical learning curve by modern standards." Then you're on to, "I want to do X. Why are there 28 competing libraries for X, and why are the most popular ones invariably the most hated?" And so on.

There's a strong case to be made that procedural is a better paradigm than object-oriented for a lot of the niche that Go targets.

You mentioned concurrency ergonomics, but I just wanted to emphasize that I doubt that Java's concurrency story can ever be a match for Go's. There's too much legacy baggage that can never be unloaded.


While I think it is overstated how hard it is to choose a JDK (pretty much just get the first OpenJDK release you see, which is packaged everywhere), I do see the advantage of a default build tool. Though for beginner use cases both maven and gradle is just a copy-pastable few lines and you are ready to .. java (sorry for the joke).

I don’t really agree about the 28 competing library thing though. First of all, Java has a really good standard library. Sure, it shows its age at some places but it’s not like you have to grab a new dependency for everything, I pretty much only grab deps for very specialized tasks, and in case of Java I now there will always be a match. The only difference in go here is that a bit more network-related code is in the standard library than in java, but that’s hardly that big of an advantage.

Regarding concurrency: the most unique feature of go is unarguably go routines, but the language has an otherwise quite dumb concurrency model hindering its usefulness. Sure, locking should not be the primary mechanism here, but it is painfully bad with defer being function scoped, not block scoped — while java has synchronized blocks since forever. And with the already mentioned coming of Loom, the JVM platform will again rise to the top with regards to concurrency.


> it is overstated how hard it is to choose a JDK

It's not hard to choose if you know Java well, but this sort of thing is a huge barrier to entry for someone who is just getting into it, or trying to decide what platform to use.

The community doesn't help here. If you go Googling to try to figure it out, you'll find a mess of conflicting advice being argued with varying levels of passion. By definition, a newcomer doesn't have enough background knowledge to make their own decision, and they aren't necessarily in a position to know whether or not they really need to wade through all that dreck before deciding.

re: frameworks, it's a similar story. Java has a pretty big standard library compared to a lot of smaller programming languages, but it's really not much different here from other platforms that punch in its same weight class, and I believe that includes golang. But the standard library is background noise; if Go's on the table then I've clearly got a job to do, and that job is probably something like writing Web services. And 28 is probably an undercount of the number of Java service and microservice frameworks out there. With a lot of vigorous discussion among proponents of each. It's got to be just stupidly intimidating to face down when you're first getting started. By contrast, I wouldn't be surprised if, by choosing Go, one could have the whole job done in less time than it would take to compile a list of all the information it seems like you have to read before you can even dip a toe into Java.

Disclaimer, I don't think this translates into "Go is good, Java is bad." Personally, I would absolutely pick Java if it were a project I were getting paid to do. For several reasons, but mostly because I already know Java quite well and I know it can get the job done. And I suspect that Java has more general-purpose value than Golang does. But I don't think "Is Java a good platform?" was really the question. It was, "Why might someone choose Go over Java?" and that's a very peculiar question; one that I think you can only answer in an interesting way if you put yourself in the shoes of someone for whom it's a real decision to make - most likely someone who isn't too familiar with either.


> but I just wanted to emphasize that I doubt that Java's concurrency story can ever be a match for Go's

Project Loom is already targeted for preview for JDK19. Not only does it match golang's concurrency story, it is superior to it.


It's technically very impressive and I'm looking forward to it.

But my point around ergonomics still stands. There will still always be all the legacy stuff, and there's not necessarily any way around having to understand how that works, too, because there's generally going to be some pre-existing library or legacy code or whatever that forces you to.


The whole point of Loom is to keep using legacy (blocking) calls, and the JVM will automatically take care of things for you.

> and there's not necessarily any way around having to understand how that works

Same with golang, you have to understand how things work. The entire narrative that golang is "simple" is just not true. The moment things start to go wrong, you're going to have to understand how things are working behind the scenes.


> Let's start with bytecode. It "requires" (except for AOT work) a warm-up / JIT phase that tends towards slower start times

This is true, but relatively easily solved by AOT compilation which has been tried 2 decades ago as well as now and many times in-between. With a closed-world assumption done by Graal it is not a hard thing to do.

Re: GC

What language decisions do you mean? Other than having value types and some form of pointers, I really don’t see that much of a win. Sure, in some basic networking case allocating on the stack manually almost everything may be possible, but my experience shows that general purpose programs simply live or die by heap allocations and you can’t generally avoid them. And here the complex, but state of the art GCs of Java demonstratedly win big times, and this is the reason why the performance advantages of Go are not so pronounced or even existing for more complex use-cases.

But I will give you that the Oracle acquisition is indeed a good point - though it fortunately turned out to be a good thing for the Java ecosystem in hindsight.

Do you mean complex reflection-heavy java code or even simple explicit one? Because while I agree the latter is not the most common one in some areas, I find it to be surprisingly readable and simple, while still being expressive enough when needed.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: