What are the things that Java (the language and platform) got categorically right? In other words, what things are more recent programming languages preserving and carrying forward?
Some easy answer are: garbage collection, a VM, lack of pointers, classloaders, reflection(?)
What about language based answers?
Please don't list the things Java did wrong [1], just right.
(note by Mark Harrison) This is an interesting and useful question, especially for those of us who don't use java regularly. I'm voting for reopening. Please don't close as argumentative, as it doesn't seem to be causing any arguments.
1. A continuity of syntax with a previously popular language. Even when Java was written, there were many technically better languages out there. Yet Java offered a syntax which was familiar enough to existing coders that they weren't frightened by it.
2. An understanding of what business code needs, and an API to address it. Java -- at least at one time -- managed to stay one step ahead of the curve of business needs. As implementation of Java applications became more complex, the architectural pieces needing to underpin it rolled out in step. Key examples here are JMS, Javamail, java.util.concurrent.
3. A consistent and supportive approach to open source and community dialog. This is where C# falls down and Java still consistently exceeds. Whereas MSFT has had a schizoid approach to people extending their language ( case in point [1]), Java has consistently been more than supportive of community discussion and language extension.
4. A full-featured, reliable, consistent standard library. Unlike some other popular languages [2], if you see something in the Java core API, it's going to work pretty well. It may not be a perfect implementation, but it's a good enough implementation that it's not worth reworking. And the standard library is HUGE and consistently growing.
5. No need to compile the code for your particular machine. One of my pet peeves of non-VM languages, because having to compile code for my particular machine means I have to pull down your code and figure out how to compile it. Usually this just consists of "./configure; make", but the very fact I have to think about it annoys me: it's much, much nicer to just drop a JAR onto the classpath.
6. The "bean" concept. Yeah, I know this one is kinda weird, but the concept of a "bean" in Java and the associated concept of "properties" is huge for Java's meta-programming capabilities. That concept is so powerful that if it didn't exist, we'd be forced to invent it -- think about tools like Hibernate, libraries like BeanUtils, or language structures like Groovy's GPath. All of these came from the "bean" concept.
7. Garbage collection. Having a non-optional memory management system was undoubtably the best technical innovation of Java. Which is funny, because it was the reason all the C++ coders were certain Java would be unacceptably slow and eventually fail.
8. A solid balance between performance and functionality. Keying off the previous idea, Java has done a good job maintaining a "fast enough" language while keeping it full-featured. With the exception of start-up time, the Sun JVM (with some help from IBM and the wider community) keeps pace or exceeds the other business languages on the market for working with large projects. Things like the garbage collector, HotSpot optimizer, and JIT are good examples of where Sun's Java impl went very, very right. And it's the reason why many languages are flocking over to the JVM.
[1] http://enfranchisedmind.com/blog/posts/testdrivennet-for-visual-studio-express-get-it-while-its-hot/Garbage collection.
I don't think Java would initially have interested me without GC. When it first came on the scene I had been using Scheme and Oberon (both with GC) and a smattering of C and C++ (both without GC). For me GC (and array bounds checking, and pointer safety, ...) was a clear win.
Apart from the technical and the language related features, one of the most important things that Java (and Sun) got right was the evolution of a vibrant and active community around which the language grew and continues to grow.
Documentation!
The existence of excellent apis is great; the existence of documented excellent apis is awesome (especially when this requires little extra work).
All Strings are Unicode. I can't believe how painful character encoding issues still are in many languages/technologies. Java is the first language I came across where Unicode is a first-class citizen. Finally!
I find the Java "ecosystem" very rich: plenty of open source projects, tons of libraries, good information on the web, and the documentation for the standard API is an excellent resource.
Backward compatibility between versions.
Package and class naming conventions that follow the directory layout.
marketing!
it is a nice language, and your boss lets you use it!
Checking bounds of all array accesses and validity of all casts.
Nobody seems to have mentioned Enumerations. They've done quite a nice job on those.
Garbage collection - I use C++ and know the pain of releasing the memory myself
Clear distinction between interfaces and classes - Clearly separates two different concepts
I would say that its support for runtime class loading. Despite occasional situations of classpath hell, it is years beyond what we had to suffer with DLLs or with COM. I'm not sure how C# handles this issue, but at least Java does it well on all platforms.
I'm also fairly impressed with Java's portability; it worked better and more efficiently than I expected, with the exception of things like different JDK releases on the Mac which are mostly Apple's fault.
Everything C# took from Java was the part they got right. Everything C# left behind, was the part Java got wrong.
By learning from other languages, the next implementation can fix and improve the previous language.
You can say the same from C++. Whatever Java borrowed was the right thing from java, whatever they put apart, was what C++ got wrong ( from Sun's perspective of course )
EDIT
I have to make a note on my own sentence. When I said "Everything" I mean it in the most subjective sense of the word. In this case it was everything Microsoft felt was wrong about Java. They wanted to implement Java on MS platform, but when they incurred in license violation, they simply took most of the architecture and the main concepts, and created .NET, CLR and C#.
I think this was a very big step. Otherwise all C# developers will still be programming in VB or C++ ( which not necessarily is a bad thing, just not their favorite language I guess )
Java did not carry forward the biggest mistake in 'C' - the size of integer types being platform-dependent. Every chunk of C has three feet of bletch at the start that tries to work out the correct declaration for a 16-bit int.
No multiple inheritance of implementation. It's just too difficult.
Classes in the java.lang package are part of the language, not simply a bolt-on (as they are in C++).
The language weenies were kept away from java in the early days, meaning that java was a small language. Regrettably, now all the lisp programmers who realise that they will never actually earn a living coding lisp want to add "closures" and Bog knows what else.
Having said that - I though generics were a bad idea, too - but now I wouldn't live without 'em.
1.Garbage collection
2.Platform independent
3.Directory and package structure
4.Follows OOPS
For some projects I still had my doubts a few years ago because of the license Java was under, but now under the GPL it's unstoppable.
A syntax that was based on C/C++.
They may not be the perfectly designed languages, but I think it really helped javas popularity since it is easy for old C/C++ coders to get started.
I can't believe no-one else has mentioned:
But then also...
A good fast implementation of a virtual machine + interoperability with other languages that produce compatible bytecodes (Groovy, Jython, JRuby, etc).
Java re-popularised the practice of process virtualisation using virtual machines. I say RE-popularised because this damage-containment mechanism has been the norm on mainframes for thirty years. Use of VMs also solves DLL hell because the process can load whatever it needs in the privacy of its VM without conflicting with the incompatible needs of other processes.
Recently I have suffered DLL hell with Silverlight, which is based on .NET4, however this was with the frameworks, not the software running within them.
I think doing away with pointers.
Now I know pointers are useful for many things, but if you really need them, then it's easy enough to just use another language.
Its almost impossible to write a non-trivial c++ program without a whole lot of *'s and &'s all over the place.
A simple build and package management system. Packages enforce consistent directory structure and avoid name collisions. javac
and jar
make building Java code dead-simple (heck, I don't even use Ant, since I'm already familiar with GNU Make - I just use the Java toolchain from a Makefile and it still works great). jar
uses a common file-format (zip file) and plain-text indexing information, making it very easy to inspect a Java JAR with existing utilities. It's easy to distribute a single JAR file to someone that includes all of the sources, so distribution is a breeze as well.
Compare that to C and C++ projects - there are so many ways that people build software (scons? cmake? autotools?), and everyone has their own favorite directory structure. Distribution is usually source-only, and tends to require a lot of extra packages available on the destination system due to the arbitrary build systems.
On JVM side: Memory Model (JMM) - soon it'll be essential for every language/runtime. Only having standard memory model you can write efficient portable concurrent code.
I like the concept of try - finally
blocks, even if the syntax to absolutely definitely do some cleanup in all situations without swallowing exceptions is ridiculously clunky (closures would hopefully go a long way to redeeming this).
Also, as noted above, the java.util.concurrent library is excellent. Concurrent programming is hard to get right from a developer's point of view, but I have found that the tools let me do what I need once I know what that is (and you can often get some elegant code out of it, which in my book must be worth something).
Finally - this is probably controversial, but I do like generics. Vastly better than instanceof
check and casting in 1.4, and compile time checking is excellent. Once you get a hang of the couple of gotchas, it's a pretty powerful way to communicate your intentions to the compiler and have them asserted.
I think that finding a way to make a language that high level in general that also has decent performance is quite an achievement. Though technically it's a property of the implementation, not the language, I'd say JIT compilation.
Static exception checking is the feature that I miss the most in other languages. It makes me a lot more confident that the code will not blow up if something unforeseen happens.
The API is something that is unmatched in my opinion. The fact that it tells you (because the language makes you define...) which Exceptions are thrown and things like that. It really makes development easier.
Also, the libraries are open source.
Edit: I just read the explanation of why forced Exception handling wasn't implemented in C# and I still think that I like them to be forced.
Ease of debugging!!
Checked exceptions: because they force me to write more-exception-safe code.
Javadoc.
Ease of modularizing code (JARs).
Garbage collection.
Unicode support. At least, they got it a damn sight better than anyone else had in 1995.
Competition
Being both open source and allowed in almost all large corporate environments is no small feat.
wide acceptance, huge and active community and open source frameworks for almost every possible thing
Dynamic dispatch, aka virtual functions, are the default.
This is one of the key pieces to implementing polymorphism in an object-oriented language. And if you're used to duck-typed languages like Python, you might not believe that a language claiming to be OO could get away without it. But C++ did: it will dispatch based on the static type of the variable, unless the method is explicitly marked as virtual (and yes, I understand the reasons for that choice).
Good harmony with IDE tools such as Eclipse, NetBeans, or IntelliJ.
The most important thing after GC is reflection. It isn't new, but sould be everywhere from now on.