Criticism of Java

From Wikipedia, the free encyclopedia

The Java programming language was intended to serve as a novel way to manage software complexity. Many consider Java technology to deliver reasonably well on this promise. Java is not without flaws, however, and it does not universally accommodate all programming styles, environments, or requirements.

Contents

[edit] Class path

Running a Java program originally required all third-party supporting libraries to be in the class path.

Prior to Java 6 it was necessary for each .jar or .zip archive required to be explicitly named in the class path. Java 6 provides a way around this by allowing directories listed in the class path to end in an asterisk (*), which will be expanded to the names of all files ending in .jar or .JAR within the directory. Such an entry does not however match .zip or .class files within that directory.[1]

[edit] License

See also: Free Java implementations and OpenJDK

Sun Java's proprietary nature gave it a controversial position in the free software community. Because Sun's implementation of Java was not free software, it could not be included in projects that required a free software or GPL-compatible license, such as the OLPC and most Linux distributions.[2][3]

Sun announced in JavaOne 2006 that Java will become open source software. The statement was issued by Sun Software Executive Vice President Rich Green: "It's not a question of whether, it's a question of how, and so we'll go do this."[4]

In July 2006, Sun's CTO Robert Brewin commented that Java would be partially open source by June 2007 but the entire platform would take more time to be fully open source.[5]

On November 13, 2006, Sun announced that its standard edition Java runtime environment would be released under the GPL by March of 2007,[6] and its source code would be available under the GPL. According to Richard Stallman, this would mean an end to the Java trap. Mark Shuttleworth called the initial press announcement "a real milestone for the free software community."[6][7]

Following on their promise, Sun released the complete source code of the Class library under GPL on May 8, 2007, except some limited parts that were licensed by Sun from 3rd parties who did not want their code to be released under an open-source license.[8] Sun's goal is to replace the parts that remain closed with alternative implementations and make the class library completely open.

[edit] Resource management

While Java does manage memory, it does not manage all resources, such as JDBC database connections; these must be released just as memory would need to be in C++.

Java performs garbage collection, so memory management is automatic, with the intention of making allocation errors such as memory leaks less likely.

Conceptually, Java always allocates objects on the heap. Only the compiler may optimize this to faster stack-based allocation. In this respect Java is less flexible than C++, which allows the programmer to control where objects are allocated. In both languages, values of primitives type are allocated on the stack, and the compiler decides how to use the available registers.

While automatic memory management may limit memory leaks, memory is not the only resource that can be leaked. Other resources such as file handles, database and network connections are still prone to leaking, especially when exceptions are thrown. Java somewhat mitigates this by attempting to ensure the execution of "finalization" methods before garbage collection occurs, without, however guaranteeing any particular order of execution between related resources.

[edit] Language choices

[edit] Primitives vs. objects

Java designers decided not to implement certain features present in other languages (including multiple inheritance, operator overloading, and tuples). Java permits multiple inheritance of interfaces but not of implementations.

Java's primitive types are not objects. Primitive types hold their values in the stack rather than being references to values. Because of this, Java is not considered to be a pure object-oriented programming language and this makes reflection more complicated. The motivation for primitive types being non-object oriented was performance considerations. However, as demonstrated in C Sharp it is possible to allow for value types/primitive types to exhibit OO characteristics such as encapsulation, instance methods and interface implementation without compromising performance at all.

Java 5.0 and later supports automatic conversion (autoboxing) of primitive data types to corresponding object form wherever required. This is not without problems, however: 1) Special care must be taken when comparing two boxed primitive types as the boxed instances have identity as reference objects and 2) when autounboxing, a null pointer exception may be thrown. Since this operation occurs implicitly (without a cast or method call), this unchecked exception may not be obvious by inspection of the line of code to an unfamiliar reader. Finally 3) boxed primitives does not allow for operator based arithmetic; either the programmer must ensure an unbox operation, or she must use member methods which does not lend itself to be read as fluently as operator based arithmetic.

[edit] Generics

When generics were added to Java 5.0, there was already a large framework of classes (many of which were already deprecated), so generics were chosen to be implemented using erasure to allow for migration compatibility and re-use of these existing classes. This limited the features that could be provided by this addition as compared to other languages.[9][10]

There is a common misconception that type erasure was nessecary for backwards compatability in the sense that old code could run on a new JVM and new code could call old code. However, this was entirely possible without type erasure (i.e. with reified generics), as has been demonstrated with the addition of generics to the very similar C# programming language. Java 5.0 could have implemented new generic collections classes with reified generics and have those collection classes implement the non-generic collection interfaces such as IList, ISet etc.

Type erasure was only nessecary because of a requirement for a temporary migration compatability; a requirement that the collection classes be the same classes, so that code which did not insulate itself through use of interfaces (thus breaking best practices) could co-exist in the same JVM with new generic style code without the use of wrapping techniques.

Type erasure has several drawbacks:

  • Typecasting overhead when inserting and removing from a collection and when calling any other method of a generic type which takes a parameter of a parameterized type.
  • Inability to use primitive types as type parameters. Because all types must be of reference type and must be "erased" to their upper bounds, it was not possible to allow the use of primitive types. Instead Java 5.0 features autoboxing which "boxes" primitive type on insertion into collections, thus incurring extra overhead and making the code more opaque.
  • What looks like separate classes at development time is really a single class at runtime. Thus static (class-level) members are shared among all classes realized from the generic class.
  • Inability to create new instances or new arrays of types defines through a type parameter.
  • Disparity with arrays which means that in general the developer should never let a method return an array of a parametric type.
  • The type erasure process may produce clashing method signatures.
  • Inability to implement different realizations of the same generic interface.
  • Inability to use generic exceptions

[edit] Non-Virtual methods

Java provides no way to make methods non-virtual (although they can be "sealed" by using the final modifier to disallow overriding). This means that there is no way to let derived classes define a new, unrelated method with the same name. This can be a problem when a base class is designed by a different person, and a new version introduces a method with the same name and signature as some method already present in the derived class. This means that the method in the derived class will implicitly override the method in the base class, even though that was not the intent of the designers of either class. To partially accommodate for these versioning problems, Java 5.0 introduced the @Override annotation, but to preserve backwards compatibility it could not be made compulsory by default.

[edit] Single paradigm

Java is predominantly a single-paradigm language. The addition of static imports in Java 5.0 accommodates the procedural paradigm better than earlier versions of Java. It is expected that the addition of new language features like closures (or lambdas) in version 7 will allow a more functional style (but the language specification has not yet been finalised).

[edit] Exception handling

Java embraced the concept of exception specifications from C++ where they were optional, but made throws clauses mandatory for any checked exception. While this can be a benefit for small systems, there is no universal agreement that using checked exceptions is a benefit for larger systems. In particular, "higher level" code is often not interested in errors thrown by "lower level" code (eg: NamingException). The coder of the naming classes must make a choice: either force higher level code to deal with naming exceptions as checked exceptions, or allow them to "bubble up" through his own low-level code without compile-time checks.

[edit] Closure

Finally, while anonymous inner classes provide a basic form of closures, they are not complete and require referenced variables to either be class fields or declared "final". The rationale behind this is that it allows JVM implementors to choose a stack model for variable lifetimes, so that a variable scope is removed when exited, thus preventing real closures. In addition, when using - for instance - "Runnable" as a closure, one has to declare the "run" method and put the code in that: you cannot simply put some code in braces and pass it around (however the Java 7 language specification is aiming to address this with first class closures).

[edit] Floating point arithmetic

While Java's floating point arithmetic is largely based on IEEE 754 (Standard for Binary Floating-Point Arithmetic), certain features are not supported even when using the strictfp modifier, such as Exception Flags and Directed Roundings — capabilities mandated by IEEE Standard 754. Many so-called "Java gotchas" are not problems with Java per se, but problems that are inevitable whenever using floating point arithmetic.[11][12]

[edit] Look and feel

The look and feel of GUI applications written in Java using the Swing platform may look different from native applications. While programmers can choose to use the AWT toolkit that displays native widgets (and thus look like the operating platform), the AWT toolkit is unable to meet advanced GUI programming needs by wrapping around advanced widgets and not sacrificing portability across the various supported platforms, each of which have vastly different APIs especially for higher-level widgets. If an alternative GUI toolkit is used, such as SWT, it is possible for a Java application to have native look and feel whilst also having access to advanced widgets.

