What Makes Java Agile

[article]
Summary:

Java is one of the most commonly used programming languages, patronized for its simplicity, extensibility, and object-orientedness. The principles of Agile software emphasize simplicity, interactions among individuals, working software, customer collaboration, and responsiveness to change. So, what makes Java Agile?

Simplicity

Several features make Java simple, including:

  • Use of object-oriented principles
  • Automatic garbage collection

As Java is based on the familiar object-oriented principles of polymorphism, inheritance, abstraction, and encapsulation, it is easy to learn if a developer knows some other object-oriented language such as C/C++, though some differences exist.

With automatic garbage collection, the garbage collector (GC) monitors the heap memory for unused objects and deletes the objects that are no longer in use to free up heap memory. In contrast, some languages such as C/C++ do not provide automatic garbage collection, requiring explicit code to delete unused objects. Smart pointers do provide automatic deletion if a smart pointer count reaches 0, but smart pointers have to be coded.


Maintainability

Java source code is easy to understand and maintain by virtue of several features that include:

  • Naming conventions such as meaningful class/method/variable names
  • Comments in various forms


Extensibility

Java source code is extensible by virtue of several features that include:

  • Abstraction with interfaces & abstract classes
  • Method overriding
  • Sealed classes

Sealed classes, introduced in Java 17, provide a more fine-grained class extensibility by allowing a developer to explicitly specify the classes that can extend the class. Sealed classes are discussed in more detail in Sealed Classes in Java 17.

Code accessibility may be set with access modifiers. The @SafeVarargs annotation on a private instance method prevents the method from being overridden.

Portability

Java is a platform independent language, source code for which can be compiled once into bytecode (binaries) and run on any JVM (Java Virtual Machine) operating system. To illustrate with an example, C++ code gets compiled into platform-specific binaries. C/C++ code compiled on Windows runs only on Windows, and C/C++ code compiled on Linux runs only on Linux.

A new feature added in Java 18 making UTF-8 as the default character set makes Java portable as discussed in New Java 18 Feature–Default Charset UTF-8.

Easy to Update

Several features make Java easy to update.

One of the requirements that made it difficult to classes that implemented an interface was the binary incompatibility introduced when interface methods needed to be updated. Classes that implemented an older version of an interface became incompatible and unusable unless updated. To demonstrate, consider an interface A with a method fn1.

public interface A {

void fn1(int a, String b);

}

Assume that two different classes implemented the interface, and over time one of the classes needs to update the code to add a new method called fn2. To add the new method, the new method is added to the interface as follows.

public interface A {

void fn1(int a, String b);

String fn2(String a);


}

The class that needs the new method may be updated as needed, but what about the other classes that don’t need the new method. The other classes become binary incompatible. Java 8 added a new feature called default implementation for interface methods that provides a default method implementation using the default keyword if a class does not provide an implementation. As an example:

public interface A {

void fn1(int a, String b);

default String fn2(String a){

return “”;

}

}

As a result, classes implementing the older versions of an interface could be continued to be used as such without becoming binary incompatible.

Local variable type inferencing introduced in Java 10 made it unnecessary to declare a type for each local variable. By declaring a local variable with the var identifier, the type of a variable is inferred from the context. The feature precludes having to update local variable type declarations if the use of the variable is updated.


Less Code

Several features make less code feasible.

Record classes in Java 16 introduce a concise syntax for declaring immutable data carriers. Records are discussed in more detail in Records in Java 14 for Concise Data Carriers.

The new switch control statement added in Java 14 precludes fall-through semantics of an earlier switch that required a break; statement to avoid a fall-through. A fall-through implies that all switch case labels after the matching case label get run, which may not be needed. The switch in version 14 has a new syntax that supports a switch expression, a block denoted with {}, and a throw statement. The value returned by a switch expression can be assigned to a variable. The new switch is discussed in detail in Switch Expressions in Java 14 add Simplicity and Agility. Pattern matching for switch expressions and statements is in preview in Java 19.

The Text Blocks feature, added in Java 15 makes adding multi-line string literals more concise. Before text blocks, a multi-line string could only be added by quoting each line in double-quotes, and concatenating the multi-lines with the concatenation operator (+), and requiring escape sequences for newline characters. The Text Blocks feature is discussed in more detail in Text Blocks Make Java More Agile.

One of the other features that makes less code feasible is pattern matching for the instanceof operator, which was discussed in detail in Using the New Pattern Matching Feature in Java 16.

A concise try-with-resource statement in Java 9 precludes having to declare resource variables that are final, or effectively final. As an example:

try (fileReader;
bufferedReader) {
}

Another new feature that reduces code is support for a multi-catch statement, which was introduced in Java 7. Prior to Java 7, multiple exceptions could only be caught with multiple catch statements, as an example:

try {
} catch (JAXBException e1) {

} catch (SQLException e2) {

}

In Java 7 and latter versions the catch blocks can be combined with a | as follows:

try {
} catch (JAXBException e1|SQLException e2) {

}


Code Packaging

Java already provided the package structure for code using the package statement. Java 9 introduced named modules to package multiple packages together.


Frequent Release Cycle

Java has adopted a new release cadence cycle starting with Java versions succeeding Java 8 in which a new Long Term Support (LTS) version is made available every two years with multiple non-LTS versions released every 6 months. This facilitates making available for test, and user input, new features as preview features in the non-LTS versions instead of waiting for new features in the Java release cycle of a version every three years. This also promotes user collaboration as end users are able to test the preview features and provide input on whether a preview feature is useful and how it could be improved.

Tags: 

About the author

AgileConnection is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.