Criticism of Java
| Industry | Software development |
|---|---|
| Founded | 1995 |
| Products | Programming language, Java platform, Java Virtual Machine (HotSpot) |
The Java programming language along with the Java platform have encountered criticism regarding several design decisions, including the approach to implementing generics, the strict enforcement of object-oriented paradigms, the absence of support for unsigned numeric types, the handling of floating-point calculations, and a history marked by security weaknesses in the primary Java Virtual Machine, HotSpot. Initial versions of Java software were also reproached for lagging behind other languages in terms of performance. Developers frequently highlight that inconsistencies across various Java implementations introduce challenges when crafting sophisticated and portable Java applications.[1]
Checked exceptions
Java was among the first languages to introduce checked exceptions, mandating that methods explicitly declare any checked exceptions they might throw. This feature often results in extensive boilerplate code. Notably, no other major programming language has adopted checked exceptions since their introduction.
Generics
With the arrival of generics in Java 5.0, backward compatibility with extensive pre-existing class libraries necessitated implementing generics through type erasure. This approach restricted the power and flexibility of generics compared to implementations in other programming languages.[2][3]
Because of type erasure, generic type parameters are not retained at runtime, which prohibits certain operations such as instanceof checks or instantiating new generic objects:[4] <syntaxhighlight lang="java"> 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
}
} </syntaxhighlight>
An issue uncovered in 2016 demonstrated that Java's type system is unsound; certain JVMs would throw runtime exceptions like ClassCastException despite this behavior being technically non-compliant with the language specification.[5] This problem was addressed starting with Java 10.
<syntaxhighlight lang="java"> class Nullless<T, U> {
class Constrain {}
final Constrain<? super T> constrain;
final U u;
Nullless(T t) {
u = coerce(t);
constrain = getConstrain();
}
U upcast(Constrain constrain, B b) {
return b;
}
U coerce(T t) {
return upcast(constrain, t);
}
Constrain<? super T> getConstrain() {
return constrain;
}
public static void main(String[] args) {
String zero = new Nullless<Integer,String>(0).u;
}
} </syntaxhighlight>
Noun-orientedness
Java's design philosophy encourages developers to conceptualize solutions primarily as interacting nouns (classes), with verbs (methods) serving as operations on those nouns. According to Steve Yegge, this approach limits the language's expressiveness because functions are tied to a single class and cannot seamlessly operate across different types.
In contrast, many multi-paradigm languages provide functions as standalone entities, offering enhanced flexibility through features such as function overloading and generic functions. To mitigate this limitation, Java 8 introduced functional programming capabilities.
Unsigned integer types
The absence of native unsigned integer types in Java complicates direct data exchange with languages like C and restricts its ease of use in domains like cryptography that depend on unsigned values. Although developers can employ larger signed types or simulate unsigned behavior using bitwise operations, these methods increase memory consumption and necessitate rewriting logic that relies on two's complement overflow behavior.
While JDK 8 added some support for unsigned integers via APIs, it did not extend this functionality to unsigned bytes nor incorporate it directly into the language syntax.
Operator overloading
Java has faced criticism for not supporting user-defined operator overloading, a feature that can enhance code clarity, particularly for classes representing mathematical constructs such as complex numbers or matrices. The language only permits operator overloading for string concatenation using + and +=, which the compiler implements internally through StringBuilder objects. Custom operator overloads by users are not supported.
Compound value types
Unlike C's structs, Java does not provide compound value types that store data directly instead of through references. Value types often offer advantages in memory footprint and execution speed. For instance, Java's HashMap maintains an array of references to HashMap.Entry objects, introducing an extra level of indirection. If Entry were a value type, key-value pairs could be stored inline, enhancing cache locality and reducing both memory usage and heap fragmentation. The introduction of generic primitive types could further eliminate indirection by enabling direct storage of keys and values.
Large arrays
Java restricts arrays to a maximum size of 231 elements (approximately 2.1 billion) because array indices are of type int, not long. This limitation constrains collections to fewer than two billion elements and prevents memory mapping for continuous file regions exceeding 2 GB. Expanding array size support would require modifications to the JVM. Moreover, Java lacks true multidimensional arrays represented as contiguous memory blocks accessed via a single pointer, limiting performance in scientific and technical computing contexts.
Integration of primitives and arrays
Handling arrays and primitive types differently from classes has been criticized because it forces general-purpose libraries to implement multiple versions of similar functions.
Parallelism
In 1999, Per Brinch Hansen argued that Java's approach to parallelism—especially its monitor implementation—does not provide the necessary guarantees for secure and dependable concurrent programming. Although developers can rely on design patterns to mitigate risks, the compiler cannot enforce these conventions, potentially leading to insecure or unreliable parallel code.
Serialization
Java enables object serialization, which transforms objects into byte streams containing type metadata for subsequent deserialization. Despite its utility, this feature introduces considerable security vulnerabilities in both practical applications and theoretical frameworks.
Floating point arithmetic
While Java's floating-point calculations adhere to IEEE 754 standards, it omits certain required elements—even when using the strictfp keyword—such as Exception Flags and Directed Rounding modes. Furthermore, Java does not support the extended precision types defined by IEEE 754.
Absence of tuples
Java does not offer built-in support for tuples, resulting in widespread reliance on external libraries that developers must incorporate and maintain. Critics caution that adding a generic tuple class could lead to codebases that are difficult to sustain.
Abstracted relationship between code and hardware
In 2008, the United States Department of Defense identified Java as an unsuitable choice for introductory programming courses, emphasizing students’ limited grasp of how source code translates into hardware operations and the challenges in evaluating runtime costs due to Java’s abstraction layers. Earlier, in 2005, Joel Spolsky criticized Java's prevalence in academic settings through his essay The Perils of JavaSchools, arguing it hampers the cultivation of flexible software design abilities. Conversely, figures like Ned Batchelder disputed Spolsky’s assertions, suggesting his critique was subjective and centered on concepts he personally found difficult rather than universally vital programming competencies.
Performance
Prior to 2000, Java was often criticized for subpar performance; however, the introduction of the HotSpot VM with Java 1.3 marked a turning point with substantial enhancements. Current JVM implementations frequently rank among the fastest language platforms, typically executing within a factor of three compared to highly optimized native languages such as C and C++.
Performance has markedly advanced since early releases. In optimized scenarios, JIT compiler efficiency can rival that of native compilers. Java bytecode may be interpreted during runtime or compiled either at load time or runtime into machine code. Modern JVMs predominantly employ just-in-time compilation, enabling performance after startup to approach native execution speeds.
Nonetheless, game developer John Carmack observed in 2005 that Java on cell-phone devices remained sluggish, limiting available CPU resources and control relative to specialized gaming hardware.
Security
The Java platform incorporates a security framework intended to execute untrusted bytecode within sandbox environments that restrict access to critical system resources such as local storage and network interfaces, thereby mitigating malware risks.
In 2010, vulnerabilities within Java’s sandboxing mechanisms—including Oracle’s implementations—resulted in heightened malware activity. Although Oracle released patches addressing these issues, many users remained exposed due to delayed updates or lack of awareness. Organizations often impose restrictions on software installations but are slow to implement essential security patches.
Oracle faced criticism for postponing security fixes. Notably, when addressing widely exploited vulnerabilities in Java 7, Oracle removed Java 6 from affected systems despite its ongoing enterprise use and assurances that it was not susceptible to those specific threats.
Research by Marco Pistoia in 2007 exposed a critical weakness in Java’s stack inspection security model. This model requires verifying each method on the call stack for appropriate permissions when accessing sensitive resources to prevent privilege escalation attacks such as the confused deputy problem. Pistoia demonstrated that access decisions could depend on earlier method calls no longer present on the stack, compromising this safeguard.
Certain operations implicitly grant Java’s AllPermission, including altering the security manager, utilizing custom class loaders capable of assigning all permissions to malicious classes, and creating custom permissions that imitate AllPermission. These security concerns are extensively analyzed in Pistoia’s authoritative publications on Java security.
Concurrent installations
Prior to the release of Java 7, installation processes did not automatically uninstall previous Java versions, resulting in multiple copies coexisting on a single Windows machine. This situation created security vulnerabilities since certain applications—and potentially harmful software—depended on particular Java versions. With Java 7, this issue was mitigated by removing older versions during installation, provided the user agreed, thereby enhancing both security and system maintenance.
The use of just-in-time (JIT) compilation involves generating executable code at runtime, which inherently brings about security concerns and exposes systems to possible exploitation.
See also
- Comparison of Java and C++
- Comparison of C# and Java
- Java performance
- Write once, run anywhere
- Scala, a language created to overcome some of Java's shortcomings
External links
- Free But Shackled - The Java Trap, an essay by Richard Stallman from the free software movement (April 12, 2004)
- Computer Science Education: Where Are the Software Engineers of Tomorrow? (January 8, 2008)
- What are Bad features of Java?
- ↑ Wong, William (2002-05-27). "Write Once, Debug Everywhere". electronicdesign.com. Archived from the original on 2009-03-21. Retrieved 2008-08-03.
To date, Java's "write-once, run-everywhere" ideal has not been fully realized. Although most of a Java program transfers between different Java environments, leveraging VM-specific features creates portability issues.
- ↑ "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". 2006-12-06. Archived from the original on 22 July 2012. Retrieved 2006-12-09.
- ↑ "Type Erasure".
- ↑ Amin, Nada; Tate, Ross (2016-10-19). "Java and scala's type systems are unsound: the existential crisis of null pointers". ACM SIGPLAN Notices. 51 (10): 838–848. doi:10.1145/3022671.2984004. ISSN 0362-1340.