30 minutes to learn Java8's default methods and static interface methods

  • 2020-06-19 10:17:06
  • OfStack

preface

In the last 30 minute primer on Java8's lambda expressions, we learned about lambda expressions. Now, continuing with the new language features of Java8, today we're going to look at default methods and static interface methods.

This new language feature of es9EN8 is also supported in Android N. For how to configure the Java8 development environment in Android development, see lambda expressions for Java8 in the 30 minute Primer in the previous article.

The default method

The default method allows us to add new methods to the interface of our software library and ensure compatibility with older versions of the code that USES the interface.

Here's a simple example to take a closer look at the default method:

1.1 Day, PM says we need to get time and date for our product. So we wrote an interface class TimeClient that sets and gets the date and time.


 public  interface  TimeClient { 

    void setTime(int hour,int  minute,  int  second); 

    void  setDate( int  day,  int  month,  int  year); 

    void  setDateAndTime( int  day,  int  month,  int  year, 

              int  hour,  int  minute,  int  second); 

    LocalDateTime getLocalDateTime(); 

 } 

And the implementation class for this interface SimpleTimeClient :


public  class  SimpleTimeClient  implements  TimeClient {

    private  LocalDateTime localDateTime;

    public  SimpleTimeClient(){ 

      localDateTime = LocalDateTime.now(); 

    } 

    @Override 

    public  void  setTime( int  hour,  int  minute,  int  second) { 

      LocalTime localTime = LocalTime.of(hour, minute, second); 

      LocalDate localDate = LocalDate.from(localDateTime); 

      localDateTime = LocalDateTime.of(localDate,localTime); 

    } 

 

    @Override 

    public  void  setDate( int  day,  int  month,  int  year) { 

      LocalDate localDate = LocalDate.of(day, month, year); 

      LocalTime localTime = LocalTime.from(localDateTime); 

      localDateTime = LocalDateTime.of(localDate, localTime); 

    } 

 

    @Override 

    public  void  setDateAndTime( int  day,  int  month,  int  year,  int  hour,  int  minute,  int  second) { 

      LocalDate localDate = LocalDate.of(day, month, year); 

      LocalTime localTime = LocalTime.of(hour, minute, second); 

      localDateTime = LocalDateTime.of(localDate, localTime); 

    } 

 

    @Override 

    public  LocalDateTime getLocalDateTime() { 

      return  localDateTime; 

    } 

 

    @Override 

    public  String toString() { 

      return  localDateTime.toString(); 

    } 

 

    public  static  void  main(String[] args) { 

      TimeClient timeClient =  new  SimpleTimeClient(); 

      System.out.println(timeClient.toString()); 

    } 

 } 

But PM said that this product is not only used in China, but also used by customers in other time zones. This adds a new requirement: get the date and time of the specified time zone

We used to do this:

Override the interface to add methods


 public interface TimeClient { 

    void setTime(int hour,int minute,int second); 

    void setDate(int day,int month,int year); 

    void setDateAndTime(int day,int month,int year,int hour, int minute,int second); 

    LocalDateTime getLocalDateTime(); 

    // Additional methods               

    ZonedDateTime getZonedDateTime(String zoneString); 

 }

So our implementation class has to be rewritten accordingly.


 public  class  SimpleTimeClient  implements  TimeClient {

    private  LocalDateTime localDateTime; 

    ... 

    ZonedDateTime getZonedDateTime(String zoneString){ 

     return  ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); 

    }    

    static  ZoneId getZoneId (String zoneString) { 

      try  { 

        return  ZoneId.of(zoneString); 

      }  catch  (DateTimeException e) { 

        System.err.println( "Invalid time zone: "  + zoneString + 

          "; using default time zone instead." ); 

        return  ZoneId.systemDefault(); 

      } 

    }   

  } 

This would cause us to rewrite every class that implements the TimeClient interface. This greatly increased the burden of our implementation requirements.

This is to solve the problem that only abstract methods can be defined in the Java interface. Java8 adds new features for default methods. Let's implement the requirements using the default method.


 public  interface  TimeClient { 

    void  setTime( int  hour,  int  minute,  int  second); 

    void  setDate( int  day,  int  month,  int  year); 

    void  setDateAndTime( int  day,  int  month,  int  year, 

      int  hour,  int  minute,  int  second); 

    LocalDateTime getLocalDateTime();              

    static  ZoneId getZoneId (String zoneString) { 

      try  { 

        return  ZoneId.of(zoneString); 

      }  catch  (DateTimeException e) { 

        System.err.println( "Invalid time zone: "  + zoneString + 

          "; using default time zone instead." ); 

        return  ZoneId.systemDefault(); 

      } 

    } 

    // The default method  

    default  ZonedDateTime getZonedDateTime(String zoneString) { 

      return  ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString)); 

    } 

 } 

The default method keyword is default In the past, we could only define methods in the interface that were declared but not implemented. With the default method, we can write a complete method.

