Explain the new features of Java 8 in detail

Tips before viewing:

The IDEA version used in this article is ultimate 2019.1, and the JDK version is 1.8.0_141.

1 Introduction

Java8, also known as jdk1.8, was released by Oracle Corporation on March 18, 2014 under the name Spider.

2. New Features

  1. Lambda expressions
    Lambda allows functions to be passed as parameters to a method (functions are passed as parameters to methods).

  2. method reference
    Method references provide a very useful syntax for directly referencing methods or constructors of existing Java classes or objects (instances). Used in conjunction with Lambda, method references can make language constructs more compact and concise, reducing redundant code.

  3. functional interface
    A functional interface is an interface that has one and only one abstract method, but can have multiple non-abstract methods.

  4. default method
    A default method is a method that has an implementation in an interface.

  5. Stream API
    The newly added Stream API (java.util.stream) brings a true functional programming style to Java.

  6. Optional class
    The Optional class has become part of the Java 8 class library to resolve null pointer exceptions.

  7. Nashorn, JavaScript engine
    Java 8 provides a new Nashorn javascript engine that allows us to run specific javascript applications on the JVM.

  8. Date Time API
    Strengthen the handling of date and time.

  9. Base64
    Java 8 has built-in encoders and decoders for Base64 encoding.

2.1 Lambda expressions

Lambda s allow functions to be passed as parameters to a method (functions are passed into methods as parameters).

2.1.1 Syntax

(parameters) -> expression
 or
(parameters) -> { statements; }

2.1.2 Important Features

  1. Optional type declaration: There is no need to declare the parameter type, the compiler can uniformly identify the parameter value.

  2. Optional parameter parentheses: One parameter does not need to define parentheses, but multiple parameters need to define parentheses.

  3. Optional curly braces: If the body contains a statement, curly braces are not required.

  4. Optional return keyword: If the body has only one return value from the expression, the compiler will automatically return the value. The braces need to specify that the expression returns a value.

2.1.3 Examples

package testJava8;

public class TestLambda {
    public static void main(String[] args) {
        // declare type, no braces, no return keyword
        MathOperation addition = (int a, int b) -> a + b;
        // declare type, with curly braces, with return keyword
        MathOperation subtraction = (int a, int b) -> {return a - b;};
        // No type declaration, no braces, no return keyword
        MathOperation multiplication = (a, b) -> a * b;
        // No type declaration, curly brackets, return keyword
        MathOperation division = (a, b) -> {return a / b;};

        System.out.println(" 4 + 2 = " + addition.operate(4,2));
        System.out.println(" 4 - 2 = " + subtraction.operate(4,2));
        System.out.println(" 4 * 2 = " + multiplication.operate(4,2));
        System.out.println(" 4 / 2 = " + division.operate(4,2));
    }

    interface MathOperation{
        int operate(int a, int b);
    }
}

The running result is as follows

2.1.4 Note

  1. A lambda expression can only refer to outer local variables marked final, which means that local variables defined outside the domain cannot be modified inside the lambda, otherwise a compilation error will occur.
    The local variables of a lambda expression may not be declared final, but they must not be modified by subsequent code (that is, implicitly have final semantics)

  2. It is not allowed to declare a parameter or local variable with the same name as a local variable in a Lambda expression.

2.2 Method reference

A method reference refers to a method by its name.

Method references can make language constructs more compact and concise, reducing redundant code.

Method references use a pair of colons :: .

2.2.1 Syntax

  1. Constructor reference: Class::new

  2. Static method reference: Class::static_method

  3. A method reference to an arbitrary object of a specific class: Class::method

  4. Method reference for a specific object: instance::method

2.2.2 Examples

package testJava8;

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

public class TestMethodReference {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        // static method reference
        list.forEach(System.out::println);
    }
}

operation result

2.3 Functional interface

A functional interface is an interface that has one and only one abstract method, but can have multiple non-abstract methods.

Functional interfaces can be implicitly converted to lambda expressions.

2.3.1 Definition and Implementation

@FunctionalInterface
interface FunctionalInterface {
    void doSomething(String param);
}

Using Lambda Expressions to Implement Interfaces

FunctionalInterface functionalInterface -> System.out.println("Param : " +  param);

