Amazing Java 8 features you need to know Part 2

1. Introduction

In a previous article we discussed several new features introduced in Java 8.

2. Content

In this article we will discuss below features:

  1. Default methods in interface 
  2. Static methods in Interface
  3. Date and Time API
  4. IO APIs. Read here.

Let us get started.

3. Default methods in Interface

Java 8 introduces a concept of Defaults methods. You can add methods with default implementation to interface without breaking existing functionality or implementation of interface. We can provide an implementation to default methods and hence they can be used by concrete class directly.

Below is default method sort in List interface:

default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

You can directly use this method as follows:

class TransactionComparators {
	public static int compareByTime(
					Transaction t1, 
					Transaction t2) {
		return t1.date().compareTo(t2.date());
	}
	public static int compareByAmount(
					Transaction t1, 
					Transaction t2) {
		return t1.amount().compareTo(t2.amount());
	}
}
List<Transaction> transactions = // get List<Transaction>

Comparator<Transaction> TXN_TIME 
      = (t1, t2) -> TransactionComparators.compareByTime(t1, t2);

txns.sort(TXN_TIME);

Comparator<Transaction> TXN_AMOUNT 
      = (t1, t2) -> TransactionComparators.compareByTime(t1, t2);

txns.sort(TXN_AMOUNT);

What’s in it for me?

Good thing about default methods is that we can provide default behavior based on the contract. The advantages are that it is simple to implement and it is backward compatible too. No one needs to change their implementation just because you have added a new method or methods to interface.

4. Static methods in Interface

In addition to default methods, Java 8 allows you to add a public static method in the interface too. Very good example of this is the Comparator interface. It has a plethora of public static methods. Let us take a look at a few of those.

  1. nullsFirst
  2. nullsLast
  3. reverseOrder

4.1 nullsFirst

Let us take an example where we have a List with null elements in it.  In order to sort this List we need to write null safe Comparator. As we are writing null safe comparator we need to provide functionality to nulls elements too i.e. would null elements be ranked lower or higher than non-null elements.

The code would be something like this.

public int compare(T o1, T o2) {
	if (o1 == o2) {
        	return 0;
	}
	if (o1 == null) {
		return (this.nullsLow ? -1 : 1);
	}
	if (o2 == null) {
		return (this.nullsLow ? 1 : -1);
	}
	return o1.compareTo(o2);
}

Before Java 8 this was a goto solution. Spring Framework’s Comparator, Apache Collections Comparators had this functionality in-build so we needn’t write this kind of code. We can just use this library. But now we can use solution provided by Java 8.

We will use default method sort in List interface and provide a Comparator to it.

Using lambda expression :

List<Integer> numbers = Arrays.asList(56, 73, null, 42, 3, 7, null);

numbers.sort(Comparator.nullsFirst((x, y) -> Integer.compare(x,y)));

// expected output
List<Integer> output = Arrays.asList(null, null, 3, 7, 42, 56, 73);

Assert.assertEquals(oupout, numbers);

Using method reference :

List<Integer> numbers = Arrays.asList(56, 73, null, 42, 3, 7, null);

numbers.sort(Comparator.nullsFirst(Integer::compare));

// expected output
List<Integer> output = Arrays.asList(null, null, 3, 7, 42, 56, 73);

Assert.assertEquals(output, numbers);

4.2 nullsLast

If we want to keep nulls at the end of the List we can use nullsLast method.

Using lambda expression :

List<Integer> numbers = Arrays.asList(56, 73, null, 42, 3, 7, null);

numbers.sort(Comparator.nullsLast((x, y) -> Integer.compare(x, y)));

// expected output
List<Integer> output = Arrays.asList(3, 7, 42, 56, 73, null, null);

Assert.assertEquals(output, numbers);

Using method reference :

List<Integer> numbers = Arrays.asList(56, 73, null, 42, 3, 7, null);

numbers.sort(Comparator.nullsLast(Integer::compare));

// expected output
List<Integer> output = Arrays.asList(3, 7, 42, 56, 73, null, null);

Assert.assertEquals(output, numbers);

4.3 reverseOrder

In order to sort the elements of the List in reverse manner we can use a public static method called reverseOrder.

List<Integer> numbers = Arrays.asList(56, 73, 42, 3, 7);

numbers.sort(Comparator.reverseOrder());

// expected output
List<Integer> output = Arrays.asList(73, 56, 42, 7, 3);

Assert.assertEquals(output, numbers);

4.4 Composing comparators

We can compose multiple comparators into one in a fluent manner. Let us take an example, give the List<Integer> with null elements, sort it in reverse manner and push all nulls to the end of the List. 

We first use Comparator.nullsFirst method to make all nulls come first in the sorting strategy. Then we just reverse sort the entire List.

List<Integer> numbers = Arrays.asList(null, 56, null, 73, 42, 3, 7);

Comparator<Integer> nullsFirst 
	= Comparator.nullsFirst(Integer::compare);

Comparator<Integer> reversedNullsFirst = nullsFirst.reversed();

numbers.sort(reversedNullsFirst);

// expected output
List<Integer> output = Arrays.asList(73, 56, 42, 7, 3, null, null);

Assert.assertEquals(output, numbers);

What’s in it for me?

You can write several helper methods in the interface itself. 

5. Date and Time APIs

Date apis is a big improvement in Java 8. java.util.Date is a mutable class. No idea why it was designed that way. It represents a value and values must be immutable. But now in Java 8 the Date apis goes to a next level.

Let us just take an example first. I am in PST time zone i.e. America/Los_Angeles.

LocalDateTime localDateTime = LocalDateTime.now();
// prints 2020-06-17T14:22:35.271

LocalDateTime gets the date and time based on your time zone. Don’t use this api where other time zones are needed. 

Few more examples

LocalDateTime localDateTime = LocalDateTime.now();

LocalDate localDate = localDateTime.toLocalDate();

localDateTime.toString(); // 2020-06-17T14:25:41.776

localDate.getDayOfMonth(); // 17

localDate.getDayOfYear(); // Prints 169

localDate.getDayOfWeek(); // WEDNESDAY

localDate.getMonth(); // JUNE 

There are many things we can do with this API such as create new LocalDate using year, month and date.

LocalDate localDate = LocalDate.of(2020, Month.MAY, 12);
localDate.toString(); // 2020-05-12

Zoned Date and Time : Date time according to time zone can be obtained by the ZonedDateTime class. Let us take a look at it with few examples.

Get system default time zone.

ZonedDateTime zonedDateTime = ZonedDateTime.now(); 
// 2020-06-17T14:35:52.223-07:00[America/Los_Angeles]

Parse the time zone of America/Chicago by providing the date and time.

ZonedDateTime newZone = ZonedDateTime.parse(
			"2020-08-20T12:30:56.223-07:00[America/Chicago]");
// prints 2020-08-20T12:30:56.223-07:00[America/Chicago]

Create a new ZoneId using a time zone.

ZoneId zoneId = ZoneId.of("America/Chicago");

String id = zoneId.getId(); // America/Chicago

ZoneRules zoneRules = zoneId.getRules(); 
// ZoneRules[currentStandardOffset=-06:00]

int size = ZoneId.getAvailableZoneIds().size(); // 589  

ZoneRules zoneRules = ZonedDateTime.now().getZone().getRules();
// ZoneRules[currentStandardOffset=-08:00]

ZoneRules zoneRules = ZoneId.of("Europe/London").getRules();
// ZoneRules[currentStandardOffset=Z]

6. IO APIs

For IO APIs you can read about Files class IO APIs. The linked article explains new methods introduced in Java 8. Read here.

7. Conclusion

This article describes several different exciting features of Java 8. In next article we will take a look at passing code as behavior in details which will be followed by detailed article on lambda expression.

Leave a Reply

Your email address will not be published. Required fields are marked *