Java8 New Features Learning Record

Foreword: Java  8 has been published for a long time, and many reports indicate that Java 8 is a major version upgrade.There are already many articles on the new features of Java 8 on Java Code Geeks.

for example Playing with Java 8 – Lambdas and Concurrency,Java 8 Date Time API Tutorial : LocalDateTime and Abstract Class Versus Interface in the JDK 8 Era.

This article also refers to some other information, such as: 15 Must Read Java 8 Tutorials and The Dark Side of Java 8.

This article synthesizes the above information and compiles a reference textbook about the new features of Java 8. I hope you can get some results.

1. Introduction

Without doubt, Java 8 It is the most important version of Java since Java 5, released in 2004.This version includes over a dozen new features in languages, compilers, libraries, tools, and JVM.

In this article, we will learn about these new features and use actual examples to illustrate what scenarios are appropriate for use.

This tutorial contains several types of issues Java developers often face:

  • language
  • Compiler
  • library
  • tool
  • Runtime (JVM)

2. New features of the Java language

Java 8 is a major version of Java, and it is believed that while these new features are expected by Java developers, they also require a lot of effort to learn.In this section, we will cover most of the new features of Java 8.

.1 Lambda expressions and functional interfaces

Lambda expressions (also known as closures) are the largest and most anticipated language change in Java 8.It allows us to pass functions as parameters to a method or treat the code itself as data processing: Functional Developer Very familiar with these concepts.

Languages on many JVM platforms (Groovy, Scala Lambda expressions have been supported since birth, but Java developers have no choice but to use anonymous internal classes instead of Lambda expressions.

Lambda's design took a lot of time and community power, and eventually found a compromise solution to achieve a concise and compact language structure.

The simplest Lambda expression can consist of a comma-separated list of parameters, ->symbols, and statement blocks, for example:

Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

The type of parameter e in the code above is inferred by the compiler, and you can also explicitly specify the type of the parameter, for example:

Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );

If a Lambda expression requires a more complex statement block, you can enclose it in curly brackets, similar to the body of a function in Java, for example:

Arrays.asList( "a", "b", "d" ).forEach( e -> {
    System.out.print( e );
    System.out.print( e );
} );

Lambda expressions can refer to class members and local variables that are implicitly converted to final, such as the following two code blocks that work exactly the same:

String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach( 
    ( String e ) -> System.out.print( e + separator ) );

and

final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach( 
    ( String e ) -> System.out.print( e + separator ) );

Lambda expressions have return values, and the type of return value is inferred by the compiler.If a statement block in a Lambda expression has only one line, the return statement may not be used, and the following two code snippets have the same effect:

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );

and

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
    int result = e1.compareTo( e2 );
    return result;
} );

Lambda's designers thought about a number of ways to make existing functionality compatible with Lambda expressions and generated Function Interface This concept.Function interfaces are interfaces that have only one function and can be implicitly converted to Lambda expressions.The best examples of functional interfaces are java.lang.Runnable and java.util.concurrent.Callable.In practice, functional interfaces are very fragile: as long as a developer adds a function to the interface, it is no longer a functional interface and can cause compilation failures.To overcome this code-level vulnerability and explicitly state that an interface is a functional interface, Java 8 provides a special annotation @FunctionalInterface (all related interfaces in the Java library already have this annotation), which is a simple definition of a functional interface:

@FunctionalInterface
public interface Functional {
    void method();
}

But one thing to note is that Default and static methods The definition of a functional interface is not broken, so the following code is legal.

@FunctionalInterface
public interface FunctionalDefaultMethods {
    void method();
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">default</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">defaultMethod</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span> </span>{            
}        

}

Lambda expressions, the biggest selling point of Java 8, have the potential to attract more developers to join the JVM platform and use the concept of functional programming in pure Java programming.If you need more details on Lambda expressions, you can refer to Official Documents.

Default and static methods for 2.2 interfaces

Java 8 extends the meaning of interfaces using two new concepts: the default method and the static method. Default Method Makes the interface a bit like traits, but achieves different goals.The default method allows developers to add a new method to an existing interface without breaking binary compatibility, that is, not forcing classes that implement the interface to implement the new method at the same time.