2.3.2 Existing functional interfaces

Functional interfaces available prior to JDK 1.8:

  1. java.lang.Runnable

  2. java.util.concurrent.Callable

  3. java.security.PrivilegedAction

  4. java.util.Comparator

  5. java.io.FileFilter

  6. java.nio.file.PathMatcher

  7. java.lang.reflect.InvocationHandler

  8. java.beans.PropertyChangeListener

  9. java.awt.event.ActionListener

  10. javax.swing.event.ChangeListener

Newly added functional interfaces in JDK 1.8:

  1. java.util.function

2.4. Default method

The default method is that interfaces can have implementation methods, and implementing classes are not required to implement their methods.

A default method can be implemented simply by prefixing the method name with the default keyword.

2.4.1 Syntax

default method

public interface DefaultFunctionInterface {
   default void doSomething(){
      System.out.println("...");
   }
}

static default method

public interface DefaultFunctionInterface {
   static void doSomething(){
      System.out.println("...");
   }
}

2.4.2 Examples

package testJava8;

public class TestDefaultFunction {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.print();
    }
}

interface Animal{
    default void print(){
        System.out.println("this is an animal");
    }

    static void say(){
        System.out.println("animal called");
    }
}

class Dog implements Animal{
    public void print(){
        Animal.super.print();
        Animal.say();
    }
}

Test Results

2.5 Stream API

Stream s provide a high-level abstraction over Java collection operations and representations in an intuitive way similar to querying data from a database using SQL statements.

Stream is a queue of elements from a data source and supports aggregation operations

  1. Elements are objects of a specific type that form a queue. Stream s in Java do not store elements, but compute on demand.

  2. Data Source The source of the stream. Can be a collection, an array, an I/O channel, a generator, etc.

  3. Aggregation operations Similar operations to SQL statements, such as filter, map, reduce, find, match, sorted, etc. Unlike previous Collection operations, Stream operations have two basic characteristics:

  4. Pipelining: Intermediate operations return the stream object itself. This way multiple operations can be concatenated into a pipeline, as in fluent style. Doing so allows optimizations for operations such as laziness and short-circuiting.

  5. Internal iteration: Previously, the collection traversal was performed by Iterator or For-Each, which explicitly iterated outside the collection, which was called external iteration. Stream provides an internal iteration method, which is implemented through the visitor pattern (Visitor).

The stream of elements is processed by intermediate operation s in the pipeline, and finally the result of the previous processing is obtained by the terminal operation.

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect|
+--------------------+       +------+   +------+   +---+   +-------+

The above process is converted to Java code as:

List<Integer> transactionsIds = 
widgets.stream()
             .filter(b -> b.getColor() == RED)
             .sorted((x,y) -> x.getWeight() - y.getWeight())
             .mapToInt(Widget::getWeight)
             .sum();

2.5.1 Generating Streams

There are two ways to implement streams

  1. stream() − Creates a serial stream for the collection.

  2. parallelStream() − Creates a parallel stream for the collection.

package testJava8;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class TestStream {
    public static void main(String[] args) {
        List<String> strList = Arrays.asList("abcd", "123", "cde", "b456", "", "ghj");
        // stream
        List<String> notNullList = strList.stream().filter(str -> !str.isEmpty()).collect(Collectors.toList());
        System.out.println(notNullList.toString());
    }
}

The result is

2.5.2 forEach

Stream provides the method 'forEach' to iterate over each data in the stream.

package testJava8;

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

public class TestStream {
    public static void main(String[] args) {
        List<String> strList = Arrays.asList("abcd", "123", "cde", "b456", "", "ghj");
        // forEach
        strList.forEach(System.out::println);
    }
}

The result is

2.5.3 map

The map method is used to map each element to the corresponding result

package testJava8;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class TestStream {
    public static void main(String[] args) {
        List<String> strList = Arrays.asList("abcd", "123", "cde", "b456", "", "ghj");
        // map
        List newList = strList.stream().map(str -> str + "i").collect(Collectors.toList());
        System.out.println(newList.toString());
    }
}

The result is

2.5.4 filter

The filter method is used to filter out elements by the set conditions.

