What is new in Java 9

Java 9 is a major feature release. The following summarizes features and enhancements in Java  language version 9.

  • Allow @SafeVargs annotation on private instance methods
  • Allow final variables to be used as resources in the try-with-resources statement
  • Allow the use of diamond with anonymous classes if the type of the inferred type is denotable.
  • Complete the removal of underscore from the set of legal identifier names. This was started in java version 8.
  • Add support for private interface methods.

Reference : https://docs.oracle.com/javase/9/language/toc.htm#JSLAN-GUID-16A5183A-DC0D-4A96-B9D8-AAC9671222DD

Example of replacing anonymous inner class by a Lambda expression in Java 8

One  of the facilities that Java 8 offers is the reduction of the numbers of lines of code in some situations. In this example, we will replace an anonymous inner class by a Lamba Expression. Reducing the code used to compare two players to almost one single line.

First of all, we will need a Player object. A player has a name and a score. Please note that we will use the Integer wrapper type instead of the primitive int type, in order to benefit from the compareTo method offered by the Integer object.

package com.tutoref;

public class Player {
 
 private String name;
 private Integer score;
 
 // Default constructor to allow instanciation without parameters
 public Player(){}
 
 // Constructor with parameters
 public Player(String name, int score){
  this.name = name;
  this.score = score;
 }
 
 public String getName() {
  return name;
 }
 
 public void setName(String name) {
  this.name = name;
 }
 
 public Integer getScore() {
  return score;
 }
 
 public void setScore(Integer score) {
  this.score = score;
 }
 
 
 @Override
 public String toString() {
  // To customise the displaying of a player
  return "[name : "+this.name+", score : "+this.score+"]";
 }
}

 

Comparison using an anonymous inner class

The playerComparator inner class is used to tell the program how to compare two players, based on their score.

In this example we create the playerComparator of type Coparator<Player>, after that create and add some players to the ListArray collection, then we use the Collections.sort method ot sort the players based on their score.

package com.tutoref;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class PlayerSort {

 public static void main(String[] args) {
  
  // Create a comparator object
  Comparator<Player> playerComparator = new Comparator<Player> () {
   @Override
   public int compare(Player player1, Player player2) {
    return player1.getScore().compareTo(player2.getScore());
   }
  };
  
  
  // Create a list of players
  List<Player> playerList = new ArrayList<Player>();
  
  // add some players
  playerList.add(new Player("Messi",500));
  playerList.add(new Player("Ronaldo",750));
  playerList.add(new Player("Roberto",900));
  playerList.add(new Player("Albert",450));
  playerList.add(new Player("Michel",750));
  playerList.add(new Player("Mario",750));
  
  // Sort the list based on the score 
  // using the comparator object
  Collections.sort(playerList,playerComparator);
  
  // display the sorted list of players (in ascendant order)
  System.out.println(playerList);
 }

}

 

COMPARISON Using Lambda Expression

This example will replace the  anonymous inner class, reducing it to one line of code.

package com.tutoref;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class PlayerSortUsingLambdaExp {

 public static void main(String[] args) {
  
  // Create a list of players
  List<Player> playerList = new ArrayList<Player>();
  
  // add some players
  playerList.add(new Player("Messi",500));
  playerList.add(new Player("Ronaldo",750));
  playerList.add(new Player("Roberto",900));
  playerList.add(new Player("Albert",450));
  playerList.add(new Player("Michel",750));
  playerList.add(new Player("Mario",750));
  
  Collections.sort(playerList, (p1, p2) -> p1.getScore().compareTo(p2.getScore()) );
  
  // display the sorted list of players (ascendent order)
  System.out.println(playerList);
 }

}

The compactor interface is also a Functional Interface, this is why it can be replaced by a lambda expression. You can imagine that we passed the function making the comparison as parameter.

Example of a Functional Interface

Also called a SAM (Single Abstract Method). An FI is an interface containing :

  • One and only one abstract method;
  • Zero or many static methods
  • Zero or many default methods

There are many built-in functional interfaces included in Java 8. The Predicate FI is one of them.

Here is an example of a functional interface :

@FunctionalInterface
interface MostBasicFi{
   boolean test();

   // a static method
   public static void foo1(){
    // add some logic...
   }

   // a default method
   public static void foo2(){
    // add some logic...
   }
   
}

 

 

Array Example in Java 8

Declaring and instantiating an array

// declaration and instanciation
String [] oneDimentionArray = new String[10];
String [][] multiDimentionArray = new String[10][];
String [][] multiDimentionArray2 = new String[10][20];

Note that you can also put the square brackets after the variable name :

// Brackets after the variable name
String oneDimentionArray[] = new String[10];

 

Affecting values to an array (Initialisation)

// One dimension array
oneDimentionArray[0]="Value 1";
oneDimentionArray[2]="Value 2";

// two dimension array
multiDimentionArray[0][1] = "An other value";

Trying to access oneDimentionArray[1] will throw the ArrayOutOfBoundsException as it was not set.

Declaring and initialization

When creating arrays of Objects (and not primitives) , you can use curly brackets to initialize you array with the values this way :

String [] array = new String [] {"A", "B", "C"};

 

Iterating trough arrays

To read array values you can read a specific index :

System.out.println("Cell 0 value : "+myTable[0]);

You can also iterate through the array using the old for loop:

for(int i = 0 ; i < myTable.lenght ; i++){
  System.out.println(myTable[i]);
}

Or the new enhanced for loop :

// we suppose that myArray is an array of Strings
for(String value: myArray){
   System.out.println(value)
}

Please note that you can find other ways of iterating through arrays.

Java Enum example

The enum type in java is a special data type that enables a variable to be set to one of a predefined set of values.

An enum can be in its own file (example: Directions.java) or included in an other class.

Example of a simple enum

enum Directions {
   NORTH, SOUTH, EAST, WEST 
}

A more elaborated example

enum Directions{
     NORTH("N"),
     SOUTH("S"),
     EAST("E"),
     WEST("W");
     // the ; after the fields is needed
     
     private final String symbol;
     
     Directions(String symbol){
      this.symbol=symbol;
     }
     
     public String symbol(){
      return this.symbol;
     }
}

 The use of an enum

Directions direction = Directions.EAST;

//...

switch(direction){
  case EAST:
   System.out.println("EAST");
   break;
  case SOUTH:
   System.out.println("SOUTH");
   break;
  case NORTH:
   System.out.println("NORTH");
   break;
  case WEST:
   System.out.println("WEST");
   break;
   
   default:
}

The above code will print the following:

EAST

 

log4j.properties example

The following example will show how redirect log outpout to Console, a file and both.

This configuration should be writen in log4j.properties file.

 

write the log in the console

# Logger options
log4j.rootLogger=INFO, stdout

# Write the log to the standard output
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

 

write the log in a file

# Logger options
log4j.rootLogger=INFO, file
log4j.appender.file=org.apache.log4j.RollingFileAppender

# Write the log to a file
log4j.appender.file.File=/var/logs/log.log
log4j.appender.file.MaxFileSize=50MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

 

write the log in both console and a file

# Logger options
log4j.rootLogger=INFO, file, stdout
log4j.appender.file=org.apache.log4j.RollingFileAppender

# Write the log to the standard output
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

# Write the log to a file
log4j.appender.file.File=/var/logs/log.log
log4j.appender.file.MaxFileSize=50MB
log4j.appender.file.MaxBackupIndex=10
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n