Java is designed to be simple and easy to learn. This was achieved by not including some useful features. Clearly a decision was made to hide some problems rather than to give people the means to solve them.
I learned C++ after I learned Java. C++ does not have these problems, but its very completeness make it more daunting. I still believe that Java is a good way to learn Object Orientated programming, but that people will quickly become frustrated by the limitations.
Casts are checked at run time. Therefore a system design can only be checked by run-time testing See No generic programming.
This is problematic
This means that design problems may not be seen until too late, and they may not show the big picture.
This is not enough
If there are an almost infinite number of paths through the code - for instance, a converter, compiler, or virtual machine - then the design flaws may never be seen during testing.
All objects are passed by reference, therefore developers must do a great deal of explicit cloning in order to ensure that object references are not being shared.
Developers must manually clone an object if they want to get a copy of an argument that they can safely change.
Collections (e.g. lists) are collections of object references, so a method that returns a collection needs to manually clone each item in the collection (note that normal collection cloning just creates a copy of the same references). Developers need to trust that methods do this properly although there is no way to tell without looking at the implementation.
Java programmers often believe that there are no pointers in Java, but forget that everything apart from a base type (such as an int) is a reference. It is far too easy to change an object and inadvertently affect some other code that you didn't know was sharing the same object. Also, this type of problem is very difficult to debug - it just looks like random behavior.
Developers do not know whether a method will change the values of its arguments unless they look at the implementation of that method. This type of problem is also difficult to debug because coders rarely expect a method to change its arguments.
There are no collections of particular types of objects - there are just collections of references to Objects. Collections will normally contain references to instances of a particular class or its subclasses, but nothing about a collection's declaration says what it will contain. Developers who take objects from these collections must cast to the expected type, but the compiler is unable to check the validity of the cast until run-time. See Not strongly typed At compile Time.
Again, a developer can only know what a method will do to a collection by looking at the implementation.
It is possible to create your own subclassed containers which are specialized for a particular type, but this leads to a lot of repetitive code, and it is not possible to change the return type of an overridden method.
Java has the following problems:
- A Java compiler can not logically test as much of a program's design as a C++ compiler can.
- Some design problems may not be found, even at run-time, until too late.
- There is not enough separation between interface and implementation.
Java developers could document the behavior of every method but they rarely do, and there is no formal guarantee that the code will comply with the constraints described in its documentation.
Ideally, a design would be perfect from the start, developers would make no errors while implementing it, and all of the code would be completely documented. In the real world, designs are perfected only in the course of development, simple errors are made, and documentation is incomplete. This is the reality, but java does not help us deal with it.
However, java is simpler and more portable, so it is useful for these types of systems:
- Systems whose processes are very repetitive and which can be exhaustively tested. e.g. interactive web-sites.
- Systems with very shallow class hierarchies, with very little interaction between the classes, and very little use of polymorphism.
And Java certainly has advantages over plain C, which also suffers from the problems listed here.
Thinking In Java, Bruce Eckel: Tells you how Java really works.
Copyright © Murray Cumming. Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.