The difference between the default method and the abstract method is that the abstract method needs to be implemented, while the default method does not.The default methods provided by an interface are inherited or overridden by the interface's implementation class, as shown in the following example code:

private interface Defaulable {
    // Interfaces now allow default methods, the implementer may or 
    // may not implement (override) them.
    default String notRequired() { 
        return "Default implementation"; 
    }        
}

private static class DefaultableImpl implements Defaulable {
}

private static class OverridableImpl implements Defaulable {
@Override
public String notRequired() {
return "Overridden implementation";
}
}

The Defaulable interface defines a default method, notRequired(), using the keyword default.The DefaultableImpl class implements this interface and inherits the default method from it by default; the OverridableImpl class also implements this interface, but overrides its default method and provides a different implementation.

Another interesting feature of Java 8 is that static methods can be defined in interfaces, as shown in the following example code:

private interface DefaulableFactory {
    // Interfaces now allow static methods
    static Defaulable create( Supplier< Defaulable > supplier ) {
        return supplier.get();
    }
}

The following code snippet combines the use scenarios of default and static methods:

public static void main( String[] args ) {
    Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
    System.out.println( defaulable.notRequired() );
defaulable = DefaulableFactory.create( OverridableImpl::<span class="hljs-keyword"><span class="hljs-keyword">new</span> );
System.out.println( defaulable.notRequired() );

}

The output of this code is as follows:

Default implementation
Overridden implementation

Since the implementation of the default method on the JVM provides support at the byte code level, it is very efficient.The default method allows the interface to be improved without breaking through the existing inheritance system.This feature is used in official libraries to add new methods to the java.util.Collection interface, such as stream(), parallelStream(), forEach(), removeIf(), and so on.

Although the default approach offers so many benefits, it should be used cautiously in practical development: in complex inheritance systems, it can cause ambiguity and compilation errors.If you want to know more details, you can refer to Official Documents.

2.3 Method References

Method references allow developers to directly reference existing methods, constructors of Java classes, or instance objects.The use of method references in conjunction with Lambda expressions makes the construction of Java classes seem compact and concise without much complex template code.

In Simon's example, the Car class is an example of different method references that can help readers distinguish between four types of method references.

public static class Car {
    public static Car create( final Supplier< Car > supplier ) {
        return supplier.get();
    }              
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">static</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">collide</span>(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params"> final Car car </span>) </span>{
    System.<span class="hljs-keyword"><span class="hljs-keyword">out</span>.println( <span class="hljs-string"><span class="hljs-string">"Collided "</span> + car.toString() );
}

<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">follow</span>(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params"> final Car another </span>) </span>{
    System.<span class="hljs-keyword"><span class="hljs-keyword">out</span>.println( <span class="hljs-string"><span class="hljs-string">"Following the "</span> + another.toString() );
}

<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">repair</span>(</span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params"></span>) </span>{   
    System.<span class="hljs-keyword"><span class="hljs-keyword">out</span>.println( <span class="hljs-string"><span class="hljs-string">"Repaired "</span> + <span class="hljs-keyword"><span class="hljs-keyword">this</span>.toString() );
}

}

The first method refers to a constructor reference with the syntax Class::new or, more generally, Class<T>::new.Note: This constructor has no parameters.

final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );

The second method references a static method reference with the syntax Class::static_method.Note: This method accepts a Car type parameter.

cars.forEach( Car::collide );

The third method references a type that is a reference to a member method of a class, and the syntax is Class::method. Note that this method does not define an entry parameter:

cars.forEach( Car::repair );

The fourth method references a type that is a reference to a member method of an instance object, and the syntax is instance::method.Note: This method accepts a Car type parameter:

final Car police = Car.create( Car::new );
cars.forEach( police::follow );

Running the example above, you can see the following output in the console (Car instances may be different):

Collided com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Repaired com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Following the com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d

If you want to know and learn more, you can refer to Official Documents

2.4 Repeat notes

