Tuesday, September 18, 2018

Java SE 9... What's New? [Code Samples - 01/02]

As I had promised, albeit very late, 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'


00. Default Interface Methods
Whenever there is existing or legacy code which has Interfaces that require addition of new methods - It causes breakage of existing classes that inherit/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 a good practice as per 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.

01: import java.util.List;  
02:    
03:  public interface LegacyPublicInterface {  
04:        
05:        
06:      /**  
07:       * Additional Default Method that Can be Invoked on Each Type of Invoice that Implements the LegacyPublicInterface.   
08:       * It can also be over-ridden by the Extending Invoice Types. This is an Example Usage and Benefit of the Java/JDK 8  
09:       * Default Interface feature.  
10:       * @param items  
11:       */  
12:      default void checkStatusOnEachItem (List<String>... items) {  
13:        
14:          for(String item : items) {  
15:              if(item.startsWith("OOS_")) {  
16:                  items.remove(item);  
17:              }  
18:          }  
19:          return;  
20:      }  
21:    
22:  }  
23:    


From the Example Above, the LegacyPublicInterface in an Existing Application is already extended by Multiple Invoice Types (For Example in an Inventory System). But as per changing business, 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 thus feature of Default Methods, the following 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. 


A. Java Language Changes in JDK 9

[01] 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 modifier 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.

 package com.techilashots.java9.features;  
 
/**  
  * @author sumith.puri  
  *   
  * prior to java 8, the default scope/visibilty of every method in an interface was same  
  * the attributes were all by default, [public static final] and the methods were [public]  
  * with java 8, [default] interface methods have been introduced but so has been a new scope/visibility  
  * with java 9, interface can have private visibility methods that can be used internally   
  */  
 public interface Java9PrivateMethodInterface {  

      public void preJava9BusinessMethodOne();  

      public void preJava9BusinessMethodTwo();  

      public default void newJava9BusinessMethodThree() {  
           System.out.println("Interface Methods can call Private Interface Methods!");  
           System.out.println("");  
           java9BusinessMethodThreeHelper();  
      }  

      private void java9BusinessMethodThreeHelper() {  
           System.out.println("Default Methods... Now Private Methods!");  
           System.out.println("Once Upon a Time, I was a Java Developer!");  
      }  
 }  


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

      //new features of java 9  
      //private interface methods  
      private void privateInterfaceMethod() {  

           System.out.println("01. Private Interface Methods");  
           System.out.println("-----------------------------");  
           System.out.println("[Private Interface Method Invoked by Default Interface Method]");  
           Java9PrivateMethodInterface java9PrivateMethodInterface = new Java9PrivateMethodInterface() {  
                @Override  
                public void preJava9BusinessMethodTwo() {  
                     // TODO Auto-generated method stub  
                }  
                @Override  
                public void preJava9BusinessMethodOne() {  
                     // TODO Auto-generated method stub  
                }  
           };  

           java9PrivateMethodInterface.newJava9BusinessMethodThree();  
           System.out.println("");  
           System.out.println("================================");  
           System.out.println("");  
      }  


[02] 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 causing compilation failure only in Java 1.9). This may cause a some issues when compiling legacy source code, especially which had a necessity to denote some specific resource or entity using the _ (underscore).  It may have to be rewritten and may have many related ramifications.
 /**  
  * @author sumith.puri  
  *  
  */  
 public class Java9VariableNaming {  
      // pre-java 9, this was a valid variable name  
      // from java 8, _ was marked as a reserved keyword (compiler warning) 
      // from java 9, the following line of code will cause compilation failure  
      // private String _;  
      private String _socket = null;  
      /**  
       * @param args  
       */  
      public void notForDemoMethod() {  
           _socket = new String("Network Socket");  
           System.out.println("_ is no Longer a Valid Variable Name!, [Variable Value: " + _socket + "]");            
      }  
 }  


[03] Allow Effectively final variables to be used as Resources in Try with Resources
Upto Java 8, Every variable that had to be used within Try with Resources statements requires to be declared within the try statement. Only then, can it be used within the try block. This is a limitation for th 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 that is not changed once after it has been initialized.

 package com.techilashots.java9.features; 

 import java.io.BufferedReader;  
 import java.io.File;  
 import java.io.FileReader;  
 import java.io.IOException;  
 
 /**  
  * @author sumith.puri  
  */  
 public class EffectivelyFinalTryResources {  
 
     private static File file = new File("try_resources.j9");   

      //with java 9, you need to use either explicitly final or effectively final variables in try/resources  
      public void methodWithAnomaly() throws IOException {  

           file.createNewFile();  
           BufferedReader bufferedReader = new BufferedReader(new FileReader(file));  
       
           //prior to java 9, the usage would look like this  
           //try (final BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {  
           //this code will not compile before java 9  
           try (bufferedReader) {            
                System.out.println("Can Use Final or Effectively Final in Try with Resources!");  
           } finally {  
                System.out.println("Java 9 Gives More Flexibility to Developers.");  
           }            
      }  
 }  


