{{announcement.body}}
{{announcement.title}}

SKP's Java/Java EE Gotchas: Revisiting Java SE 9 Features, Part 1

DZone 's Guide to

SKP's Java/Java EE Gotchas: Revisiting Java SE 9 Features, Part 1

In this follow up article, we discuss some of the nuances of Java 9 in the context of potential errors you might encounter.

· Java Zone ·
Free Resource

Preparing for an interview? Want to just revisit Java SE 9 features? Trying to recollect or revise Java SE programming constructs? Let me take you back in time to what was introduced first in Java SE 9? Join me for this tutorial series on Java as we all eagerly await the official release of Java SE 14!

As I promised, I am back with the code samples of my earlier article Java SE 9... What's New? You may refer the earlier article to understand the newly introduced features at a high level. This article provides the code samples for each of the features.

You may download the code samples for the following new features here. (Import as eclipse project, set compiler/environment as Java 9. Run the main class 'Java9Application' to see the output/outcome of the Code Samples.)

I plan to start by re-visiting a Java 8 feature, Default Interface Methods.

You may also enjoy: SKP's Java/Java EE Gotchas: Java SE 9 Features

Default Interface Methods

Whenever there is existing or legacy code that has Interfaces that require the addition of new methods, it breaks existing classes that inherit or implement from this interface, unless the implementation for each of these added methods is provided in the classes. This is not very maintainable code. Even though it's a good practice as from SOLID and other OO paradigms to provide an interface without any implementation — we need to handle and solve the problem as mentioned above. This is where default interface methods come in.


Java
 




x
20


 
1
import java.util.List;  
2
    
3
  public interface LegacyPublicInterface {  
4
        
5
        
6
/**  
7
Additional Default Method that Can be Invoked on Each Type of Invoice that Implements the LegacyPublicInterface. It can also be over-ridden by the Extending Invoice Types. This is an Example Usage and Benefit of the Java/JDK 8. Default Interface feature.  
8
 
9
 @param items  
10
*/  
11
      default void checkStatusOnEachItem (List<String>... items) {  
12
        
13
          for(String item : items) {  
14
              if(item.startsWith("OOS_")) {  
15
                  items.remove(item);  
16
              }  
17
          }  
18
          return;  
19
      }      
20
  }  


 23: 

From the example above, the LegacyPublicInterface in an existing application is already extended by multiple invoice types (for example, in an inventory system). Re-engineering effort requires that each of the invoices have a method to invalidate or remove an Item marked with "OOS." Given such a problem, prior to Java 8, we would have to introduce a new method declaration in the interface and then require that each of the implementing classes implement their own logic for handling this. With default interfaces, the task becomes very simple (the code is now more maintainable and extensible and requires very less effort to change). With the introduction of Default Methods, here are the possibilities:

  1. Use the Default Method(s) without breaking existing functionality (best use)
  2. Implementing Class can choose to override these Default Methods
  3. Abstract Classes can be provided over the Interfaces to override Implementation
So, let's get further into each of these changes in Java 9, one-by-one.

Java Language Changes in JDK 9

Private Interface Methods

Interfaces in Java 9 are allowed to have Private Methods. This was done to allow code sharing between non-abstract methods in the Interface. All rules related to ordinary Private modifiers apply to these methods. The point to note is that a method cannot be both private and abstract. It definitely needs to have a method body.

Java
 




xxxxxxxxxx
1
27


 
1
 package com.techilashots.java9.features;  
2
 
3
/**  
4
  * @author sumith.puri  
5
  *   
6
  * prior to java 8, the default scope/visibilty of every method in an interface was same  
7
  * the attributes were all by default, [public static final] and the methods were [public]  
8
  * with java 8, [default] interface methods have been introduced but so has been a new scope/visibility  
9
  * with java 9, interface can have private visibility methods that can be used internally   
10
  */  
11
 public interface Java9PrivateMethodInterface {  
12
 
           
13
      public void preJava9BusinessMethodOne();  
14
 
           
15
      public void preJava9BusinessMethodTwo();  
16
 
           
17
      public default void newJava9BusinessMethodThree() {  
18
           System.out.println("Interface Methods can call Private Interface Methods!");  
19
           System.out.println("");  
20
           java9BusinessMethodThreeHelper();  
21
      }  
22
 
           
23
      private void java9BusinessMethodThreeHelper() {  
24
           System.out.println("Default Methods... Now Private Methods!");  
25
           System.out.println("Once Upon a Time, I was a Java Developer!");  
26
      }  
27
 }  




You can observe the usage of the above private method (internally by the new default method) through the following code.

