Four features from Java which are really cool.
Posted on September 2, 2010 by William Woody
There are, in my opinion, four basic language features in Java which make the language extremely cool–in that they allow IDE developers and software developers to quickly and easily deploy tools which make working with Java very easy.
I wanted to point out these features in the hope that future languages (or future extensions to other existing languages such as C++ or Objective C) could incorporate these features, in order to make those language ecosystems better overall.
Now there are a lot of things that are cool about Java. The standard RTL, so there is a standard way to create multiple threads, do file I/O, networking or other similar things is quite cool. (I'm used to the days of early versions of Pascal or C where it was anybody's guess how to do these things.) But in my estimation the following four features have made the overall Java ecosystem quite friendly compared to other languages.
1. Reflection.
Java's reflection system is quite complete, allowing full introspection for any given object of the class of that object, the interfaces it implements, the base class it extends, the methods it implements and the fields that are contained in that class. With methods you can introspect the parameters and the return values. You can even dynamically, using the reflection system, construct objects on the fly and invoke methods on the fly.
Java's reflection system is far more powerful than similar systems in Objective C (which, by design, cannot really allow introspection of the methods implemented by a class, since methods are just messages and there is no strong association of implemented messages), or in C++ (which really only allows you to discover the class of an object, and that's it.)
Later versions of Java even provide an annotation mechanism by which classes can be annotated or marked with special flags, so during introspection different classes can be handled in different ways.
This level of reflection allows one to construct a complete dynamic serialization library, serializing and deserializing objects without ever needing the object to know what is being done to it.
And because the reflection information is contained (as a first class, well documented data structures) inside a compiled .class file, it is not all that difficult to compile a Java file, then introspect the .class file and provide information about that class. By using this it is possible for an IDE to automatically determine, for example, which methods in an abstract class need to be implemented by a child class, and automatically write the missing method calls for you. I suspect in fact this is how the Eclipse functions to create a new class, populating the methods that need to be implemented, is performed.
I use that all the time.
2. Proxying.
Java also has the ability to, given an interface class declaration, create a proxy class which provides an implementation of that interface, redirecting the method calls to another object.
Proxying is a very powerful mechanism which allows remote procedure calls to be implemented with just a few lines of code. Proxying also allows other very powerful techniques to be implemented, such as using interface methods to define the constant values in a property file, and automatically associate variables in a dynamically loaded configuration file.
While proxying is a bit of a one-trick horse, it provides a tremendous amount of power that, combined with reflection, allows you to do RPC without having to create a RMI language specification and compiler to build the client and server components. You can infer the parameters with reflection and redirect with proxying.
3. Exception Stack Introspection.
Of course most languages have exceptions. What makes Java really cool is the ability to dump the function call stack when an exception is thrown. This is an extremely powerful mechanism because it allows you to know precisely what was thrown and where it was thrown from. And most of the time, knowing what happened and where gives you a huge clue as to why something went wrong.
In fact, I'd say the biggest mistake I've ever seen a Java programmer make is to re-throw an exception without setting the cause parameter of the re-thrown exception. For example, I've seen the following:
// A whole bunch of complicated crap with calls
// into thousands of lines of error-prone methods.
catch (Exception someException) {
throw new StandardException("All hell broke loose.");
Then I see the following:
com.chaosinmotion.mything.StandardException: All hell broke loose.
at com.chaosinmotion.mything.Test.doSomething(Test.java:19)
at com.chaosinmotion.mything.Test.main(Test.java:32)
And I want to murder the developer who couldn't be bothered to add an 'initCause' call to the rethrown exception.
4. Inner classes and anonymous classes
To me, these both have the same net effect: they give the developer the ability to define a class inside another class, which has access to the parameters of the outer class, which can then be used as a form of closure. And closures are cool because they allow a callback function or method invocation to have access to the immediate lexical environment where the functioning requiring the closure to be invoked.
For example, suppose we have a method call that takes an interface, where the method in that interface is called for each list of objects in a system:
private interface Callback
void object(Collection l);
private void getAllObjects(Callback callback)
We can gather up all of the objects in a single list using an anonymous inner class in a function call:
private List gatherAll()
final ArrayList n = new ArrayList();
getAllObjects(new Callback() {
public void object(Collection l)
n.addAll(l);
While Java's implementation of anonymous functions may not meet the strict criteria of closures, in that you do not get full read/write access to all the stack variables within the function where the anonymous class is declared (thanks to the Funarg Problem), read-only access to mutable objects gets us close enough that it doesn't really make much difference.
Closure-like functionality is such a cool language feature that Apple added it to the latest version of Objective C. Something like the above could be done by declaring a method -getAllObjects: which takes a block–a reference to a function with closure:
- (void)getAllObjects:(void (^)(NSArray *))callback;
Then calling it with a block that accumulates the results:
- (NSMutableArray *)gatherAll
NSMutableArray *n = [[[NSMutableArray alloc] init] autorelease];
[self gatherAllObjects: ^(NSArray *param) {
[n addObjectsFromArray:param];
The reason for me picking these four features is simple: I believe if other languages were extended to provide these features, then it would not only make the languages themselves more useful, but if they were provided, they would also allow the ecosystem of IDEs and compilers to become more useful as well. Reflection is extremely important to the ecosystem of IDEs: by being able to parse some sort of data structure during development that gives full inspection of the various components of a class or collection of function calls, it would make automatic code generation far easier to create. Better yet, if compilers for a given language could standardize on an intermediate "story of your compile" like structure that also gives line numbers for compiled objects (as is provided in Java class files with debugging turned on), it would make it extremely easy to automatically generate code on the fly during development.
And every language has an undue amount of bookkeeping stuff that needs to be written which make those languages cumbersome to use. C++, for example, requires all methods to be described in two separate places: once in the header file, and again with the method code. Imagine an IDE which could automatically generate the code declarations based on the header declarations, leaving you to only fill in the blanks. Or an IDE which could automatically add the required methods from the abstract class method declarations in an abstract C++ class.
This entry was posted in Java by William Woody. Bookmark the permalink.