[04] @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:

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

Hence @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.
 package com.techilashots.java9.features;  

 /**  
  * @author sumith.puri  
  */  
 public class SafeVarargsOnPrivateMethod {  

      public void demoSafeVarargsInJava9() {  
           safeVarargsInJava9(24.00f, 03, 19, 82);  
      }  

      @SafeVarargs  
      private void safeVarargsInJava9 (Float a, Integer...b) {  
           System.out.println("Invoked a Private Instance Method with " + a + ", " + b[0] + ", " + b[1] + ", " + b[2]);  
           System.out.println("With Java 9, @SafeVarargs is Allowed on Private Instance Methods!");  
      }  
 }  


[05] Allow Diamond with Anonymous Classes If Inferred Type's Argument Type is Denotable
Upto Java 8, using Generics and Diamond Operators with Anonymous Classes. It 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, 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.


 package com.techilashots.java9.features;  
 /**  
  * @author sumith.puri  
  */  
 public class DiamondOperatorOnAnonymous {  
      public void diamondForInferredDenotable() {  
           //prior to java 9, anonymous inner classes were not allowed to use diamond operator  
           Java5ToJava8Coder<? extends Number> java9SyntaxGuru = new Java5ToJava8Coder<>() {  
                     @Override  
                     public void java9SyntaxMagic() {  
                          System.out.println("Introduced in Java 5, Generics was Intriguing and Complex!");  
                          System.out.println("With Java 9, Diamond Operator On Anonymous Classes is Allowed...");  
                          System.out.println("As Long as Java 9 Infers the Type (Inferred) to be Denotable.");  
                     }  
           };  
           java9SyntaxGuru.java9SyntaxMagic();  
      }  
 }  
 abstract class Java5ToJava8Coder<T extends Number> {  
       public abstract void java9SyntaxMagic();  
 }


B. Core Library Changes in Java 9

[06] 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 (JVM) 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.
 package com.techilashots.java9.features;  
 import java.lang.ProcessHandle.Info;  

 /**  
  * @author sumith.puri  
  */  
 public class ProcessAPIChanges {  
      
      public void detailedAPIInfo(ProcessHandle processHandle) {  
           
           Info processInfo = processHandle.info();  
           System.out.println("[Java 9 Developers... Check this Out!]");  
           System.out.println("[Detailed Process Info is Provided Below]");  
           System.out.println("[Executable Name] " + processInfo.command().get());  
           System.out.println("[User Name] " + processInfo.user().get());  
           System.out.println("[Start Time] " + processInfo.startInstant().get().toString());  
           System.out.println("+++++");  
      }
  
      public static void main(String[] args) {  
           
           System.out.println("06. Process API Changes (Core Library) ");  
           System.out.println("--------------------------------------");  
           System.out.println("Check Out the Detailed Process Information in Java 9");  
           
           ProcessAPIChanges processAPIChanges = new ProcessAPIChanges();  
           ProcessHandle processHandle = ProcessHandle.current();  
           
           System.out.println("With Java 9, Process Id is Available");  
           System.out.println("[Current Process Id] " + processHandle.pid());  
           System.out.println("-------------------------------------");  
           
           processAPIChanges.detailedAPIInfo(processHandle);  
           
           System.out.println("-------------------------------------");  
           System.out.println("With Java, You can View all Processes..");  
           System.out.println("That are Visible to the Current Process!");  
           
           ProcessHandle.allProcesses()  
            .filter(ph -> ph.info().command().isPresent())  
            .limit(4)  
            .forEach((process) -> processAPIChanges.detailedAPIInfo(process));  
           
           System.out.println("");  
           System.out.println("================================");  
           System.out.println("");  
      }  
 }  


[07] 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.


 package com.techilashots.java9.features;  
 
 /**  
  * @author sumith.puri  
  */  
 public class EnhancedDeprecation {  
      
      @Deprecated(forRemoval=true)  
      public void methodMarkedForRemoval() {  
           System.out.println("Java 9 Allows Enhanced Method Deprecation");  
           System.out.println("Invoked Method is Deprecated and Marked [For Removal]");  
           this.methodDeprecatedSince();  
      }  
      
      @Deprecated(since="12.2")  
      public void methodDeprecatedSince() {  
           System.out.println("Invoked Method is Deprecated and Marked [Since]");  
      }  
 }  
 
 

