Criticism of Java
The Java programming language and Java software platform have been criticized for design choices in the language and platform, including the implementation of generics, forced object-oriented programming, the handling of unsigned numbers, the implementation of floating-point arithmetic, and a history of security vulnerabilities in the primary Java VM implementation, HotSpot. Additionally, software written in Java, especially its early versions, has been criticized for its performance compared to software written in other programming languages. Developers have also remarked that differences in various Java implementations must be taken into account when writing complex Java programs that must be used across these implementations.[1]
Language syntax and semantics
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 type 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.[2][3]
Because generics were implemented using type erasure the actual type of a common template parameter E is unavailable at runtime. Thus, the following operations are not possible in Java:[4]
public class MyClass<E> {
public static void myMethod(Object item) {
if (item instanceof E) { //Compiler error
...
}
E item2 = new E(); //Compiler error
E[] iArray = new E[10]; //Compiler error
}
}
Noun-orientedness
By design, Java encourages programmers to think of a programming solution in terms of nouns (classes) interacting with each other, and to think of verbs (methods) as operations that can be performed on or by that noun.[5] Steve Yegge argues that this causes an unnecessary restriction on language expressiveness because a class can have multiple functions that operate on it, but a function is bound to a class and can never operate on multiple types.[6]
In many other multi-paradigm languages, there is support for functions as a top-level construct. When combined with other language features such as function overloading (one verb, multiple nouns) and/or generic functions (one verb, a family of nouns with certain properties), the programmer is given the ability to decide whether it makes more sense to solve a specific problem in terms of nouns or verbs. Java version 8 introduced some functional programming features.
Hidden relationship between code and hardware
In 2008 the U.S. DOD's Center Software Technology Support published in the "Journal of Defense Software Engineering" an article discussing the unsuitableness of Java as first learned programming language in education. Disadvantages given for Java as first language were that students "had no feeling for the relationship between the source program and what the hardware would actually do" and the impossibility "to develop a sense of the run-time cost of what is written because it is extremely hard to know what any method call will eventually execute".[7] Similarly Joel Spolsky in 2005, criticised Java as overfocused part of universities' curriculum in his essay The Perils of JavaSchools.[8] Others, like Ned Batchelder, disagree with Spolsky for criticizing the parts of the language that he found difficult to understand, claiming that Spolsky's commentary was more of a 'subjective rant'.[9]
Unsigned integer types
Java lacks native unsigned integer types. Unsigned data is often generated from programs written in C, and the lack of these types prevents direct data interchange between C and Java. Unsigned large numbers are also used in a number of numeric processing fields, including cryptography, which can make Java more inconvenient to use for these tasks.[10] Although it is possible to partially circumvent this problem with conversion code and using larger data types, it makes using Java cumbersome for handling unsigned data. While a 32-bit signed integer may be used to hold a 16-bit unsigned value losslessly and a 32-bit unsigned value would require a 64-bit signed integer, a 64-bit unsigned value cannot be stored easily using any integer type because no type larger than 64 bits exists in the Java language. In all cases, the memory consumed may increase by a factor of up to two, and any logic that depends on the rules of two's complement overflow must typically be rewritten. If abstracted using functions, function calls become necessary for many operations which are native to some other languages. Alternatively, it is possible to use Java's signed integers to emulate unsigned integers of the same size, but this requires detailed knowledge of bitwise operations.[11] Some support for unsigned integer types was provided in JDK 8, but not for unsigned bytes and with no support in the Java language.[12]
Operator overloading
Java has been criticized for not supporting the capability of implementing user-defined operators. Operator overloading improves readability,[13] thus the lack of it in Java can make the code less readable, especially for classes representing mathematical objects, such as complex numbers, matrices, etc. The language contains only one non-numerical usage for operators, and that is String concatenation, implemented with the +
operator. However, this is implemented only in the compiler, and compiles to a StringBuilder - it is impossible to create user-defined operator overloads.
Compound value types
Java lacks compound value types, such as structs in C, bundles of data that are manipulated directly instead of indirectly via references. Value types can offer significant performance improvements and memory savings in some cases.[14][15][16] A typical example is Java's HashMap, which is internally implemented as an array of HashMap.Entry objects.[17] Because Java lacks value types, this array is actually an array of references (pointers) to Entry objects, which in turn contains references to key and value objects. Looking up something in the map requires inefficient double indirection. If Entry were a value type, the array could store pairs of key and value references directly, eliminating the first indirection, increasing locality and reducing memory usage and heap fragmentation. If Java further supported generic primitive types, primitive keys and values could be stored in the array directly, removing the second indirection.
Large arrays
Java has been criticized for not supporting arrays of more than 231−1 (about 2.1 billion) elements.[18][19][20] This is a limitation of the language; the Java Language Specification, Section 10.4, states that:
Arrays must be indexed by int values... An attempt to access an array component with a long index value results in a compile-time error.[21]
Supporting large arrays would also require changes to the JVM.[22] This limitation manifests itself in areas such as collections being limited to 2 billion elements[23] and the inability to memory map continuous file segments larger than 2 GB.[24] Java also lacks true multidimensional arrays (contiguously allocated single blocks of memory accessed by a single indirection), which limits performance for scientific and technical computing.[15]
There is no efficient way to initialize arrays in Java. When declaring an array, the JVM compiles it to bytecodes with instructions that set its elements one by one at runtime. Because Java methods cannot be bigger than 64KB, arrays of even modest sizes with values assigned directly in the code will throw the message "Error: code too large" on compilation.[25]
Integration of primitives and arrays
The fact that arrays and primitives are somewhat special and need to be treated differently from (other) objects has been criticized,[26] because it requires writing many variants when creating general libraries.
Parallelism
Per Brinch Hansen argued in 1999[27] that Java's implementation of parallelism in general and monitors in particular do not provide the guarantees and enforcements required for secure and reliable parallel programming. While it is possible for a programmer to establish design and coding conventions to, say, only access thread-global variables in a controlled fashion, the language and compiler make no attempt to enforce that controlled access. I.e. the programmer may mistakenly allow uncontrolled access to thread-global variables, and the compiler will not detect it.
Serialization
Java provides a mechanism, called object serialization where an object can be represented as a sequence of bytes that includes the object's data as well as information about the object's type and the types of data stored in the object. After a serialized object has been written into a file, it can be read from the file and deserialized that is, the type information and bytes that represent the object and its data can be used to recreate the object in memory[28] This poses very serious theoretical and actual security risks.[29][30]
Floating point arithmetic
Although 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. Additionally, the extended precision floating-point types permitted in 754 and present in many processors are not permitted in Java.[31][32][33]
Performance
In the early days of Java (before the HotSpot VM was implemented in Java 1.3 in 2000) there were many criticisms of performance. Java has been demonstrated to run at a speed comparable with optimised native code, and modern JVM implementations are regularly benchmarked as one of the fastest language platforms available—typically within a factor of 3 relative to C and C++.[34]
Java's performance has improved substantially since the early versions.[35] Performance of JIT compilers relative to native compilers has in some optimized tests been shown to be quite similar.[35][36][37]
Java bytecode can either be interpreted at run time by a virtual machine, or it can be compiled at load time or runtime into native 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. Modern performant JVM implementations all use the compilation approach, so after the initial startup time the performance is similar to native code.
Game designer and programmer John D. Carmack concluded in 2005 about Java on cell-phones: "The biggest problem is that Java is really slow. On a pure cpu / memory / display / communications level, most modern cell phones should be considerably better gaming platforms than a Game Boy Advance. With Java, on most phones you are left with about the CPU power of an original 4.77 mhz (sic) IBM PC, and lousy control over everything."[38]
Security
The Java platform provides a security architecture[39] which is designed to allow the user to run untrusted bytecode in a "sandboxed" manner to protect against malicious or poorly written software. This "sandboxing" feature is intended to protect the user by restricting access to certain platform features and APIs which could be exploited by malware, such as accessing the local filesystem, running arbitrary commands, or accessing communication networks.
In 2010, there was a significant increase in the prevalence of malicious software targeting security flaws in the sandboxing mechanism in multiple commonly used Java implementations, including Oracle's. These flaws allow untrusted code to bypass the sandbox restrictions, exposing the user to malicious attacks. Targeted security flaws that have already been fixed by security updates from the JVM maintainers have been exploited in computers without the security updates.[40]
Critics have suggested that updated versions of Java are not used because there is a lack of awareness by many users that Java is installed, there is a general lack of knowledgeability on how to update Java, and (on corporate computers) many companies restrict software installation and are slow to deploy updates.[40][41]
Oracle has been criticised for not providing Java security updates for known security bugs, for long periods of time, despite these security bugs having known exploits.[42] When Oracle finally acted to patch against widely exploited flaws in Java 7, they deleted Java 6 on the users' machines in spite of this being widely used by enterprise applications that Oracle had claimed were not impacted by the flaws.[43]
In 2007, a research team led by Marco Pistoia, exposed another important flaw of the Java security model,[44] which is based on stack inspection. This means that, at the time a security-sensitive resource is about to be accessed, the security manager triggers a stack walk, which verifies that the codebase of each method on the current call stack has been authorized to access the security-sensitive resource. This is done to prevent confused deputy attacks, which take place every time a legitimate, more privileged computer program is tricked by another program into misusing its authority on the system. The confused-deputy problem is a specific type of privilege escalation. The issue with this approach as observed by Marco Pistoia, et al. is that at the moment a security-sensitive resource is accessed, code responsible for the identification of that resource may no longer be on the current stack. For example, a method executed in the past may have modified the value of an object field, which is used to determine the resource being accessed. That method may have already popped out from the stack when the stack inspection takes place. Other limitations of the Java security model is that certain permissions are implicitly equivalent to Java's AllPermission
. These include the permission to change the current security manager (and replace it with one that could potentially bypass the stack inspection), the permission to instantiate and use a custom class loader (which could choose to associate AllPermission
to a malicious class upon loading it), and the permission to create a custom permission (which could potentially declare itself as powerful as AllPermission
via a malicious implementation of its implies
method). These issues are also documented in Marco Pistoia's two books on Java Security: Java 2 Network Security (Second Edition) and Enterprise Java Security.
Multiple parallel Java installations
With Java versions prior to 7, it was normal for the installer not to detect or remove prior Java installations. It was quite common on a Windows computer to see multiple installations of Java 6 on the same computer, varying only by update revision. Multiple Javas are permitted and can be accessed by programs that look for specific versions.
This has the effect that new Java installations only provide new language features and bug fixes, but they do not correct security vulnerabilities, because malicious programs can look for the older prior Java releases and use them rather than the newest versions.
Java 7 updated prior versions of itself, but did not look for the presence of Java 6 and earlier.[45]
No automatic self-update capability
As of 2014, common 3rd party tools (such as Adobe Flash and Adobe Reader) that have been the subject of security vulnerability scrutiny, have moved to an automatic update model on Windows. This model doesn't require any user intervention, and assures that security issues are promptly resolved without requiring additional effort by the system users or administrators.
As of 2015, Java 8 still requires that the computer user manually apply Java updates themselves. These updates can only be applied by those with administrator privileges. The Windows Java updater frequently triggers a disruptive random User Account Control elevation prompt; however, choosing Yes or No for elevation will still yield the same "Java needs to be updated" message.
See also
Notes
- Wong, William (27 May 2002). "Write Once, Debug Everywhere". electronicdesign.com. Archived from the original on 21 March 2009. Retrieved 3 August 2008.
So far, the "write-once, run-everywhere" promise of Java hasn't come true. The bulk of a Java application will migrate between most Java implementations, but taking advantage of a VM-specific feature causes porting problems.
- "Generics in Java". Object Computing, Inc. Archived from the original on 2 January 2007. Retrieved 9 December 2006.
- "What's Wrong With Java: Type Erasure". 6 December 2006. Retrieved 9 December 2006.
- "Type Erasure".
- "Java SE Specifications".
- Yegge, Steve. "Execution in the Kingdom of Nouns".
- Robert B.K. Dewar; Edmond Schonberg (1 January 2008). "Computer Science Education: Where Are the Software Engineers of Tomorrow?". CrossTalk Jan 2008. U.S. DOD Software Technology Support Center. Archived from the original on 12 April 2009. Retrieved 15 March 2015.
The Pitfalls of Java as a First Programming Language [...] Students found it hard to write programs that did not have a graphic interface, had no feeling for the relationship between the source program and what the hardware would actually do, and (most damaging) did not understand the semantics of pointers at all, which made the use of C in systems programming very challenging.
- Joel Spolsky (29 December 2005). "Joel on Software - The Perils of JavaSchools". joelonsoftware. Retrieved 18 November 2015.
It's bad enough that JavaSchools fail to weed out the kids who are never going to be great programmers, which the schools could justifiably say is not their problem. Industry, or, at least, the recruiters-who-use-grep, are surely clamoring for Java to be taught. But JavaSchools also fail to train the brains of kids to be adept, agile, and flexible enough to do good software design
- Ned Batchelder (1 January 2006). "Joel Spolsky is a crotchety old man". nedbatchelder.com. Retrieved 2 February 2016.
Why does Joel pick out pointers and recursion as the two gatekeeper concepts? Because he found them difficult? As Tim Bray points out, Java is perfectly adept at recursion, and concurrency may be a more important and difficult concept to master in any case. The emphasis on recursion in Lisp languages is a bit over the top, and doesn't carry into other programming cultures. Why do people think it's so important for software engineering? Don't get me wrong: I love recursion when it's the right tool for the job, but that is just not that often to warrant Joel's focus on it as a fundamental concept.
While we're hunting around for tough concepts that separate the men from the boys, what about the one that got Joel and I into a tussle two years ago: Exceptions. He doesn't like them, basically, because they confuse him. Is this any different than a Java guy not liking pointers? Yes, you can avoid exceptions and use status returns, but you can also try really hard to avoid pointers. Does that mean you should? So Joel's got the concepts he likes (pointers and recursion), and laments their decline, but doesn't seem to notice that there are newer concepts that he's never caught on to, which the Java kiddies feel at home with. - "Java libraries should provide support for unsigned integer arithmetic". Bug Database, Sun Developer Network. Oracle. Retrieved 18 January 2011.
- Owen, Sean R. (5 November 2009). "Java and unsigned int, unsigned short, unsigned byte, unsigned long, etc. (Or rather, the lack thereof)". Retrieved 9 October 2010.
- "Unsigned Integer Arithmetic API now in JDK 8 (Joseph D. Darcy's Oracle Weblog)". Retrieved 15 May 2016.
- "C++ Operator Overloading". 7 April 2016.
- Java Grande Forum Panel (November 1998). "Java Grande Forum Report: Making Java Work for High-End Computing" (PDF). SC98.
- Moreira, J.E.; S. P. Midkiff; M. Gupta; P. V. Artigas; M. Snir; R. D. Lawrence (2000). "Java programming for high-performance numerical computing". IBM Systems Journal. 39 (1): 21–56. CiteSeerX 10.1.1.13.1554. doi:10.1147/sj.391.0021.
True rectangular multidimensional arrays are the most important data structures for scientific and engineering computing.
- Hutchinson, Ben (14 June 2008). "The JVM needs Value Types". Retrieved 3 February 2012.
- "java.util.HashMap Source Code". JDK 8. zGrepCode. Retrieved 6 August 2018.
- Arndt, Holger; Bundschus, Markus; Naegele, Andreas (2009). "Towards a Next-Generation Matrix Library for Java" (PDF). 2009 33rd Annual IEEE International Computer Software and Applications Conference. pp. 460–467. CiteSeerX 10.1.1.471.7567. doi:10.1109/compsac.2009.67. ISBN 978-0-7695-3726-9.
...it is not possible in Java to have arrays with more than 231 entries...
- "Why does Java's Collection.size() return an int?". Stack Overflow. Archived from the original on 26 March 2013. Retrieved 10 February 2012.
- Carpenter, Bob (28 July 2010). "Big Bit-Packed Array Abstraction (for Java, C, etc.)". LingPipe Blog. Retrieved 10 February 2012.
- James Gosling; Bill Joy; Guy Steele; Gilad Bracha. "The Java Language Specification" (Third ed.). Addison Wesley. Retrieved 6 February 2012.
- Lowden, James. "Proposal: Large arrays (take two)". Java.net coin-dev mailing list. Retrieved 10 February 2012.
- "java.util.Collection". Java™ Platform, Standard Edition 7 API Specification. Retrieved 10 February 2012.
- "java.nio.ByteBuffer". Java™ Platform, Standard Edition 7 API Specification. Retrieved 6 February 2012.
- David Flanagan. Java in a Nutshell. p. 77.
- Sherman R. Alpert (IBM) (1998). "Primitive Types Considered Harmful". Java Report, November, 1998 (Volume 3, Number 11). Retrieved 18 November 2015.
- Brinch Hansen (April 1999). "Java's Insecure Parallelism" (PDF). SIGPLAN. Retrieved 13 October 2012.; alternate url
- Serialization and Deserialization in Java with Example by geeksforgeeks website
- Serialization Must Die Security issues and problems with serialization of random objects. by dzone.com
- Bloch, Joshua (2018). Effective Java. Addison-Wesley. pp. 339–345. ISBN 978-0-13-468599-1.
- Kahan, W.; Joseph D. Darcy (1 March 1998). "How Java's Floating-Point Hurts Everyone Everywhere" (PDF). Retrieved 9 December 2006.
- "Types, Values, and Variables". Sun Microsystems. Retrieved 9 December 2006.
- "Java theory and practice: Where's your point? Tricks and traps with floating point and decimal numbers". IBM. 1 January 2003. Retrieved 19 November 2011.
- "Computer Language Benchmarks Game: Java vs Gnu C++". benchmarksgame.alioth.debian.org. Archived from the original on 13 January 2015. Retrieved 19 November 2011.
- J.P.Lewis & Ulrich Neumann. "Performance of Java versus C++". Graphics and Immersive Technology Lab, University of Southern California.
- "The Java Faster than C++ Benchmark". Retrieved 15 May 2016.
- FreeTTS - A Performance Case Study Archived 25 March 2009 at the Wayback Machine, Willie Walker, Paul Lamere, Philip Kwok
- John D. Carmack (27 March 2005). "Cell phone adventures". John Carmack's Blog. armadilloaerospace.com. Archived from the original on 24 November 2015. Retrieved 10 November 2015.
- Java SE Platform Security Architecture. Oracle. Retrieved 2013-04-23.
- "Researchers Highlight Recent Uptick in Java Security Exploits".
- "Have you checked the Java?". Archived from the original on 3 September 2012. Retrieved 25 November 2010.
- "Oracle knew about critical Java flaws since April". 30 August 2012. Retrieved 30 August 2012.
- "'Silent but deadly' Java security update breaks legacy apps - dev". Retrieved 15 May 2016.
- Pistoia, Marco; Banerjee, Anindya; Naumann, David A. (May 2007). "Beyond Stack Inspection: A Unified Access-Control and Information-Flow Security Model". 2007 IEEE Symposium on Security and Privacy (SP '07). IEEE: 149–163. doi:10.1109/sp.2007.10. ISBN 978-0-7695-2848-9.
- "Attachment A". www.java.com. Retrieved 3 March 2018.
External links
- Free But Shackled - The Java Trap, an essay by Richard Stallman of the free software movement (dated April 12, 2004)
- Computer Science Education: Where Are the Software Engineers of Tomorrow? (dated January 8, 2008)
- What are Bad features of Java?