Java
 




xxxxxxxxxx
1
23


 
1
   //new features of java 9  
2
      //private interface methods  
3
      private void privateInterfaceMethod() {  
4
 
            
5
           System.out.println("01. Private Interface Methods");  
6
           System.out.println("-----------------------------");  
7
           System.out.println("[Private Interface Method Invoked by Default Interface Method]");  
8
           Java9PrivateMethodInterface java9PrivateMethodInterface = new Java9PrivateMethodInterface() {  
9
                @Override  
10
                public void preJava9BusinessMethodTwo() {  
11
                     // TODO Auto-generated method stub  
12
                }  
13
                @Override  
14
                public void preJava9BusinessMethodOne() {  
15
                     // TODO Auto-generated method stub  
16
                }  
17
           };  
18
 
            
19
           java9PrivateMethodInterface.newJava9BusinessMethodThree();  
20
           System.out.println("");  
21
           System.out.println("================================");  
22
           System.out.println("");  
23
      }  




Underscore as A Variable Name Is Not Legal Anymore

Using only the underscore character ("_") as a variable name is not legal anymore. This is because it is marked as a reserved keyword from Java 1.8 (but caused compilation failure only in Java 1.9). This may cause some issues when compiling legacy source code, especially with a necessity to denote some specific resource or entity using the underscore. It may have to be rewritten and may have many related ramifications.

Java
 




xxxxxxxxxx
1
18


 
1
 /**  
2
  * @author sumith.puri  
3
  *  
4
  */  
5
 public class Java9VariableNaming {  
6
      // pre-java 9, this was a valid variable name  
7
      // from java 8, _ was marked as a reserved keyword (compiler warning) 
8
      // from java 9, the following line of code will cause compilation failure  
9
      // private String _;  
10
      private String _socket = null;  
11
      /**  
12
       * @param args  
13
       */  
14
      public void notForDemoMethod() {  
15
           _socket = new String("Network Socket");  
16
           System.out.println("_ is no Longer a Valid Variable Name!, [Variable Value: " + _socket + "]");            
17
      }  
18
 }  




Allow Effectively Final Variables to Be Used as Resources in Try with Resources 

Until Java 8, every variable that had to be used within Try with Resources statements was required to be declared within the try statement. Only then can it be used within the try block. This is a limitation for the developer. Hence, in Java 9, this restriction has been removed and any final variable or effectively final (local) variable can be used inside the try block. All other rules as applicable to Try with Resources continue. Effectively Final means the variable is not changed after it has been initialized.

Java
 




xxxxxxxxxx
1
30


 
1
 package com.techilashots.java9.features
2
 
           
3
 import java.io.BufferedReader;  
4
 import java.io.File;  
5
 import java.io.FileReader;  
6
 import java.io.IOException;  
7
 
8
 /**  
9
  * @author sumith.puri  
10
  */  
11
 public class EffectivelyFinalTryResources {  
12
 
13
     private static File file = new File("try_resources.j9");   
14
 
           
15
      //with java 9, you need to use either explicitly final or effectively final variables in try/resources  
16
      public void methodWithAnomaly() throws IOException {  
17
 
           
18
           file.createNewFile();  
19
           BufferedReader bufferedReader = new BufferedReader(new FileReader(file));  
20
       
21
           //prior to java 9, the usage would look like this  
22
           //try (final BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {  
23
           //this code will not compile before java 9  
24
           try (bufferedReader) {            
25
                System.out.println("Can Use Final or Effectively Final in Try with Resources!");  
26
           } finally {  
27
                System.out.println("Java 9 Gives More Flexibility to Developers.");  
28
           }            
29
      }  
30
 }  




@SafeVarargs is Allowed on Private Instance Methods 

Using non-reifiable variable argument parameters in a method can cause multiple warnings when trying to compile code, such as:

Java
 




xxxxxxxxxx
1


 
1
NoteLegacyPublicInterface.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details.



@SafeVarargs   was introduced to suppress such warnings on unchecked or unsafe operations. By using this, the developer is signalling to the compiler that he has made sure that there will be no heap pollution (such as unsafe   forEach  operations) caused.

Prior to Java 9, @SafeVarargs is allowed on non-overridable methods such as in static methods, final instance methods and constructors. Note that the annotation will throw an error if it is used in fixed arity methods. In Java 9,   @SafeVarargs can be used on private instance methods.


Java
 




xxxxxxxxxx
1
18


 
1
 package com.techilashots.java9.features;  
2
 
           
3
 /**  
4
  * @author sumith.puri  
5
  */  