[08] 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 each of the interfaces - Set, Map and List. It is important you understand the following (even though consistent 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.
 package com.techilashots.java9.features;  
 import java.util.Set;  
 /**  
  * @author sumith.puri  
  */  
 public class ConvenienceCollections {  
      public void checkItOut() {  
           System.out.println("Java 9 Introduced a Static [of()] Factory Method");  
           System.out.println("This allows Creation of Immutable Collections");  
           Set<String> immutableCountrySet = Set.of("America", "Russia", "China", "India");  
           try {  
                immutableCountrySet.add("England");  
           } catch (Exception e) {  
                System.out.println("Caught Exception, Adding Entry to Immutable Collection!");   
           }  
      }   
 }  


You may Download the Code Samples for the following New Features Here. (Import as 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.

 Sample of New Features of Java 9  
 ================================  
   
 00. Default Interface Methods  
 -----------------------------  
 [Already Integrated Java Service - Default Implementation]  
 Core Business Method One  
 Core Business Method Two  
 Java 8 Changed the Definition of Interface Forever!  
 Thou shall not clear the Basic Core Java Interview  
   
 [Newly Integrated Java Service - Override Default Implementation]  
 Core Business Method One  
 Core Business Method Two  
 Attention - All Java Developers - Default Interfaces  
 The World is now a Newer Place from Java 8!  
   
 ================================  
   
 01. Private Interface Methods  
 -----------------------------  
 [Private Interface Method Invoked by Default Interface Method]  
 Interface Methods can call Private Interface Methods!  
   
 Default Methods... Now Private Methods!  
 Once Upon a Time, I was a Java Developer!  
   
 ================================  
   
 02. Underscore Variable Naming  
 -----------------------------  
 [Nothing to Demonstrate - Refer Code for New Rule]  
 _ is no Longer a Valid Variable Name!, [Variable Value: Network Socket]  
   
 ================================  
   
 03. Effectively Final Try with Resources  
 ----------------------------------------  
 [Nothing to Demonstrate - Refer Code for New Rule]  
 Can Use Final or Effectively Final in Try with Resources!  
 Java 9 Gives More Flexibility to Developers.  
   
 ================================  
   
 04. Safe Varargs on Private Method  
 ----------------------------------  
 [Nothing to Demonstrate - Refer Code for New Rule]  
 Invoked a Private Instance Method with 24.0, 3, 19, 82  
 With Java 9, @SafeVarargs is Allowed on Private Instance Methods!  
   
 ================================  
   
 05. Diamond on Anonymous Classes   
 --------------------------------  
 [Nothing to Demonstrate - Refer Code for New Rule]  
 Introduced in Java 5, Generics was Intriguing and Complex!  
 With Java 9, Diamond Operator On Anonymous Classes is Allowed...  
 As Long as Java 9 Infers the Type (Inferred) to be Denotable.  
   
 ================================  
   
 06. Process API Changes (Core Library)   
 --------------------------------------  
 Check Out the Detailed Process Information in Java 9  
 With Java 9, Process Id is Available  
 [Current Process Id] 1380  
 -------------------------------------  
 [Java 9 Developers... Check this Out!]  
 [Detailed Process Info is Provided Below]  
 [Executable Name] C:\Users\U074SXP\Documents\My Installed\jdk-9.0.4\bin\javaw.exe  
 [User Name] CWT\U074SXP  
 [Start Time] 2018-09-18T00:21:57.354Z  
 +++++  
 -------------------------------------  
 With Java, You can View all Processes..  
 That are Visible to the Current Process!  
 [Java 9 Developers... Check this Out!]  
 [Detailed Process Info is Provided Below]  
 [Executable Name] C:\Windows\System32\taskhost.exe  
 [User Name] CWT\U074SXP  
 [Start Time] 2018-09-17T22:39:11.949Z  
 +++++  
 [Java 9 Developers... Check this Out!]  
 [Detailed Process Info is Provided Below]  
 [Executable Name] C:\Program Files\Microsoft Application Virtualization\Client\AppVStreamingUX.exe  
 [User Name] CWT\U074SXP  
 [Start Time] 2018-09-17T22:39:11.996Z  
 +++++  
 [Java 9 Developers... Check this Out!]  
 [Detailed Process Info is Provided Below]  
 [Executable Name] C:\Program Files (x86)\Symantec\Symantec Endpoint Protection\12.1.7004.6500.105\Bin\ccSvcHst.exe  
 [User Name] CWT\U074SXP  
 [Start Time] 2018-09-17T22:39:12.074Z  
 +++++  
 [Java 9 Developers... Check this Out!]  
 [Detailed Process Info is Provided Below]  
 [Executable Name] C:\Program Files\Synaptics\SynTP\SynTPEnh.exe  
 [User Name] CWT\U074SXP  
 [Start Time] 2018-09-17T22:39:12.214Z  
 +++++  
   
 ================================  
   
 07. Enhanced Deprecation  
 ------------------------  
 [Nothing to Demonstrate - Refer Code for New Rule]  
 Java 9 Allows Enhanced Method Deprecation  
 Invoked Method is Deprecated and Marked [For Removal]  
 Invoked Method is Deprecated and Marked [Since]  
   
 ================================  
   
 08. Convenience Collection Method  
 ---------------------------------  
 [Nothing to Demonstrate - Refer Code for New Rule]  
 Java 9 Introduced a Static [of()] Factory Method  
 This allows Creation of Immutable Collections  
 Caught Exception, Adding Entry to Immutable Collection!  
   
 ================================  


Happy Coding with Java 9!

No comments: