Welcome to Chapter 14. In this book, my focus has been on the fundamental concepts of object-oriented programming in Java only. All programs were compiled in Java 8, which was the baseline in this book. Like other popular languages, Java is continuously growing, with new features added regularly. Though detailed coverage of these features was out of the scope of this book, in this chapter, you will examine some features or enhancements from various versions of Java. You get the most value out of a new enhancement if you are familiar with the existing features. So, for this chapter, I have picked only topics with which you are already familiar.
As a student, I first saw a Java book, which was based on Java 2, in my professor’s hand a long time ago. But at the time of this writing, Java 13 has been released, and in the upcoming days Java’s release train will be very fast. At present, Java is releasing new versions every six months. As a result, you can expect to see a lot more changes in the near future. But, as was said before, if you are familiar with the fundamental features and architecture, you can adapt to changes easily. All you have learned from this book can help you.
One final comment: for the latest features, I have compiled and executed the programs in the command-line environment. This is because my Eclipse environment was not ready to accept the latest features. So, if your preferred IDE is not ready to accommodate a latest feature, you can do the same thing I did. Now, let’s start.
Try-with-resource from Java 7
The try-with-resource statement
is a try statement in which you can declare one or multiple resources. A resource is an object that should be closed when your program finishes execution. But to use this feature, you have to choose an object that implements the AutoCloseable interface in the java.lang package.
This is because the close() method of an AutoCloseable object is called automatically once the control exits a try-with-resource block.
Here, I present a simple demonstration for you. In this demonstration, Resource1 is a class that implements the AutoCloseable interface.
So, if you use this concept using the following block:
try(Resource1 resource1 = new Resource1()) {
resource1.useResource();
}
in the output you will notice that the close() method of Resource1 is called automatically.
Demonstration 1
Consider the following code:
package java2e.chapter14;
//Resource-1
class Resource1 implements AutoCloseable {
public void useResource() {
System.out.println("Using a Resource1 type.");
}
@Override
public void close() throws Exception {
System.out.println("Close Resource1 type now.");
}
}
class TryWithResourceDemo {
public static void main(String[] args) throws Exception {
System.out.println("***Demonstration 1.Try with Resource demo.***
");
try(Resource1 resource1 = new Resource1()) {
resource1.useResource();
}
catch(Exception e) {
System.out.println(e);
}
}
}
Output
***Demonstration-1.Try with Resource demo.***
Using a Resource1 type.
Close Resource1 type now.
Q&A Session
14.1 What is a resource?
A resource is an object. Once your program uses a resource, you should close it before your program finishes execution.
14.2 Can I close multiple resources using this feature?
Yes. Here is a sample syntax for you, where two resources are used:
try(Resource1 resource1 = new Resource1();Resource2 resource2 = new Resource2()) {
//Some code
}
Implementing Functional Interface Methods Using Lambda Expressions from Java 8
In Java, a functional interface is an interface that has only one method. You can use a lambda expression to provide an implementation for the interface method.
But the notable change is that in this case, you do not need to define the method again before you provide an implementation for it. So, you can save lots of typing.
Demonstration 2
To help you understand this concept, I have provided a usual implementation before using a lambda expression. Here, you will see how to use a lambda expression that can have a return statement. Refer to the supporting comment lines for a better understanding.
package java2e.chapter14;
@FunctionalInterface
interface MyFunctionalInterface {
int addNumbers(int firstNumber, int secondNumber);
//error:You cannot declare multiple methods in a functional interface.
//int addNumbers2(int firstNumber, int secondNumber);
}
//Usual implementation of an interface method
class Implementor implements MyFunctionalInterface{
public int addNumbers(int firstNumber, int secondNumber) {
System.out.println("Implementing the interface method 'addNumbers' inside the Implementor class.");
System.out.println("Sum of "+ firstNumber + " and " +secondNumber + " is : ");
return firstNumber+ secondNumber;
}
}
class LambdaExpressionDemo {
public static void main(String[] args) {
System.out.println("***Demonstration 2. Lambda expression.***
");
//Common way to use an interface method.
MyFunctionalInterface impl1= new Implementor();
System.out.println(impl1.addNumbers(1, 2));
// Using lambda expression with a return statement.
System.out.println("Using Lambda expression with the return statement now.");
MyFunctionalInterface impl3 = (int a, int b) -> {
return (a + b);
};
System.out.println("Sum of 50 and 100 is :");
System.out.print(impl3.addNumbers(50,100));
Output:
***Demonstration 2. Lambda expression.***
Implementing the interface method 'addNumbers' inside the Implementor class.
Sum of 1 and 2 is :
3
Using Lambda expression with the return statement now.
Sum of 50 and 100 is :
150
Q&A Session
14.3 Is @FunctionalInterface mandatory in this program to show that it is a functional interface?
No. But using the annotation in a case like this is a good practice that enhances readability. Also, if you use this annotation, in the future, if anyone tries to add another abstract method in the interface by mistake, the compiler can immediately raise an error.
Java Language Specification(11) says the following:
A functional interface is an interface that has just one abstract method (aside from the methods of Object) and thus represents a single function contract. This “single” method may take the form of multiple abstract methods, with override equivalent signatures inherited from superinterfaces; in this case, the inherited methods logically represent a single method.
It facilitates early detection of inappropriate method declarations appearing in or inherited by an interface that is meant to be functional.
“[I]nstances of functional interfaces can be created with method reference expressions and lambda expressions.”
Private Interface Method from Java 9
Private interface methods were a new addition in Java 9. Prior to Java 7, interface methods were straightforward—those were public abstract methods. Java 8 allows you to add public static methods and public default methods. In Java 9 onward you can use private static methods and private default methods in the interface.
Demonstration 3
Let’s consider the following demonstration. Here, you have an interface called
MyInterface with four methods:
The first one is a common interface method; it does not have a body, and it is by default public and abstract.
Then you have two default methods.
Finally, you have the private non-static interface method, called privateInterfaceMethod(). Notice that since the method is private, you cannot call the method directly from main().
In this example, I am calling the private method through the default methods:
interface MyInterface{
void commonInterfaceMethod();
default void defaultInterfaceMethod1() {
System.out.println("**Default non-static method1()**");
//Doing the common task using the private interface method
privateInterfaceMethod();
}
default void defaultInterfaceMethod2() {
System.out.println("**Default non-static method2()**");
//Doing the common task using the private interface method
privateInterfaceMethod();
}
private void privateInterfaceMethod() {
System.out.println("**Private non-static method in MyInterface**");
System.out.println("**I can do the common tasks of multiple default methods.**");
}
}
class MyInterfaceImplementor implements MyInterface{
@Override
public void commonInterfaceMethod() {
System.out.println("**Implementing the commonInterfaceMethod().**");
}
}
class PrivateInterfaceMethodFromJava9 {
public static void main(String[] args) {
System.out.println("***Demonstration 3.Private Interface Method From Java 9.***
");
MyInterface interOb=new MyInterfaceImplementor();
interOb.commonInterfaceMethod();
interOb.defaultInterfaceMethod1();
interOb.defaultInterfaceMethod2();
}
}
Output:
***Demonstration 3.Private Interface Method From Java 9.***
**Implementing the commonInterfaceMethod().**
**Default non-static method1()**
**Private non-static method in MyInterface**
**I can do the common tasks of multiple default methods.**
**Default non-static method2()**
**Private non-static method in MyInterface**
**I can do the common tasks of multiple default methods.**
Q&A Session
14.4 What is the use of a private interface method?
If you have multiple default methods in the interface and those interfaces are performing a common task, you can place the common code in the private helper method. Consider Demonstration 4 again. It shows how two default methods— defaultInterfaceMethod1() and defaultInterfaceMethod2()—can accomplish a common task using a private interface method.
14.5 If the sharing of code is the concern, I can make another default method and share the common code in that method. Is this understanding correct?
You can do that, but that approach cannot be considered a better design than this. It is better to use a private helper method than a public helper method. This approach can promote better encapsulation and security.
14.6 Can a default method be private?
No. You will get a compile-time error if you use the following line of code:
default private void defaultPrivateInterfaceMethod() {
//some code
}
The error will be as follows:
PrivateInterfaceMethodFromJava9.java:14: error: illegal combination of modifiers: private and default
default private void defaultPrivateInterfaceMethod() {//some code
^
1 error
14.7 Can I make a private interface method static?
Yes. For example, if you add the following two methods in the interface
MyInterface:
public static void publicStaticInterfaceMethod() {
System.out.println("**Public static method in MyInterface**");
System.out.println("**Invoking the private static method in MyInterface now.**");
}
private static void privateStaticInterfaceMethod() {
System.out.println("**Private static method in MyInterface**");
}
and then invoke the
publicStaticInterfaceMethod() method from
main() like the following:
MyInterface.publicStaticInterfaceMethod();
you will see the following lines in your output:
**Public static method in MyInterface**
**Invoking the private static method in MyInterface now.**
Local Variable Type Inference from Java 10
From Java 10 onward, you can declare a local variable without specifying its type.
Even if you do not declare the variable type, it can assume its type from what it is being set to. For example, from Java 10 onward, you can write something like the following:
Demonstration 4
The upcoming demonstration can show you a simple usage of
var:
class LocalVariableTypeInterpretation {
public static void main(String[] args) {
System.out.println("***Demonstration 4.Local Variable Type Interpretation.***
");
int myInt1=1;//ok
var myInt2=2;//Java10 onwards ok
System.out.println("The value in myInt1 is :"+ myInt2);
System.out.println("The myInt1 is of type:");
//It will print java.lang.Integer
System.out.println(((Object)myInt1).getClass().getName());
System.out.println("The myInt2 is of type:");
//It will also print java.lang.Integer
System.out.println(((Object)myInt2).getClass().getName()); }
}
Output:
***Demonstration 4.Local Variable Type Interpretation.***
The value in myInt2 is :1
The myInt1 is of type:
java.lang.Integer
The myInt2 is of type:
java.lang.Integer
Restrictions
Here are some important restrictions when you use
var:But the following line will raise a compile-time error:
var myInt;//Error
myInt=1;
var var=12.5;//Till now , compiler allows it
You can use var in the context of initializing local variables and for loops, but you cannot use them in method parameters or return types. For example, in the following code segment, both methods in MyClass will raise compile-time errors:
//You can use 'var' in the context of initializing local variables //and for loops but you cannot use them in method parameters
//or return type.
class MyClass {
void myMethod1(var i) { // Compile-time error
// some code
}
var myMethod2(int i) { //Compile-time error
}
}
New String Methods from Java 11
From Java 11 onward, you’ll get some new
String class
methods. In the following example, you will see three of them—
isBlank(),
repeat(), and
strip(). Let’s see their definitions:
isBlank(): This method will return the Boolean value true if the string is empty or contains only white space codepoints; otherwise, false.
repeat(int n): Returns a string whose value is the concatenation of this string repeated n number of times.
strip(): This method returns a string with all leading and trailing white space removed.
Demonstration 5
Consider the following code:
class StringMethodsFromJava11 {
public static void main(String[] args) {
System.out.println("***Demonstration 5.Some new String methods from Java 11.***
");
String str1 = "A non-empty string.";
System.out.println("The str1 is :"+ str1);
System.out.println(" 'The str1 is a blank string'-This statement is "+ str1.isBlank());
String str2 = "";
System.out.println("The str2 is :"+ str2);
System.out.println(" 'The str2 is a blank string'-This statement is "+ str2.isBlank());
//Repeat the string
System.out.println("
Repeating 'str1' 3 times now.");
System.out.println(str1.repeat(3));
//Using strip() removing beginning and trailing whitespaces
String str3 = " Hi, Readers! How are you? ";
System.out.println("
The str3 is :"+ str3);
System.out.println("After strip() operation, str3 is :" + str3.strip());
}
}
Output:
***Demonstration 5.Some new String methods from Java 11.***
The str1 is :A non-empty string.
'The str1 is a blank string'-This statement is false
The str2 is :
'The str2 is a blank string'-This statement is true
Repeating 'str1' 3 times now.
A non-empty string.A non-empty string.A non-empty string.
The str3 is : Hi, Readers! How are you?
After strip() operation, str3 is :Hi, Readers! How are you?
Q&A Session
14.8 How is isEmpty()different from isBlank()?
The definition of
isEmpty() says that if and only if the string length is zero, it will return
true. The following block of code can illustrate the difference between these two methods:
//isBlank vs isEmpty
String nonEmpty=" ";//a tab space
System.out.println("The nonEmpty.length()="+ nonEmpty.length());
System.out.println(nonEmpty.isBlank());//true
System.out.println(nonEmpty.isEmpty());//false
When you execute this block of code, you will get following output:
The nonEmpty.length()=1
true
false
Since the length of nonEmpty is not zero, isBlank() returns true, but isEmpty() returns false.
14.9 How is strip() different from trim()?
strip() can detect Unicode whitespace. But
trim() can remove the space that is less than or equal to
u0020. To see the difference, you can examine a string like the following:
//Medium Mathematical Space U+205F
String str1 = "u205F u205FThis is my test string with trailing whitespace-END.u205F u205F";
Now if you call the
trim() method and the
strip() method on this string object, you will notice the difference. For example, if you test with the following lines of code:
String trimmedString = str1.trim();
String strippedString = str1.strip();
System.out.printf("'%s'%n", trimmedString);
System.out.printf("'%s'%n", strippedString);
you will see that strip() can recognize the initial and trailing whitespaces of the string and complete its job properly.
New switch Expression in Java 12/13
The switch expression
appeared in Java 12 and was further refined in Java 13. But it is a preview language feature. Using this expression, an entire switch block can receive an input value. You can use lambda-style syntax to implement this. Using this feature, you implement a straightforward control flow that is free of “fall-through.”
Demonstration 6
The following demonstration shows a simple use of this feature. For case 1 to case 5, it will print a common message (
Your version is between 1 and 5), for cases 6 to 12 it will print another common message (
Your version is between 6 and 12). If the version is 13, the example will show a different message (which is shown in the output). The example also includes a default case to print about the default version. For simplicity, the
myVersion variable is “hard-coded” here. But you can always modify it to accept a different version or consider the user’s input. My focus was on the main feature, so I’m ignoring the other fancy parts.
class SwitchExpressionTest {
public static void main(String[] args) {
System.out.println("***Testing Switch expression in Java 13.***");
System.out.println("Considering versions between 1 to 13.");
int myVersion=13;//Your version.You can change here.
testNewSwitchExpressionInJava13(myVersion);
}
public static void testNewSwitchExpressionInJava13(int version){
switch (version) {
case 1,2,3,4,5-> System.out.println(" Your version is between 1 and 5.");
case 6,7,8,9,10,11,12-> System.out.println("Your version is between 6 and 12");
case 13-> System.out.println("At present, 13 is the latest version. You picked it.");
default -> System.out.println("You didn't pick between 1 and 13. Default version is: 0");
}
}
}
Output:
***Testing Switch expression in Java 13.***
Considering versions between 1 and 13.
At present, 13 is the latest version. You picked it.
Running the Code
In a command-line environment, if the path is not set, to avoid a lot of typing (to mention the javac and java locations), you need to set the path. You can set it in your environment variable, or you can set the path like the following.
Normally, Java13 will be installed in this path. If you use a different path, mention that location only for the path variable. In Chapter
7, you saw how to troubleshoot some common errors in a command-line environment.
C:TestClasschapter14>set path=C:Program FilesJavajdk-13in;
To compile the code in this demonstration, you need to use the
–enable-preview option. Here is a sample:
C:TestClasschapter14> javac --enable-preview -source 13 SwitchExpressionTest.java
Here is the immediate output:
Note: SwitchExpressionTest.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
To run the program, you can try the following command, shown in bold:
C:TestClasschapter14>java --enable-preview SwitchExpressionTest
The output is already shown “” above.
Q&A Session
14.10 Why do I need to pass the additional parameters with javac or java when I compile or run this program?
This is still a preview feature. This simply means that, though the overall feature is complete, the final decision to include it in a mainline JDK has yet to be decided. To build confidence in a feature and to get maximum possible feedback, a feature can be tagged like this.
When you use a preview feature, you need to unlock it when you compile the program or run the program. This is why you used the -enable-preview option earlier to compile and run the program in this example (Demonstration6).
Summary
This chapter covered the following:
Switch expression from Java12/13
New String class methods from Java 11
Local variable type inference from Java 10
Private methods from Java 9
Implementing functional interfaces with lambda expressions from Java 8
Try-with resource-from Java 7