6
 public class SafeVarargsOnPrivateMethod {  
7
 
           
8
      public void demoSafeVarargsInJava9() {  
9
           safeVarargsInJava9(24.00f, 03, 19, 82);  
10
      }  
11
 
           
12
      @SafeVarargs  
13
      private void safeVarargsInJava9 (Float a, Integer...b) {  
14
 
           
15
           System.out.println("Invoked Private Instance Method with " +a+ "," +b[0]+ "," +b[1]+ "," +b[2]);  
16
           System.out.println("With Java 9, @SafeVarargs is Allowed on Private Instance Methods!");  
17
      }  
18
 }  



Allow Diamond with Anonymous Classes If Inferred Type's Argument Type is Denotable 


Until Java 8, using Generics and Diamond Operators with Anonymous Classes was mainly because the compiler could not infer whether it can represent the type in the Argument passed to the Diamond Operator. JSR 334 has the following to say about using Diamond with anonymous classes:
"Using diamond with anonymous inner classes is not supported since doing so in general would require extensions to the class file signature attribute to represent non-denotable types, a de facto JVM Change."
Additional information is located in the Project Coin mailing list's Diamond Operator and Anonymous Classes topic:
"Internally, a Java compiler operates over a richer set of types than those that can be written down explicitly in a Java program. The compiler-internal types which cannot be written in a Java program are called non-denotable types. Non-denotable types can occur as the result of the inference used by diamond. Therefore, using diamond with anonymous inner classes is not supported since doing so in general would require extensions to the class file signature attribute to represent non-denotable types, a de facto JVM change. It is feasible that future platform versions could allow use of diamond when creating an anonymous inner class as long as the inferred type was denotable."
With Java 9, the Java Compiler has changed its inference algorithm in a way that diamond operator (generics) can now work simultaneously with anonymous classes, as long as the argument type of the inferred type is denotable. The important point to note is that things that fall under denotable are primitive types, raw types and non-generic types. Non-denotable means ones that cannot be written in a Java program, like usage of extends and super, along with wildcard types in generics. These are usually inferred by the compiler. So, as long as the compiler identifies that the argument type of inferred type is denotable, you can use the diamond operator in conjunction with anonymous inner classes.

Java
 




xxxxxxxxxx
1
10


 
1
package com.techilashots.java9.features;   
2
 
            
3
/** * @author sumith.puri */ 
4
public class DiamondOperatorOnAnonymous {   
5
  
6
  public void diamondForInferredDenotable() {   
7
    
8
    //prior to java 9, anonymous inner classes were not allowed to use diamond operator 
9
    
10
    Java5ToJava8Coder<? extends Number> java9SyntaxGuru = new Java5ToJava8Coder<>() { 
11
    @Override 
12
    public void java9SyntaxMagic() { 
13
        System.out.println("Introduced in Java 5, Generics was Intriguing and Complex!"); 
14
        System.out.println("With Java 9, Diamond Operator On Anonymous Classes is Allowed..."); 
15
        System.out.println("As Long as Java 9 Infers the Type (Inferred) to be Denotable."); 
16
      } 
17
    }; 
18
    java9SyntaxGuru.java9SyntaxMagic(); 
19
  } 
20
}   
21
 
            
22
abstract class Java5ToJava8Coder<T extends Number> { 
23
  public abstract void java9SyntaxMagic(); 
24
}



Core Library Changes in Java 9

JEP 102: Process API Updates 

With Java 9, one can retrieve the PID of the process through a native call. This is achievable through the ProcessHandle  . Also, we can retrieve information about the currently running Java process and info (inner class of   ProcessHandle) class/object that contains details on the process. We can also enlist or return a snapshot of all currently running processes in the system.

Java
 




xxxxxxxxxx
1
48


 
1
package com.techilashots.java9.features;  
2
 import java.lang.ProcessHandle.Info;  
3
 
           
4
 /**  
5
  * @author sumith.puri  
6
  */  