The Swing toolkit--written completely in Java--both creates the problem of having a different look and feel from native applications, and avoids the problem of being limited by native toolkit capabilities because it reimplements widgets using only the most basic drawing mechanisms that are guaranteed available on all platforms. Unfortunately, the default installations of the JRE (as of August 2006) do not use the system's "native" look and feel, instead defaulting to the built-in Metal Look and Feel. If the programmer doesn't take care to set the native look and feel, users will have applications whose appearance is vastly different from that of their native applications. Apple Computer's own optimized version of the Java Runtime, which is included within the Mac OS X distribution, by default does set the default and implements its "Aqua" look-and-feel, giving Swing applications on the Macintosh a similar appearance to native software. Even in this environment, the programmer must still do some extra work to ensure that that application looks like an Aqua one (for example, they must set system properties to ensure the menubar is rendered in the OS X menubar and not in the application window as it would be on other platforms).

[edit] Performance

Further information: Java performance

Java's performance has improved substantially since the early versions, and performance of JIT compilers relative to native compilers has in some tests been shown to be quite similar.[13][14][15] The performance of the compilers does not necessarily indicate the performance of the compiled code; only careful testing can reveal the true performance issues in any system.

In a paper written in 1999 by Lutz Prechelt it is outlined that, statistically, programmer efficiency and experience has a bearing many standard deviations greater on run-time and memory usage than language choice. This paper specifically uses Java as a basis for the comparison, due to its then bad reputation.[16] Sun Microsystems have taken considerable trouble to address these problems, and regularly produce white papers on this topic.[17] A more recent study (2003–4) gives Java a comparable performance to C++.[18]

[edit] General

Java bytecode can either be interpreted at run time by a virtual machine, or it can be compiled at load time or runtime into machine code which runs directly on the computer's hardware. Interpretation is slower than native execution, and compilation at load time or runtime has an initial performance penalty for the compilation.

[edit] Language constraints

There are a few language requirements which incur an unavoidable time penalty, although these features are not unique to Java. Among these are array bounds checking, run-time type checking, and virtual function indirection (although each of these can in some situations be avoided by an optimizing compiler). Also the lack of features can affect performance. For example, Java does not have arrays of structures or a true multi-dimensional array, but only an array of references to objects or further arrays. Nor does Java allow returning more than one value from a function without using an object. The net result is that Java code makes more heap allocations than some other languages.

[edit] Garbage collection

The garbage collector controls when objects are deleted from memory. Java does not allow the programmer to control when garbage collection occurs - it cannot be delayed, or exercised on a particular object. While this makes programming much simpler and reduces memory leaks, it lacks the flexibility that can, in some cases, result in a more efficient handling of memory. The programmer can call the function System.gc() as a hint that this is a suitable time to run the garbage collector, but the JVM is not obliged to honour this suggestion. Lower-level languages provide more flexibility over memory management, and while garbage collection is not part of the language specification and therefore its use is not mandated, in some cases (notably C and C++) a number of third-party garbage collectors are available.

The use of a garbage collector to automatically delete objects can add overhead compared to manual deallocation and can have a positive or negative impact on performance depending upon the garbage collector implementation and the characteristics of the application's use of objects. With the modern generational garbage collectors used in many JVMs, many applications actually experience greater performance because of faster allocation and deallocation algorithms.

Because the garbage collector may run at any time, Java is unsuitable for real time programming. In older JVM implementations, collection paused the program's own threads. The current implementation, using concurrent collection, does not need to pause the program but will typically slow its execution. This is problematic in a real-time environment because making scheduling guarantees is impossible with arbitrary interruptions, and deadlines may be missed while the garbage collector is running.

[edit] Byte code vs. native compilation

Relative performance of JIT compilers as compared to native compilers can be quite close, and is often a subject of debate. The JIT compilation stage may be time consuming, which is inconvenient for applications that are short-lived and/or contain large amounts of code. Once compiled to native code, however, the performance of the program can be comparable to that achieved by a native compiler, even on numerical tasks. Although Java does not support manual inlining of method calls, many JIT compilers perform this optimization at load time and can exploit information from the runtime environment to guide more effective transformations, such as profile-directed inlining. Dynamic recompilation, as provided by Sun's HotSpot JVM, can exceed the performance of the static compilation available in most other languages by exploiting information that is only available at runtime.

[edit] Hardware interfacing

Because Java was designed with an emphasis on security and portability, it does not support direct access to the machine architecture and address space. This means working directly with a specific piece of hardware such as a scanner, digital camera, audio recorder, video capture, or any hardware that requires direct memory space control (typically those pieces or hardware installed with drivers), cannot easily be accomplished with Java. An illustration of this issue is seen in version 1.0 of Java as it was not possible to access a printer because the interface code to the various printer drivers was not included in this first JVM.