Since the introduction of Java 5 annotation Since then, this feature has become very popular and widely used in various frameworks and projects.However, there is a big limitation to annotations: you cannot use the same annotation multiple times in the same place.Java 8 breaks this limit by introducing the concept of repeated annotations, which allow the same annotation to be used multiple times in the same place.

Using the @Repeatable annotation to define duplicate annotations in Java 8 is not really a linguistic improvement, but a trick done by the compiler, and the underlying technology is still the same.You can use the following code instructions:

package com.javacodegeeks.java8.repeatable.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class RepeatingAnnotations {
@Target( ElementType.TYPE )
@Retention( RetentionPolicy.RUNTIME )
public @interface Filters {
Filter[] value();
}

<span class="hljs-annotation"><span class="hljs-meta">@Target</span>( ElementType.TYPE )
<span class="hljs-annotation"><span class="hljs-meta">@Retention</span>( RetentionPolicy.RUNTIME )
<span class="hljs-annotation"><span class="hljs-meta">@Repeatable</span>( Filters.class )
<span class="hljs-keyword"><span class="hljs-keyword">public</span> <span class="hljs-annotation"><span class="hljs-meta">@interface</span> Filter {
    <span class="hljs-function"><span class="hljs-function">String </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">value</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span></span>;
};

<span class="hljs-annotation"><span class="hljs-meta">@Filter</span>( <span class="hljs-string"><span class="hljs-string">"filter1"</span> )
<span class="hljs-annotation"><span class="hljs-meta">@Filter</span>( <span class="hljs-string"><span class="hljs-string">"filter2"</span> )
<span class="hljs-keyword"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword"><span class="hljs-class"><span class="hljs-keyword">interface</span> </span><span class="hljs-title"><span class="hljs-class"><span class="hljs-title">Filterable</span> </span>{        
}

<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">static</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">main</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(String[] args)</span> </span>{
    <span class="hljs-keyword"><span class="hljs-keyword">for</span>( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) {
        System.out.println( filter.value() );
    }
}

}

As we have seen, the Filter class here is decorated with @Repeatable(Filters.class) annotations, which are containers for filter annotations, and the compiler tries to shield these details from developers.This allows the Filterable interface to be annotated with two Filters (no information about Filters is mentioned here).

In addition, the reflection API provides a new method: getAnnotationsByType(), which returns duplicate annotations of a certain type, such as Filterable.class.getAnnoation(Filters.class), which returns two instances of Filter, which are output to the console as follows:

filter1
filter2

If you want to know more, you can refer to Official Documents.

2.5 Better type inference

The Java 8 compiler has greatly improved the type inference. In many scenarios, the compiler can deduce the data type of a parameter to make the code more concise.The example code is as follows:

package com.javacodegeeks.java8.type.inference;

public class Value< T > {
public static< T > T defaultValue() {
return null;
}

<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> T </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">getOrDefault</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">( T value, T defaultValue )</span> </span>{
    <span class="hljs-keyword"><span class="hljs-keyword">return</span> ( value != <span class="hljs-keyword"><span class="hljs-keyword">null</span> ) ? value : defaultValue;
}

}

The following code is an application of type Value <String>

package com.javacodegeeks.java8.type.inference;

public class TypeInference {
public static void main(String[] args) {
final Value< String > value = new Value<>();
value.getOrDefault( "22", Value.defaultValue() );
}
}

The type of the parameter Value.defaultValue() is derived by the compiler and does not need to be explicitly specified.This section of code in Java 7 will have compilation errors unless Value. <String>defaultValue() is used.

2.6 Widening the use of annotations

Java 8 extends the use of annotations.Annotations can now be used on almost any element: local variables, interface types, superclasses, and interface implementation classes, and even on exception definitions for functions.Here are some examples:

package com.javacodegeeks.java8.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collection;

public class Annotations {
@Retention( RetentionPolicy.RUNTIME )
@Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )
public @interface NonEmpty {
}

