It's quite a paradox; Java is really fast if you keep allocations down, but Java "best practices" often involve tons of object creation.
It can also be quite hard to find out if your code will be fast or not because there are a whole bunch of rules to determine if and when your Java code will be compiled to machine code or executed through JIT. Not having a way to find out if the compiler is smart enough to cache certain values or optimize some boilerplate code away like you can with native compilers is quite annoying sometimes.
Java is really fast if you do plenty of allocations as well, it is cheaper to allocate on the JVM than most malloc implementations. Also, you are probably better served by writing “idiomatic” code, and only try to optimize allocation pattern if that part of the code turned up in the profiler.
It would be different. A large number of real world applications aren't especially performance sensitive and it makes sense to have tools that prioritize other things than performance. We also see how languages that do prioritize performance can suffer in other aspects (C++ is a clear example).
I think that this is fundamental in some way. Consider arithmetic. Fixed with integers suck from an ergonomics perspective. But variable-size integers are necessarily slower. Even designing something as basic as how arithmetic will work in your language forces you to consider performance against usability.
I'm gonna bet that vast majority of enterprise Java apps aren't so sensitive to performance. What they have is tons of business-specific logic leading to different code paths.
Accumulated business logic can be quite a heavy beast, as I learned in experience, but hundreds of `if`-s can rarely be significantly optimized with clever algos.
You only need to take care of object allocation count for hot paths. You can still use java "best practices" for everything around that (if they are what you want)
Interestingly this is an area where Java shows its Lisp roots. Avoiding “consing” (allocation to the heap) is a key technique for writing high performance code.
This is where using a profiler like YourKit or Flight Recorder is your friend. It will show you the objects that can't be optimised away and where code bottlenecks are. It's hard to determine this in advance for Java.
It can also be quite hard to find out if your code will be fast or not because there are a whole bunch of rules to determine if and when your Java code will be compiled to machine code or executed through JIT. Not having a way to find out if the compiler is smart enough to cache certain values or optimize some boilerplate code away like you can with native compilers is quite annoying sometimes.