I prefer Java's environment compatibility over C#'s.
I prefer Java's execution speed over Python/Ruby.
I abhor Perl's syntax, and would rather use Ruby/Python/Groovy to solve Perl problems.
Java's greatest strength is it's JVM, cheap, reliable, versatile.
C/C++ force me to deal with a class of memory management bugs that I would rather not, even as a seasoned programmer who understands pointers/references/diamond problem/template meta programming/data structures.
Non-type safe languages force me to move things the compiler is doing for me, into a test infrastructure. I'm not removing the compiling phase, just renaming it to unit tests.
Lamda functions/co-routines and no-side effects are interesting, and makes threaded programming easier, but need more exposure to the subject, it's more a hobby then a tool in my belt at this point.
So I come back to JavaLet me ask you, what do you perceive as a "better language", and for what field?
A better language would facilitate more reuse. A better language would have a real type system. A better language wouldn't explicitly discourage unintentional extension points.
In Java, there is no way to reuse code other than by subclassing something. This is the second-worst possible way to reuse code, because you often don't want to reuse code in the form "make me a thing that's oh kind of like that other thing". The best way to reuse code is through composition; either something like interfaces with some implementation in them ("roles"), or by automatic delegation. If I "has a" foo, then I should be able to delegate some subset of foo's methods to myself. This allows me to use some of foo's implementation without requiring foo's API to become my own API. (If foo does some role fooable, then if I delegate the right methods, I also become fooable. Then anything that takes a fooable can now accept me.)
The type system should make this standard. You should never be able to type a variable with a concrete type; only abstract interfaces. This way, extensibility is mandatory rather than a "best practice".
As for type systems, it should be something deeper than "there are some random primitive types, and everything else is a subclass of Object". That's worthless, because null is a subtype of every type, but violates Liskov. This means that I can't ever be sure my code will actually work at runtime. Haskell fixes this with the Maybe type. By making nullability explict, the compiler can check that you handle it where it needs to be handled.
Finally, a better language wouldn't be so uptight about privacy. If you don't want to support some API, don't add it to an interface that you implement. Document that you don't want someone to call it. Most of Java's syntax focuses on access levels: private, default, protected, public, final. Who cares? If I want to reimplement a private method, it's probably because I know what I'm doing. It's the langauge's job to make the programmer's intent clear, not to stop me from violating that programmers's wishes. Larry Wall said it best: "Perl doesn't have an infatuation with enforced privacy. It would prefer that you stayed out of its living room because you weren't invited, not because it has a shotgun."
Anyway, Java makes writing flexible and reusable software very difficult. This is why you see so much brittle and outdated software written in Java. Compare this to Emacs Lisp, which doesn't enforce any privacy ever. Much of Emacs is over 30 years old, and it's still "state of the art". Food for thought.
I worry. Java has checked exceptions. The stated purpose of this feature is to make callers consider explicitly the different exceptions that might arise from what they're calling, and deal with them appropriately.
The end result? There is an endless reserve of lazy people who don't do that. They catch exceptions and throw them out. The feature doesn't work and there are a bunch of no-op (or worse) try blocks everywhere that clutter everything up and handle errors in inappropriate ways. At least, that's my experience working with other people's Java code.
So, suppose you had to deal in interfaces everywhere. The goal of this feature would be that programmers think about how to separate and generalize the potentially-reusable functionality in the code they're writing. Would that actually be the result? I sort of suspect that the actual result would be a million interfaces that have thirty unrelated methods because they were copied-and-pasted from the class that someone made. IFooable would be equally as unreusable as ConcreteFooable ever was.
Basically, I don't think that restrictions like that are effective to stop people from structuring their code awfully. Anyone who understands the concept behind the restriction would have probably written nice, reusable code anyway, and everyone else will just hack around it with trial and error until their program compiles. (It's the same reason I agree with you about having the compiler enforce encapsulation.)
Ultimately, I have no interest in making it easy for bad programmers to program. This is Java's biggest problem -- it claims to help prevent bad code, which people want, but it doesn't actually do that. Its "bad code prevention features" actually have the opposite effect; they makes writing good code an ordeal that requires great patience, skill, and tools.
The major problem with Java is that because code is so difficult to write, people are afraid to delete it. Deleting code is the best possible thing a programmer can do, and Java discourages by causing programmers to value bad code. That's what's terrible about it.
(One big problem I see in the programming field in general is that everyone tries to put their prototypes into production. Then they wonder why their code is hard to maintain and it has a lot of bugs. The answer: you didn't know enough about the problem you were trying to solve when you started, so now you have a mess. Throw it away and start with complete understanding. Then you'll be able to build your application correctly. Call it refactoring if you want to, but the only thing that the prototype was for was to teach you about your problem and how to solve it. Now do it for real.)
I'm glad Java introduced automatic memory management to the average workaday programmer. I'm not glad that one of the better languages hasn't replaced it yet.