<span class="hljs-keyword"><span class="hljs-keyword">public</span> <span class="hljs-keyword"><span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword"><span class="hljs-class"><span class="hljs-keyword">class</span> </span><span class="hljs-title"><span class="hljs-class"><span class="hljs-title">Holder</span>&lt; @</span><span class="hljs-title"><span class="hljs-class"><span class="hljs-title">NonEmpty</span> </span><span class="hljs-title"><span class="hljs-class"><span class="hljs-title">T</span> &gt; </span><span class="hljs-keyword"><span class="hljs-class"><span class="hljs-keyword">extends</span> @</span><span class="hljs-title"><span class="hljs-class"><span class="hljs-title">NonEmpty</span> </span><span class="hljs-title"><span class="hljs-class"><span class="hljs-title">Object</span> </span>{
    <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">method</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span> @NonEmpty Exception </span>{            
    }
}

<span class="hljs-annotation"><span class="hljs-meta">@SuppressWarnings</span>( <span class="hljs-string"><span class="hljs-string">"unused"</span> )
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">static</span> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">main</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(String[] args)</span> </span>{
    <span class="hljs-keyword"><span class="hljs-keyword">final</span> Holder&lt; String &gt; holder = <span class="hljs-keyword"><span class="hljs-keyword">new</span> <span class="hljs-annotation"><span class="hljs-meta">@NonEmpty</span> Holder&lt; String &gt;();        
    <span class="hljs-annotation"><span class="hljs-meta">@NonEmpty</span> Collection&lt; <span class="hljs-annotation"><span class="hljs-meta">@NonEmpty</span> String &gt; strings = <span class="hljs-keyword"><span class="hljs-keyword">new</span> ArrayList&lt;&gt;();        
}

}

ElementType.TYPE_USER and ElementType.TYPE_PARAMETER are two new annotations added to Java 8 to describe scenarios in which annotations are used.The Java language has also changed to recognize these new annotations.

3. New features of the Java compiler

3.1 Parameter Name

In order to get the parameter names of methods in Java programs at run time, older Java programmers must use different methods, such as Paranamer liberary .Java 8 finally normalized this feature to support both the language level (using the reflection API and the Parameter.getName() method) and the byte code level (using the new javac compiler and the -parameters parameter).

package com.javacodegeeks.java8.parameter.names;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class ParameterNames {
public static void main(String[] args) throws Exception {
Method method = ParameterNames.class.getMethod( "main", String[].class );
for( final Parameter parameter: method.getParameters() ) {
System.out.println( "Parameter: " + parameter.getName() );
}
}
}

This feature is turned off by default in Java 8, so if you compile and run the above code without the -parameters parameter, the following results will be output:

Parameter: arg0

If you take the -parameters parameter, the following results are output (correct results):

Parameter: args

If you use Maven for project management, you can configure the -parameters parameter in the configuration item of the maven-compiler-plugin compiler:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.1</version>
    <configuration>
        <compilerArgument>-parameters</compilerArgument>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

4. New features of the official Java Libraries

Java 8 adds many new tool classes (date/time classes) and extends existing ones to support modern concurrent programming, functional programming, and so on.

4.1 Optional

The most common bug in Java applications is Null value exception .Before Java 8, Google Guava The Optionals class was introduced to solve NullPointerException, which prevents the source code from being contaminated by various null checks so that developers can write cleaner code.Java 8 also added Optional to the official library.

Optional is simply an easy way to store T-type values or nulls.It provides some useful interfaces to avoid explicit null checks for reference Java 8 Official Documentation Learn more.

Next, let's look at an example of using Optional: possibly empty values or values of a certain type:

Optional< String > fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );        
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) ); 
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );

If the Optional instance holds a non-null value, the isPresent() method returns true, or false; the orElseGet() method, which holds null, accepts a default value generated by a lambda expression; the map() method converts the value of an existing Opetional instance to a new value; and the orElse() method is similar to the orElseGet() method, but returns null when it holds nullDefault value passed in.

The output of the above code is as follows:

Full Name is set? false
Full Name: [none]
Hey Stranger!

Look at another simple example:

Optional< String > firstName = Optional.of( "Tom" );
System.out.println( "First Name is set? " + firstName.isPresent() );        
System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) ); 
System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
System.out.println();

The output of this example is:

First Name is set? true
First Name: Tom
Hey Tom!

For more details, please refer to Official Documents.