[edit] Interfacing with native code

Client side or server systems that need to "talk" to the hardware must implement a hybrid solution using Java and C/C++ or assembly language via the Java Native Interface (JNI) libraries to link native code to the Java libraries. An alternate solution is to code the hardware software component in its native C/C++/assembler language and then pass the data via files, databases or a shared memory interface, although this is not an ideal solution.

Using the JNI technique introduces many possible inconsistencies such as: machine dependency, potential deadlock situations, memory allocation leaks, and possibly poor application performance, not to mention code complexity of needing to maintain two different code bases.

However, other simpler solutions have been developed since JNI. Java Native Access is comparable to .NET P/Invoke, in that no boilerplate C glue code have to be written to be able to access the native library.

[edit] Inconsistent JVM implementations

Java is a bytecode language that runs on top of the JVM; ultimately the compatibility of the language and the ability to have it run across different platforms is dependent on the stability and version of the JVM. While Java is touted as running on a large variety of systems, the most up to date JVM (and JRE) are only those actively updated for Windows, Linux and Solaris. HP (such as Java for HP-UX) and IBM (for MVS, AIX, OS/400) provide their own implementations for their family of platforms but do not always mirror the latest Sun releases. Other JVM implementations usually follow, but sometimes lag in months or years with the more common implementations and therefore introduce compatibility problems.[citation needed]

[edit] See also

[edit] Notes

  1. ^ Setting the class path. Retrieved on 2007-08-22. “Understanding class path wildcards”
  2. ^ Additionally, some commentators assert that Java SCSL license requires that anyone who agrees to the license terms waives their right to contribute to free software clean-room implementations of Java; however Sun spokespeople assert this was no longer an issue under revised Java licensing terms "What full-fledged Java development platforms are available in Debian?". "Debian FAQ". Retrieved on 2006-12-08.
  3. ^ Java SE Tainting Issues. "Java.net: The Source for Java Technology Collaboration. Retrieved on 2006-12-09..
  4. ^ Galli, Peter (2006-05-16). Open-Source Java? Not If but How. eWeek. Retrieved on 2006-12-09.. The point of contention with Sun was how they want to open source Java without facilitating an incompatible fork Phipps, Simon (2006-05-26). Forks Aren't A Problem. Retrieved on 2006-12-09.. This could be illustrated by a post-JavaOne comment from Jonathan Schwartz, Sun's CEO, on his blog: "We're now making serious progress on open sourcing Java (and despite the cynics, using a GPL license is very much on the table), while focusing the debate on what matters most: not access to lines of code (that's already widely available), but ensuring compatibility."Schwartz, Jonathan (2006-06-25). 60 Days into the Job…. Retrieved on 2006-12-09..
  5. ^ Krill, Paul (2006-06-24). Sun CTO: Incremental open-sourcing of Java is the way. Computer World. Retrieved on 2006-12-09.
  6. ^ a b Sun Opens Java. Sun Microsystems (2006-11-13). Retrieved on 2006-12-09.
  7. ^ Sun 'releases' Java to the world. BBC News (2006-11-13). Retrieved on 2006-12-09.
  8. ^ Open JDK is here!. Sun Microsystems (2007-05-08). Retrieved on 2007-05-09.
  9. ^ Generics in Java. Object Computing, Inc.. Retrieved on 2006-12-09.
  10. ^ What's Wrong With Java: Type Erasure (2006-12-06). Retrieved on 2006-12-09.
  11. ^ Kahan, W.; Joseph D. Darcy (1998-03-01). How Java's Floating-Point Hurts Everyone Everywhere (PDF). Retrieved on 2006-12-09.
  12. ^ Types, Values, and Variables. Sun Microsystems. Retrieved on 2006-12-09.
  13. ^ Performance of Java versus C++, J.P.Lewis and Ulrich Neumann, Computer Graphics and Immersive Technology Lab, University of Southern California
  14. ^ The Java is Faster than C++ and C++ Sucks Unbiased Benchmark
  15. ^ FreeTTS - A Performance Case Study, Willie Walker, Paul Lamere, Philip Kwok
  16. ^ Lutz Prechelt. Technical opinion: comparing Java vs. C/C++ efficiency differences to interpersonal differences. Communications of the ACM, Vol 42, #10, 1999
  17. ^ Java SE 6 Performance White Paper.
  18. ^ Benchmarks.

[edit] External links

Languages