package testJava8;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class TestStream {
    public static void main(String[] args) {
        List<String> strList = Arrays.asList("abcd", "123", "cde", "b456", "", "ghj");
        // filter
        List<String> notNullList = strList.stream().filter(str -> !str.isEmpty()).collect(Collectors.toList());
        System.out.println(notNullList.toString());
    }
}

The result is

2.5.5 limit

The limit method is used to get the specified number of streams.

package testJava8;

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

public class TestStream {
    public static void main(String[] args) {
        List<String> strList = Arrays.asList("abcd", "123", "cde", "b456", "", "ghj");
        // limit
        strList.stream().limit(3).forEach(System.out::println);
    }
}

The result is

2.5.6 sorted

The sorted method is used to sort the stream.

package testJava8;

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

public class TestStream {
    public static void main(String[] args) {
        List<String> strList = Arrays.asList("abcd", "123", "cde", "b456", "", "ghj");
        // sort
        strList.stream().sorted().forEach(System.out::println);
    }
}

The result is

2.5.7 parallel Programs

parallelStream is an alternative to stream parallel handlers.

package testJava8;

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

public class TestStream {
    public static void main(String[] args) {
        List<String> strList = Arrays.asList("abcd", "123", "cde", "b456", "", "ghj");
        // parallelStream
        long count = strList.parallelStream().filter(str -> !str.isEmpty()).count();
        System.out.println(count);
    }
}

The result is

2.5.8 Collectors

The Collectors class implements many reduction operations, such as converting streams into sets and aggregating elements.

package testJava8;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class TestStream {
    public static void main(String[] args) {
        List<String> strList = Arrays.asList("abcd", "123", "cde", "b456", "", "ghj");
        // Collectors
        List<String> notNullList = strList.stream().filter(str -> !str.isEmpty()).collect(Collectors.toList());
        System.out.println(notNullList.toString());
        String merge = strList.stream().filter(str -> !str.isEmpty()).collect(Collectors.joining(", "));
        System.out.println(merge);
    }
}

The result is

2.5.9 Statistics

package testJava8;

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

public class TestStream {
    public static void main(String[] args) {
        // stats
        List<Integer> numberList = Arrays.asList(3, 8, 6, 7, 2, 9, 1);
        IntSummaryStatistics statistics = numberList.stream().mapToInt(x -> x).summaryStatistics();
        System.out.println("Maximum number:" + statistics.getMax());
        System.out.println("Minimum number:" + statistics.getMin());
        System.out.println("Average:" + statistics.getAverage());
        System.out.println("and:" + statistics.getSum());
    }
}

The result is

2.6 Optional class

The Optional class is a null able container object. The isPresent() method will return true if the value exists, and calling the get() method will return the object.

Optional is a container: it can hold a value of type T, or just null. Optional provides many useful methods so that we don't have to do explicit null detection.

The introduction of the Optional class is a good solution to null pointer exceptions.

Method (the following screenshots are from jdk1.8 api)

package testJava8;

import java.util.Optional;

public class TestOptional {
    public static void main(String[] args) {
        Integer i1 = null;
        Integer i2 = new Integer(3);

        // Optional.ofNullable allows null values
        Optional<Integer> o1 = Optional.ofNullable(i1);
        Optional<Integer> o2 = Optional.of(i2);

        System.out.println("The first parameter value exists:" + o1.isPresent());
        System.out.println("The second parameter value exists:" + o2.isPresent());

        // Optional.orElse judges whether the value exists, returns it if it exists, otherwise returns the default value
        Integer v1 = o1.orElse(new Integer(0));
        System.out.println("The first value is:" + v1);
        // Optional.get get value
        Integer v2 = o2.get();
        System.out.println("The second value is:" + v2);
    }
}

The result is

2.7 Nashorn, the JavaScript engine

Nashorn a javascript engine.

The Nashorn JavaScript Engine is no longer available in Java 15.

Starting from JDK 1.8, Nashorn replaces Rhino(JDK 1.6, JDK1.7) as Java's embedded JavaScript engine. Nashorn fully supports the ECMAScript 5.1 specification as well as some extensions. It compiles JavaScript to Java bytecode using new language features based on JSR 292, including invokedynamic, introduced in JDK 7.

This brings a performance boost of 2 to 10 times compared to the previous Rhino implementation.

2.8 New Date Time API