4.2 Streams

Added Stream API (java.util.stream) introduces functional programming for the production environment into the Java library.This is by far the largest improvement to the Java library so that developers can write more efficient, concise, and compact code.

The Steam API greatly simplifies the operation of collections (we'll see more than just collections later), so first look at this class called Task:

public class Streams  {
    private enum Status {
        OPEN, CLOSED
    };
<span class="hljs-keyword"><span class="hljs-keyword">private</span> <span class="hljs-keyword"><span class="hljs-keyword">static</span> <span class="hljs-keyword"><span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword"><span class="hljs-class"><span class="hljs-keyword">class</span> </span><span class="hljs-title"><span class="hljs-class"><span class="hljs-title">Task</span> </span>{
    <span class="hljs-keyword"><span class="hljs-keyword">private</span> <span class="hljs-keyword"><span class="hljs-keyword">final</span> Status status;
    <span class="hljs-keyword"><span class="hljs-keyword">private</span> <span class="hljs-keyword"><span class="hljs-keyword">final</span> Integer points;

    Task( <span class="hljs-keyword"><span class="hljs-keyword">final</span> Status status, <span class="hljs-keyword"><span class="hljs-keyword">final</span> Integer points ) {
        <span class="hljs-keyword"><span class="hljs-keyword">this</span>.status = status;
        <span class="hljs-keyword"><span class="hljs-keyword">this</span>.points = points;
    }

    <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> Integer </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">getPoints</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword"><span class="hljs-keyword">return</span> points;
    }

    <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> Status </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">getStatus</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword"><span class="hljs-keyword">return</span> status;
    }

    <span class="hljs-annotation"><span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> String </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">toString</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword"><span class="hljs-keyword">return</span> String.format( <span class="hljs-string"><span class="hljs-string">"[%s, %d]"</span>, status, points );
    }
}

}

The Task class has a fraction (or pseudo-complexity) concept and two additional states: OPEN or CLOSED.Now suppose you have a task set:

final Collection< Task > tasks = Arrays.asList(
    new Task( Status.OPEN, 5 ),
    new Task( Status.OPEN, 13 ),
    new Task( Status.CLOSED, 8 ) 
);

First, let's look at the question: How many OPEN state points are there in this task collection?Prior to Java 8, this problem required a foreach loop to iterate through the task collection; however, in Java 8, steams could be used to solve the problem: a list of elements, with sequential and parallel processing supported.

// Calculate total points of all active tasks using sum()
final long totalPointsOfOpenTasks = tasks
    .stream()
    .filter( task -> task.getStatus() == Status.OPEN )
    .mapToInt( Task::getPoints )
    .sum();

System.out.println( "Total points: " + totalPointsOfOpenTasks );

The console output to run this method is:

Total points: 18

There are many points of knowledge to say.First, the tasks collection is converted to a steam representation; second, the filter operation on the steam filters out all CLOSED tasks; third, the mapToInt operation is based on the Task::getPoints method of each task instance to convert the task stream to an Integer collection; and finally, the sum is calculated using the sum method to get the final result.

Before learning the next example, you need to remember some steams. Click on this for more details ) Knowledge points.Operations above Steam can be divided into intermediate and late operations.

Intermediate operations return a new steam -- performing an intermediate operation (such as a filter) does not perform the actual filtering operation, but instead creates a new steam and places the qualifying elements of the original steam into the newly created steam.

Late operations, such as forEach or sum, traverse the steam and get results or accompanying results; after a late operation, the steam processing line is processed and cannot be used.In almost all cases, late operations traverse the steam immediately.

Another value of steam is its creative support for parallel processing.For the tasks set above, we can use the following code to calculate the sum of the number of points for all tasks:

// Calculate total points of all tasks
final double totalPoints = tasks
   .stream()
   .parallel()
   .map( task -> task.getPoints() ) // or map( Task::getPoints ) 
   .reduce( 0, Integer::sum );

System.out.println( "Total points (all tasks): " + totalPoints );

Here we use the parallel method to process all task s in parallel and reduce to calculate the final result.The console output is as follows:

