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