Java 8 further enhances the handling of dates and times by releasing a new Date-Time API (JSR 310).

Java 8 provides many new API s under the java.time package. The following are two of the more important API s:

  1. Local (local) - simplifies the handling of date and time, no time zone issues.

  2. Zoned − Handles datetimes with the specified time zone.

2.8.1 Localized Date Time API

The LocalDate/LocalTime and LocalDateTime classes can handle situations where time zones are not necessary.

package testJava8;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;

public class TestLocalDateTime {

    public static void main(String[] args) {
        LocalDateTime now = LocalDateTime.now();
        System.out.println("The current time is:" + now);
        int year = now.getYear();
        Month month = now.getMonth();
        int day = now.getDayOfMonth();
        int hour = now.getHour();
        System.out.println("year:" + year + ",moon:" + month + ",day:" + day + ",Hour:" + hour);

        LocalDate d1 = now.toLocalDate();
        System.out.println("The current date is:" + d1);

        LocalDateTime d2 = now.withDayOfMonth(12).withMonth(12).withYear(2019);
        System.out.println("2019 December 12, 2009:" + d2);

        LocalDate d3 = LocalDate.of(2018, Month.JANUARY, 1);
        System.out.println("2018 January 1st:" + d3);

        LocalTime d4 = LocalTime.of(23, 59, 59);
        System.out.println("23 59:59:00:" + d4);

        LocalTime d5 = LocalTime.parse("01:01:01");
        System.out.println("1 Point 1 minute 1 second:" + d5);
    }
}

The result of running is

2.8.1 Datetime API using time zone

If we need to take the time zone into account, we can use the time zone's datetime API.

package testJava8;

import java.time.ZoneId;
import java.time.ZonedDateTime;

public class TestZonedDateTime {
    public static void main(String[] args) {
        ZonedDateTime d1 = ZonedDateTime.now();
        System.out.println("The current time is:" + d1);

        ZoneId zoneId = ZoneId.of("Asia/Shanghai");
        System.out.println("ZoneId : " + zoneId);

        ZoneId currentId = ZoneId.systemDefault();
        System.out.println("Current ZoneId : " + currentId);
    }
}

The result of running is

2.9 Base64

Java 8 has built-in encoders and decoders for Base64 encoding.

The Base64 tool class provides a set of static methods to obtain the following three BASE64 codecs:

  1. Basic: The output is mapped to a set of characters A-Za-z0-9+/, the encoding does not add any line markers, and the decoding of the output only supports A-Za-z0-9+/.

  2. URL: The output maps to a set of characters A-Za-z0-9+_, the output is a URL and a file.

  3. MIME: Output is implied to a MIME friendly format. Output does not exceed 76 characters per line, and uses '\r' followed by '\n' as a split. The encoded output has no line splits at the end.

package testJava8;

import java.util.Base64;

public class TestBase64 {
    private static String UTF8 = "UTF-8";
    public static void main(String[] args) throws Exception {
        // Base64 encoded string (basic)
        String baseStr = Base64.getEncoder().encodeToString("baseString".getBytes(UTF8));
        System.out.println("Base64 encoded string (basic) :" + baseStr);
        byte[] plainBytes = Base64.getDecoder().decode(baseStr);
        System.out.println("Base64 encoded string (basic) The original string is:" + new String(plainBytes, UTF8));

        // Base64 encoded string (URL)
        String urlStr = Base64.getUrlEncoder().encodeToString("urlString".getBytes(UTF8));
        System.out.println("Base64 encoded string (URL) :" + urlStr);
        plainBytes = Base64.getDecoder().decode(urlStr);
        System.out.println("Base64 encoded string (URL)The original string is:" + new String(plainBytes, UTF8));

        // Base64 encoded string (MIME)
        String mimeStr = Base64.getMimeEncoder().encodeToString("mimeString".getBytes(UTF8));
        System.out.println("Base64 encoded string (MIME) :" + mimeStr);
        plainBytes = Base64.getDecoder().decode(mimeStr);
        System.out.println("Base64 encoded string (MIME) The original string is:" + new String(plainBytes, UTF8));
    }
}

The result is

Tags: Java

Posted by jtjohnson260 on Thu, 12 May 2022 07:35:42 +0300