Total points(all tasks): 26.0

For a set, it is often necessary to group elements according to certain conditions.This type of task can be accomplished quickly using the API provided by steam with the following code:

// Group tasks by their status
final Map< Status, List< Task > > map = tasks
    .stream()
    .collect( Collectors.groupingBy( Task::getStatus ) );
System.out.println( map );

The output of the console is as follows:

{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}

The last example of a tasks set is how to calculate the percentage of the number of points in the set for each task in the set, using the following code:

// Calculate the weight of each tasks (as percent of total points) 
final Collection< String > result = tasks
    .stream()                                        // Stream< String >
    .mapToInt( Task::getPoints )                     // IntStream
    .asLongStream()                                  // LongStream
    .mapToDouble( points -> points / totalPoints )   // DoubleStream
    .boxed()                                         // Stream< Double >
    .mapToLong( weigth -> ( long )( weigth * 100 ) ) // LongStream
    .mapToObj( percentage -> percentage + "%" )      // Stream< String> 
    .collect( Collectors.toList() );                 // List< String > 

System.out.println( result );

The console output is as follows:

[19%, 50%, 30%]

Finally, as mentioned earlier, the Steam API not only works on Java collections, but traditional IO operations (reading data line by line from a file or network) can benefit from steam processing, for example:

final Path path = new File( filename ).toPath();
try( Stream< String > lines = Files.lines( path, StandardCharsets.UTF_8 ) ) {
    lines.onClose( () -> System.out.println("Done!") ).forEach( System.out::println );
}

The Stream method onClose returns an equivalent Stream with an extra handle that is executed when the close() method of Stream is called.Stream API, Lambda expression, and method references supported by interface default methods and static methods are Java 8's response to the modern paradigm of software development.

4.3 Date/Time API(JSR 310)

Java 8 introduced New Date-Time API(JSR 310) To improve the processing of time and date.Time and date management has always been the most painful issue for Java developers.java.util.Date and later java.util.Calendar have not solved this problem (and even confused developers).

For these reasons, third-party libraries were born Joda-Time , which can replace Java's time management API.The new time and date management API in Java 8 was heavily influenced by Joda-Time and absorbed a lot of the essence of Joda-Time.The new java.time package contains all the classes for date, time, time zone, Instant (similar to date but accurate to nanoseconds), duration (duration), and clock operations.The newly designed API carefully considers the invariance of these classes (lessons learned from java.util.Calendar) and returns a new object if an instance needs to be modified.

Let's look at the key classes in the java.time package and their respective usage examples.First, the Clock class uses time to return the current nanosecond time and date.Clock can replace System.currentTimeMillis() and TimeZone.getDefault().

// Get the system clock as UTC offset 
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );

The output of this example is:

2014-04-12T15:19:29.282Z
1397315969360

Second, focus on the LocalDate and LocalTime classes.LocalDate only contains the date part in the ISO-8601 calendar system; LocalTime only contains the time part in the calendar system.Objects of both classes can be built using Clock objects.

// Get the local date and local time
final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );

System.out.println( date );
System.out.println( dateFromClock );

// Get the local date and local time
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );

System.out.println( time );
System.out.println( timeFromClock );

The output of the above example is as follows:

2014-04-12
2014-04-12
11:25:54.568
15:25:54.568

The LocalDateTime class contains information about LocalDate and LocalTime, but it does not contain time zone information in the ISO-8601 calendar system.Here are some Examples of LocalDate and LocalTime:

// Get the local date/time
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );

System.out.println( datetime );
System.out.println( datetimeFromClock );

The output of this example is as follows:

2014-04-12T11:37:52.309
2014-04-12T15:37:52.309

If you need data/time information for a specific time zone, you can use ZoneDateTime, which holds the date and time of the ISO-8601 date system with time zone information.Here are some examples of using different time zones:

// Get the zoned date/time
final ZonedDateTime zonedDatetime = ZonedDateTime.now();
final ZonedDateTime zonedDatetimeFromClock = ZonedDateTime.now( clock );
final ZonedDateTime zonedDatetimeFromZone = ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) );