Instead of modifying the implementation class that inherits the interface, we add a new method implementation to the interface.


 public  static  void  main(String[] args) { 

      TimeClient timeClient =  new  SimpleTimeClient(); 

      System.out.println(timeClient.toString()); 

      System.out.println(timeClient.getZonedDateTime( "test" )); 

    } 

Inherit an interface with default methods

When we inherit an interface with default methods, there are generally three situations

Regardless of the default method, the inherited interface inherits the default method directly


 //1. Ignore the default methods  
 public  interface  AnotherTimeClient  extends  TimeClient{ 

 } 

From the following test code, we know that the AnotherTimeClient interface directly inherits the default method of the TimeClient interface, getZonedDateTime


 Method[] declaredMethods = AnotherTimeClient. class .getMethods(); 

      for (Method method:declaredMethods){ 

        System.out.println(method.toString()); 

      }  

 //output: 

 //public default java.time.ZonedDateTime xyz.johntsai.lambdademo.TimeClient.getZonedDateTime(java.lang.String) 

Redeclare the default method, which makes the method abstract


 // Redeclare the default method to make it abstract  

 public  interface  AbstractZoneTimeClient  extends  TimeClient{ 

    @Override 

    ZonedDateTime getZonedDateTime(String zoneString); 

 } 

The test shows that the getZonedDateTime method has changed from the default method to the abstract method:


 Method[] methods = AbstractZoneTimeClient. class .getMethods(); 

      for (Method method:methods){ 

        System.out.println(method.toString()); 

      } 

 //output:    

 //public abstract java.time.ZonedDateTime xyz.johntsai.lambdademo.AbstractZoneTimeClient.getZonedDateTime(java.lang.String) 

Redefine the default method, which causes the method to be overridden


public  class  SimpleTimeClient  implements  TimeClient {

    private  LocalDateTime localDateTime;

    public  SimpleTimeClient(){ 

      localDateTime = LocalDateTime.now(); 

    } 

    @Override 

    public  void  setTime( int  hour,  int  minute,  int  second) { 

      LocalTime localTime = LocalTime.of(hour, minute, second); 

      LocalDate localDate = LocalDate.from(localDateTime); 

      localDateTime = LocalDateTime.of(localDate,localTime); 

    } 

 

    @Override 

    public  void  setDate( int  day,  int  month,  int  year) { 

      LocalDate localDate = LocalDate.of(day, month, year); 

      LocalTime localTime = LocalTime.from(localDateTime); 

      localDateTime = LocalDateTime.of(localDate, localTime); 

    } 

 

    @Override 

    public  void  setDateAndTime( int  day,  int  month,  int  year,  int  hour,  int  minute,  int  second) { 

      LocalDate localDate = LocalDate.of(day, month, year); 

      LocalTime localTime = LocalTime.of(hour, minute, second); 

      localDateTime = LocalDateTime.of(localDate, localTime); 

    } 

 

    @Override 

    public  LocalDateTime getLocalDateTime() { 

      return  localDateTime; 

    } 

 

    @Override 

    public  String toString() { 

      return  localDateTime.toString(); 

    } 

 

    public  static  void  main(String[] args) { 

      TimeClient timeClient =  new  SimpleTimeClient(); 

      System.out.println(timeClient.toString()); 

    } 

 } 

0

implementation HandleInvalidZoneTimeClient The class of the interface will have the overridden getZonedDateTime Methods.

A static method

In the interface of Java8, we can write static methods as well as default methods. The above example is perfect for static methods.


public  class  SimpleTimeClient  implements  TimeClient {

    private  LocalDateTime localDateTime;

    public  SimpleTimeClient(){ 

      localDateTime = LocalDateTime.now(); 

    } 

    @Override 

    public  void  setTime( int  hour,  int  minute,  int  second) { 

      LocalTime localTime = LocalTime.of(hour, minute, second); 

      LocalDate localDate = LocalDate.from(localDateTime); 

      localDateTime = LocalDateTime.of(localDate,localTime); 

    } 

 

    @Override 

    public  void  setDate( int  day,  int  month,  int  year) { 

      LocalDate localDate = LocalDate.of(day, month, year); 

      LocalTime localTime = LocalTime.from(localDateTime); 

      localDateTime = LocalDateTime.of(localDate, localTime); 

    } 

 

    @Override 

    public  void  setDateAndTime( int  day,  int  month,  int  year,  int  hour,  int  minute,  int  second) { 

      LocalDate localDate = LocalDate.of(day, month, year); 

      LocalTime localTime = LocalTime.of(hour, minute, second); 

      localDateTime = LocalDateTime.of(localDate, localTime); 

    } 

 

    @Override 

    public  LocalDateTime getLocalDateTime() { 

      return  localDateTime; 

    } 

 

    @Override 

    public  String toString() { 

      return  localDateTime.toString(); 

    } 

 

    public  static  void  main(String[] args) { 

      TimeClient timeClient =  new  SimpleTimeClient(); 

      System.out.println(timeClient.toString()); 

    } 

 } 

1

Related articles: