Java 8 New Feature with examples part 2

You will learn how to use default interface methods, static interface method, lambda expressions, diamond problem, method references and repeatable annotations etch. At the end of the article you will be familiar with the most recent java 8 API changes like streams, functional interfaces, map extensions and the new Date API. 

8: Streams

java.util.Stream represents a sequence of elements on which one or more operations can be performed. 

Stream operations are divided into intermediate and terminal operations, and are combined to form stream pipelines

Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate.

Terminal operations, such as Stream. After the terminal operation is performed, the stream pipeline is considered consumed, and can no longer be used. if you need to traverse the same data source again, you must return to the data source to get a new stream. 

Sample source data to create stream and parallel stream


import java.util.Arrays;
import java.util.List;

public class Java8Stream {
    public static void main(String[] args) {
        List<StringlistArrays.asList("ram","shyam","bob","roy","aman");
    }
}

Collections in Java 8 are extended so you can simply create streams either by calling Collection.stream() or Collection.parallelStream()

Below are given common stream operation with examples

1. Filter: Filter accepts a predicate to filter all elements of the stream. This operation is intermediate which enables us to call another stream operation (forEach) on the result. ForEach accepts a consumer to be executed for each element in the filtered stream. ForEach is a terminal operation. It’s void, so we cannot call another stream operation.

list.stream().filter(e->e.startsWith("r")).forEach(System.out::println);

// roy, ram

2. Sorted: Sorted is an intermediate operation which returns a sorted view of the stream. The elements are sorted in natural order unless you pass a custom Comparator.

 list.stream().sorted().filter(e->e.startsWith("r")).forEach(System.out::println);
 
// ram, roy

list.stream().sorted().forEach(System.out::println);

// aman, bob, ram, roy, shyam

list.stream().forEach(System.out::println);
// source data untouched in previous sorting and filter operation

// "roy","shyam","bob","ram","aman"

In above example sorting apply two time with filter and without filter to show that sorted does only create a sorted view of the stream without manipulating the ordering and data of the backed collection. The ordering of original source is untouched:

3. Map: Map is an intermediate operation which convert each element into another object by the given function. In below code at first line we are converting each element into toUppercase and printing and second operation we are holding map element into another list.

  list.stream().map(String::toUpperCase).forEach(System.out::println);

// ROY, SHYAM, BOB,RAM, AMAN

 List<Stringhold=list.stream().map(String::toLowerCase).collect(Collectors.toList());

  hold.stream().forEach(System.out::println);

// "roy","shyam","bob","ram","aman"

4. Match: Using Match operation we can check whether a certain predicate match the stream. This operation used for data validation.

boolean check=list.stream().allMatch(e->e.length()>1);
 System.out.println(check); // true

 boolean check1=list.stream().allMatch(e->e.length()>3);
 System.out.println(check1); // false

 boolean check2=list.stream().anyMatch(e->e.length()>3);
 System.out.println(check2); // true

 boolean check3=list.stream().noneMatch(e->e.length()>5);
 System.out.println(check3); // true

5. Count: Count is a terminal operation returning the number of elements in the stream as a long.

long count=list.stream().count();

6. Reduce: This terminal operation performs a reduction on the elements of the stream with the given function. The result is an Optional holding the reduced value.

Optional<StringreduceList=   list.stream().reduce((s1, s2) -> s1.concat(",").concat(s2));
reduceList.ifPresent(System.out::println);
//roy,shyam,bob,ram,aman

8: Parallel Streams: Operations on sequential streams are performed on a single thread while operations on parallel streams are performed concurrent on multiple threads.


list.stream().forEach(e ->
   System.out.println(e + " " + Thread.currentThread().getName())
  );
// output of sequential streaming
roy main shyam main bob main ram main aman main bob main

 list.parallelStream().forEach(e ->
     System.out.println(e + " " + Thread.currentThread().getName())
   );
// Output of parallel streaming
shyam ForkJoinPool.commonPool-worker-1 roy ForkJoinPool.commonPool-worker-2 ram ForkJoinPool.commonPool-worker-1

In above example output you can see.

The output of this sequential stream is predictable. The list elements will always be printed in an ordered sequence.

However, the order of execution is out of our control. It may change every time we run the program.

Note: If you have bigger list then parallel stream will be fast as compare to sequential streaming because the sequential stream work with single thread and parallel work with multi-thread as shown in example.

8: Map: As mentioned maps don’t support streams. Instead maps now support various new and useful methods for doing common tasks.

Given below example to remove duplicate element from array using Map.


import java.util.HashMap;
import java.util.Map;

public class Java8Map {
    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        Integer a[]={2,1,3,4,2,1,5};
        for (int i = 0; i < a.length; i++) {
            map.putIfAbsent(a[i], "val" + a[i]);
        }
        map.forEach((id, val) -> System.out.println(id+"-"+val));

    }
}

The above code should be self-explaining: putIfAbsent prevents us from writing additional if null checks.

In below example we can return default value if not present.

map.get(23); // Null
map.getOrDefault(23,"Not Present");

Another compute method example.

map.computeIfPresent(1,(id, val) -> id+val); // 1val1
map.computeIfAbsent(25,id -> "val"+id); // val25

Next example we can remove from given key and key,value;

map.get(2); // val2
map.remove(2,"val"));  // false
map.remove(2,"val2");  // true

Next merge 

map.merge(2,"concat",(s1, s2) -> s1.concat(s2)); // val2concat

8: Date API:

Java 8 contains a brand new date and time API under the package java.time

Clock:  Clock provides access to the current date and time. Clocks are aware of a timezone.

import java.time.Clock;

public class Java8DateAPI {
    public static void main(String[] args) {
        Clock clock= Clock.systemDefaultZone();
        System.out.println(clock.millis());
        System.out.println(clock.getZone());

    }
}


Timeszones:  Timezones are represented by a ZoneId. They can easily be accessed via static factory methods. Timezones define the offsets which are important to convert between instants and local dates and times.

ZoneId.getAvailableZoneIds(); // This method will return all time zone list
ZoneId.systemDefault().getRules(); // ZoneRules[currentStandardOffset=+05:30]
ZoneId.of("America/Cuiaba").getRules(); // ZoneRules[currentStandardOffset=-04:00]

LocalTime: LocalTime represents a time without a timezone.

LocalTime localTime=LocalTime.now();
System.out.println(localTime); // 17:11:25.260

LocalTime localTime1=LocalTime.now(ZoneId.of("America/Cuiaba"));
System.out.println(localTime1); // 07:41:25.260

LocalTime localTime2=LocalTime.of(23,59,56);
System.out.println(localTime2); // 23:59:56


LocalDate: LocalDate represents a distinct date.  It’s immutable and works exactly analog to LocalTime. The sample demonstrates how to calculate new dates by adding or substracting days, months or years. Keep in mind that each manipulation returns a new instance.


LocalDate today = LocalDate.now(); // 2022-08-05
LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS); // 2022-09-05
LocalDate yesterday = tomorrow.minusDays(1); // 2022-07-05

LocalDate createDate = LocalDate.of(2022, Month.AUGUST, 8);
DayOfWeek dayOfWeek = createDate.getDayOfWeek();
System.out.println(dayOfWeek);  // MONDAY


LocalDateTime: LocalDateTime represents a date and time.  It combines date and time as seen in the above sections into one instance. LocalDateTime is immutable and works similar to LocalTime and LocalDate


LocalDateTime localDateTime = LocalDateTime.now();

localDateTime.getDayOfYear();
localDateTime.getMonth();
localDateTime.getDayOfMonth();
localDateTime.getHour()+":"+localDateTime.getMinute()+":"+localDateTime.getSecond();

8: Annotation:  Java 8 has included two new features repeating and type annotations. It means that annotations can be used anywhere you use a type.

Below are the annotation used example.

@NonNull String str;  
List<@NonNull String> str ;
Arrays<@NonNegative Integer> sort;
@Encrypted File file;
void divideInteger(int a, int b) throws @ZeroDivisor ArithmeticException  



Related Post:

No comments:

Post a Comment