System.out.println( zonedDatetime );
System.out.println( zonedDatetimeFromClock );
System.out.println( zonedDatetimeFromZone );

The output of this example is:

2014-04-12T11:47:01.017-04:00[America/New_York]
2014-04-12T15:47:01.017Z
2014-04-12T08:47:01.017-07:00[America/Los_Angeles]

Finally, look at the Duration class, which holds times as precise as seconds and nanoseconds.This makes it easy to calculate the difference between two dates, as shown in the following example code:

// Get duration between two dates
final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );

final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );
System.out.println( "Duration in hours: " + duration.toHours() );

This example is used to calculate the number of days and hours between April 16, 2014 and April 16, 2015. The output is as follows:

Duration in days: 365
Duration in hours: 8783

The overall impression of the new date and time for Java 8 is still positive, partly because of the positive impact of Joda-Time and partly because the authorities finally listened to the needs of developers.If you want more details, you can refer to Official Documents.

4.4 Nashorn JavaScript Engine

Java 8 provides a new Nashorn JavaScript Engine This enables us to develop and run JS applications on the JVM.Nashorn JavaScript Engines are another implementation of javax.script.ScriptEngine, which follows the same rules and allows Java and JavaScript to interact with each other. The example code is as follows:

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName( "JavaScript" );

System.out.println( engine.getClass().getName() );
System.out.println( "Result:" + engine.eval( "function f() { return 1; }; f() + 1;" ) );

The output of this code is as follows:

jdk.nashorn.api.scripting.NashornScriptEngine
Result: 2

4.5 Base64

Support for Base64 encoding It has been added to the official Java 8 library so that Base64 encoding can be done without using third-party libraries, as shown in the following example code:

package com.javacodegeeks.java8.base64;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Base64s {
public static void main(String[] args) {
final String text = "Base64 finally in Java 8!";

    <span class="hljs-keyword"><span class="hljs-keyword">final</span> String encoded = Base64
        .getEncoder()
        .encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
    System.out.println( encoded );

    <span class="hljs-keyword"><span class="hljs-keyword">final</span> String decoded = <span class="hljs-keyword"><span class="hljs-keyword">new</span> String( 
        Base64.getDecoder().decode( encoded ),
        StandardCharsets.UTF_8 );
    System.out.println( decoded );
}

}

The output of this example is as follows:

QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!

The new Base64 API also supports encoding and decoding of URL s and MINE s.
(Base64.getUrlEncoder() / Base64.getUrlDecoder(), Base64.getMimeEncoder() / Base64.getMimeDecoder()).

BASE64 is not used for encryption, it is a BASE64 encoded string, all composed of regular characters on the standard keyboard, so that the encoded string will not be generated for transfer between gateways UNICODE An unrecognized or missing occurrence of a string.You'll look into it again EMAIL And you'll find out EMAIL It is sent after encoding with base64.Then restore when received.

4.6 Parallel Arrays

Java 8 adds many new methods to support parallel array processing.The most important method is parallelSort(), which significantly accelerates array sorting on multicore machines.The following examples demonstrate the methods of the parallexXxx series:

package com.javacodegeeks.java8.parallel.arrays;

import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;

public class ParallelArrays {
public static void main( String[] args ) {
long[] arrayOfLong = new long [ 20000 ];

    Arrays.parallelSetAll( arrayOfLong, 
        index -&gt; ThreadLocalRandom.current().nextInt( <span class="hljs-number"><span class="hljs-number">1000000</span> ) );
    Arrays.stream( arrayOfLong ).limit( <span class="hljs-number"><span class="hljs-number">10</span> ).forEach( 
        i -&gt; System.<span class="hljs-keyword"><span class="hljs-keyword">out</span>.print( i + <span class="hljs-string"><span class="hljs-string">" "</span> ) );
    System.<span class="hljs-keyword"><span class="hljs-keyword">out</span>.println();

    Arrays.parallelSort( arrayOfLong );        
    Arrays.stream( arrayOfLong ).limit( <span class="hljs-number"><span class="hljs-number">10</span> ).forEach( 
        i -&gt; System.<span class="hljs-keyword"><span class="hljs-keyword">out</span>.print( i + <span class="hljs-string"><span class="hljs-string">" "</span> ) );
    System.<span class="hljs-keyword"><span class="hljs-keyword">out</span>.println();
}

}