7
 public class ProcessAPIChanges {  
8
      
9
      public void detailedAPIInfo(ProcessHandle processHandle) {  
10
           
11
           Info processInfo = processHandle.info();  
12
           System.out.println("[Java 9 Developers... Check this Out!]");  
13
           System.out.println("[Detailed Process Info is Provided Below]");  
14
           System.out.println("[Executable Name] " + processInfo.command().get());  
15
           System.out.println("[User Name] " + processInfo.user().get());  
16
           System.out.println("[Start Time] " + processInfo.startInstant().get().toString());  
17
           System.out.println("+++++");  
18
      }
19
  
20
      public static void main(String[] args) {  
21
           
22
           System.out.println("06. Process API Changes (Core Library) ");  
23
           System.out.println("--------------------------------------");  
24
           System.out.println("Check Out the Detailed Process Information in Java 9");  
25
           
26
           ProcessAPIChanges processAPIChanges = new ProcessAPIChanges();  
27
           ProcessHandle processHandle = ProcessHandle.current();  
28
           
29
           System.out.println("With Java 9, Process Id is Available");  
30
           System.out.println("[Current Process Id] " + processHandle.pid());  
31
           System.out.println("-------------------------------------");  
32
           
33
           processAPIChanges.detailedAPIInfo(processHandle);  
34
           
35
           System.out.println("-------------------------------------");  
36
           System.out.println("With Java, You can View all Processes..");  
37
           System.out.println("That are Visible to the Current Process!");  
38
           
39
           ProcessHandle.allProcesses()  
40
            .filter(ph -> ph.info().command().isPresent())  
41
            .limit(4)  
42
            .forEach((process) -> processAPIChanges.detailedAPIInfo(process));  
43
           
44
           System.out.println("");  
45
           System.out.println("================================");  
46
           System.out.println("");  
47
      }  
48
 }  




JEP 277: Enhanced Deprecation


With an eye on maintainable and more informative code, the developer-defined deprecation now allows us to mark deprecation with additional elements of information like forRemoval and since. The forRemoval allows allows to mark that this item may be removed in the future versions of Java and since provides information about when it was first introduced.

Java
 




xxxxxxxxxx
1
19


 
1
package com.techilashots.java9.features;  
2
 
3
 /**  
4
  * @author sumith.puri  
5
  */  
6
 public class EnhancedDeprecation {  
7
      
8
      @Deprecated(forRemoval=true)  
9
      public void methodMarkedForRemoval() {  
10
           System.out.println("Java 9 Allows Enhanced Method Deprecation");  
11
           System.out.println("Invoked Method is Deprecated and Marked [For Removal]");  
12
           this.methodDeprecatedSince();  
13
      }  
14
      
15
      @Deprecated(since="12.2")  
16
      public void methodDeprecatedSince() {  
17
           System.out.println("Invoked Method is Deprecated and Marked [Since]");  
18
      }  
19
 }  



JEP 269: Convenience Factory Methods for Collections 

This addition makes it convenient for the Developer to create Immutable Collections out of existing interfaces, be it Set, Map or List. A static factory method  of() added to Set, Map, and List. It is important you understand the following (even though it'sconsistent with previous versions of Java):

  • They are structurally immutable.
  • They disallow null elements or null keys.
  • They are serializable if all elements are serializable.
  • They reject duplicate elements/keys at creation time.
  • The iteration order of set elements is unspecified and is subject to change.
  • They are value-based. Factories are free to create new instances or reuse existing ones. Therefore, identity-sensitive operations on these instances (reference equality (==), identity hash code, and synchronization) are unreliable and should be avoided. They are serialized as specified on the serialized form page.
Java
 




xxxxxxxxxx
1
18


 
1
 package com.techilashots.java9.features;  
2
 
           
3
 import java.util.Set;  
4
 /**  
5
  * @author sumith.puri  
6
  */  
7
 public class ConvenienceCollections {  
8
      public void checkItOut() {  
9
           System.out.println("Java 9 Introduced a Static [of()] Factory Method");  
10
           System.out.println("This allows Creation of Immutable Collections");  
11
           Set<String> immutableCountrySet = Set.of("America", "Russia", "China", "India");  
12
           try {  
13
                immutableCountrySet.add("England");  
14
           } catch (Exception e) {  
15
                System.out.println("Caught Exception, Adding Entry to Immutable Collection!");   
16
           }  
17
      }   
18
 }  




You may download the code samples for the following new features here. (Import as an Eclipse project, set the compiler/environment as Java 9. Make sure that you have Java 9/JDK 9 installed on your system. Run the main class Java9Application to see the output/outcome of the code samples.)

Check out the Eclipse console output provided below from running the Java9Application (refer attached code samples). Please refer to the individual classes, provided for each of the features to understand the features better. Go ahead, add, modify, delete to experiment with all of the new Java 9 features.

Happy Coding with Java 9!

Further Reading

Thinking of Moving to JDK 9 Next Year? Think Again

Java 9 Modules (Part 1): Introduction


Topics:
core java ,gotcha ,interface ,java 9 ,java se 9 ,jdk 9 ,process api ,skp ,skptrick ,skptricks

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}