The above code uses the parallelSetAll() method to generate 20,000 random numbers, and then uses the parallelSort() method to sort them.This program outputs the first 10 elements of a random and sorted array.The result of the code output for the example above is:

Unsorted: 591217 891976 443951 424479 766825 351964 242997 642839 119108 552378 
Sorted: 39 220 263 268 325 607 655 678 723 793

4.7 Concurrency

Based on the new lambda expressions and steam features, new methods have been added to Java 8 to support focused operations for the java.util.concurrent.ConcurrentHashMap class, and new methods have been added to the java.util.concurrentForkJoinPool class to support common thread pool operations (more can be referred to) Our Concurrent Programming Course).

Java 8 also added a new java.util.concurrent.locks.StampedLock class to support capacity-based locks, which have three models to support read and write operations (you can think of this lock as a substitute for java.util.concurrent.locks.ReadWriteLock).

Several new tool classes have been added to the java.util.concurrent.atomic package, as follows:

  • DoubleAccumulator
  • DoubleAdder
  • LongAccumulator
  • LongAdder

5. New Java Tools

Java 8 offers some new command-line tools, and this section explains some of the most useful tools for developers.

5.1 Nashorn Engine: jjs

jjs is a command line tool based on the standard Nashorn engine that accepts JS source code and executes it.For example, let's write a func.js file that reads as follows:

function f() { 
     return 1; 
}; 

print( f() + 1 );

You can execute this command from the command line: jjs func.js, and the console output is:

2

If you need to know more, you can refer to Official Documents.

Class 5.2 Dependency Analyzer: jdeps

jdeps is a great command-line tool that displays Java class dependencies at the package and class levels, takes an.Class file, directory, or Jar file as input, and outputs the dependencies to the console.

We can use jedps to analyze Spring Framework Library To get fewer results, just analyze one JAR file: org.springframework.core-3.0.5.RELEASE.jar.

jdeps org.springframework.core-3.0.5.RELEASE.jar

This command outputs a lot of results, so let's just look at a few of them: Dependencies are grouped by packages, and "not found" is displayed if no dependencies are found on the classpath.

org.springframework.core-3.0.5.RELEASE.jar -> C:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar
   org.springframework.core (org.springframework.core-3.0.5.RELEASE.jar)
      -> java.io                                            
      -> java.lang                                          
      -> java.lang.annotation                               
      -> java.lang.ref                                      
      -> java.lang.reflect                                  
      -> java.util                                          
      -> java.util.concurrent                               
      -> org.apache.commons.logging                         not found
      -> org.springframework.asm                            not found
      -> org.springframework.asm.commons                    not found
   org.springframework.core.annotation (org.springframework.core-3.0.5.RELEASE.jar)
      -> java.lang                                          
      -> java.lang.annotation                               
      -> java.lang.reflect                                  
      -> java.util

More details can be referred to Official Documents.

6. New features of JVM

Use Metaspace(JEP 122 ) instead of PermGen space.In terms of JVM parameters, use -XX:MetaSpaceSize and -XX:MaxMetaspaceSize instead of -XX:PermSize and -XX:MaxPermSize.

7. Conclusion

Java 8 takes the Java platform a big step forward by providing developers with many productivity-enhancing features.It's not a good time to use Java 8 in production systems right now, but the application rate of Java 8 will increase gradually in the next few months (PS: original time is May 9, 2014, Java 8 has become the mainstream in many companies. Due to its large size, our company is now a bit Java 8, although slower, it is upgrading somewhat bad).As a developer, you should now learn some Java 8 knowledge to prepare for upgrade.

about spring : For enterprise development, we should also focus on the Spring community's support for Java 8, which you can refer to in this article: An overview of the new features of Java 8 supported by Spring 4

8. References

 
Classification: Java

Tags: Java Lambda Steam jvm

Posted on Tue, 14 May 2019 13:20:26 -0400 by michaelfn