Introduction: Java 8 has been released for a long time, and many reports indicate that Java 8 is a major release upgrade. There have been many articles on Java Code Geeks about the new features of Java 8,

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 referred to other sources such as 15 Must Read Java 8 Tutorials and The Dark Side of Java 8

This article combines the above information into a reference textbook on the new features of Java 8.

1. Introduction

Without a doubt, Java 8 is the most important release of Java since Java 5 (released in 2004). This release includes more than a dozen new features in languages, compilers, libraries, tools, and JVMS.

In this article, we’ll learn about these new features and use practical examples to show where they are appropriate.

This tutorial covers several types of questions that Java developers often face:

  • language
  • The compiler
  • library
  • tool
  • Runtime (JVM)

2. New features of the Java language

Java 8 is a major release of Java, and while these new features are eagerly awaited by Java developers, they also require a lot of effort to learn. In this section, we’ll cover most of the new features of Java 8.

.1 Lambda expressions and functional interfaces

Lambda expressions (also known as closures) are the biggest and most anticipated language change in Java 8. It allows us to pass functions as arguments to a method, or to treat the code itself as data: functional developers are familiar with these concepts.

Many languages on the JVM platform (Groovy, Scala, etc.) have supported Lambda expressions since their inception, but Java developers have had no choice but to use anonymous inner classes instead of Lambda expressions.

The design of Lambda took a lot of time and community effort to find a compromise that could achieve a concise and compact language structure.

The simplest Lambda expressions can consist of comma-separated argument lists, -> symbols, and statement blocks, such as:

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

The type of the argument e in this code is inferred by the compiler. You can also specify the type of the argument explicitly, for example:

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

If a Lambda expression requires a more complex block, it can be enclosed in curly braces, 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 ); });Copy the code

Lambda expressions can refer to class members and local variables (which are implicitly converted to final). For example, the following two code blocks have exactly the same effect:

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

and

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

Lambda expressions have return values, and the type of the return value is inferred by the compiler. If the block in a Lambda expression is only one line, you can skip the return statement. The following two code snippets have the same effect:

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

and

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

Lambda designers considered many ways to make existing functions compatible with Lambda expressions, resulting in the concept of functional interfaces. A functional interface is an interface that has only one function, and such an interface can be implicitly converted to a Lambda expression. Java. Lang. Runnable and Java. Util. Concurrent. Callable is the best example of functional interface. In practice, functional interfaces are very fragile: as soon as a developer adds a function to the interface, the interface ceases to be functional and thus fails compilation. To overcome this code-level vulnerability and explicitly state that an interface is functional, Java 8 provides a special annotation @functionalinterface (all relevant interfaces in the Java library already carry this annotation). Here’s a simple definition of a FunctionalInterface:

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

It is important to note, however, that the default and static methods do not break the definition of a functional interface, so the following code is legal.

@FunctionalInterface
public interface FunctionalDefaultMethods {
    void method();

    default void defaultMethod() {            
    }        
}Copy the code

Lambda expressions, the biggest selling point of Java 8, have the potential to attract more developers to the JVM platform and to use the concepts of functional programming in pure Java programming. If you need more details on Lambda expressions, refer to the official documentation.

2.2 Default methods and static methods of interfaces

Java 8 expands the meaning of interfaces with two new concepts: default methods and static methods. The default approach makes interfaces look a bit like traits, but for a different purpose. The default method allows developers to add a new method to an existing interface without breaking binary compatibility, that is, it does not force classes that implement the interface to also implement the new method.

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 the interface are inherited or overridden by the implementation class of the interface, as shown in the following example:

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"; }}Copy the code

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

Another interesting feature that Java 8 brings is the ability to define static methods in interfaces, as shown in the following code:

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

The following code snippet integrates the default method and static method usage scenarios:

public static void main( String[] args ) {
    Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new );
    System.out.println( defaulable.notRequired() );

    defaulable = DefaulableFactory.create( OverridableImpl::new );
    System.out.println( defaulable.notRequired() );
}Copy the code

The output of this code is as follows:

Default implementation
Overridden implementationCopy the code

Because the implementation of default methods on the JVM provides support at the bytecode level, this is very efficient. The default approach allows the interface to be improved without breaking the existing inheritance architecture. This feature is used in official libraries by adding new methods to the java.util.collection interface, such as stream(), parallelStream(), forEach(), removeIf(), and so on.

Despite the benefits of default methods, they should be used with caution in practice: in complex inheritance systems, default methods can cause ambiguity and compilation errors. If you want more details, you can refer to the official documentation.

2.3 Method Reference

Method references allow developers to refer directly to existing methods, Java class constructors, or instance objects. Method references are used in conjunction with Lambda expressions to make the constructors of Java classes look compact and concise, without a lot of complex template code.

In Simon’s case, the Car class is an example of different method references to help readers distinguish between the four types of method references.

public static class Car { public static Car create( final Supplier< Car > supplier ) { return supplier.get(); } public static void collide( final Car car ) { System.out.println( "Collided " + car.toString() ); } public void follow( final Car another ) { System.out.println( "Following the " + another.toString() ); } public void repair() { System.out.println( "Repaired " + this.toString() ); }}Copy the code

The first type of method reference is a constructor reference with the syntax Class::new, or the more general form: Class

::new. Note: This constructor takes no arguments.

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

The second type of method reference is a static method reference with the syntax Class::static_method. Note: This method takes an argument of type Car.

cars.forEach( Car::collide );Copy the code

The third method refers to a reference to a member method of a Class. The syntax is Class::method. Note that this method has no input arguments:

cars.forEach( Car::repair );Copy the code

The fourth method refers to a reference to a member method of an instance object with the syntax instance::method. Note: This method takes a Car parameter:

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

Running the above example, you can see the following output on the console (Car instances may vary) :

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@7a81197dCopy the code

For more details, please refer to the official documentation

2.4 Repeated notes

Since the introduction of annotations in Java 5, this feature has become very popular and is widely used in various frameworks and projects. However, there is one big limitation to annotations: you can’t use the same annotation more than once in the same place. Java 8 breaks this limitation by introducing the concept of repeated annotations, allowing the same annotation to be used multiple times in the same place.

Using the @REPEATable annotation to define Repeatable annotations in Java 8 is actually not a language improvement, but a trick made by the compiler. The underlying technology is still the same. You can use the following code to illustrate:

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(); } @Target( ElementType.TYPE ) @Retention( RetentionPolicy.RUNTIME ) @Repeatable( Filters.class ) public @interface Filter { String value(); }; @Filter( "filter1" ) @Filter( "filter2" ) public interface Filterable { } public static void main(String[] args) { for( Filter filter: Filterable.class.getAnnotationsByType( Filter.class ) ) { System.out.println( filter.value() ); }}}Copy the code

As we can see, the Filter class here is modified with the @REPEATable (Filters.class) annotation, and Filters are the containers that hold the Filter annotation. The compiler tries to hide these details from the developer. Thus, the Filterable interface can be annotated with two Filter annotations (nothing about Filters is said here).

In addition, the reflection API provides a new method: GetAnnotationsByType (), can return to a certain type of repeated notes, such as Filterable. Class. GetAnnoation (Filters. Class) will return the two Filter as an example, the contents of the output to the console as shown below:

filter1
filter2Copy the code

If you want to learn more, you can refer to the official documentation.

2.5 Better type inference

The Java 8 compiler has made significant improvements in type inference, allowing the compiler to deduce the data type of a parameter in many scenarios, resulting in cleaner code. Example code is as follows:

package com.javacodegeeks.java8.type.inference;

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

    public T getOrDefault( T value, T defaultValue ) {
        return ( value != null ) ? value : defaultValue;
    }
}Copy the code

The following code applies to Value

:

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() ); }}Copy the code

The type of the value.defaultValue () argument is derived by the compiler and does not need to be specified explicitly. In Java 7, this code will compile errors unless Value.

defaultValue() is used.

2.6 Expand the application scenarios of annotations

Java 8 broadens the scope of annotations. Annotations can now be used on almost any element: local variables, interface types, superclasses and interface implementation classes, and even on the exception definition of 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 { } public static class Holder< @NonEmpty T > extends @NonEmpty Object { public void method() throws @NonEmpty Exception { } } @SuppressWarnings( "unused" ) public static void main(String[] args) { final Holder< String > holder = new @NonEmpty Holder< String >(); @NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>(); }}Copy the code

Elementtype. TYPE_USER and elementtype. TYPE_PARAMETER are two new annotations in Java 8 that describe how annotations are used. The Java language has also been changed to recognize these new annotations.

3. New features for the Java compiler

3.1 Parameter Name

To get the parameter names of methods in Java programs at run time, older Java programmers had to use different methods, such as Paranamer Liberary. Java 8 has finally normalized this feature, providing support both at the language level (using reflection apis and parameter.getName () methods) and at the bytecode 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() ); }}}Copy the code

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

Parameter: arg0Copy the code

If -parameters is used, the following result is printed (correct) :

Parameter: argsCopy the code

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

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

4. New features in the Official Java library

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

4.1 Optional

The most common bug in Java applications is null-value exceptions. Prior to Java 8, Google Guava introduced the Optionals class to resolve NullPointerExceptions, preventing source code from being contaminated by various NULL checks and allowing developers to write cleaner code. Java 8 also added Optional to the official library.

Optional is just an easy way to store values of type T or NULL. It provides some useful interfaces to avoid explicit NULL checking, and you can refer to the Java 8 documentation for more details.

Let’s look at a few examples of using Optional: values that may be null or of some 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!" ));Copy the code

The isPresent() method returns true if the Optional instance holds a non-null value, false otherwise; The orElseGet() method, where Optional instances hold null, can accept a default generated by a lambda expression; The map() method converts the value of an existing Opetional instance to a new value; The orElse() method is similar to the orElseGet() method, but returns the default value passed in when null is held.

The output of the above code is as follows:

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

Here’s 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();Copy the code

The output of this example is:

First Name is set? true
First Name: Tom
Hey Tom!Copy the code

For more details, please refer to the official documentation.

4.2 Streams

The new Stream API (java.util.stream) brings functional programming for the generated environment to Java libraries. This is one of the biggest improvements to the Java library so far, allowing developers to write more efficient, concise, and compact code.

The Steam API greatly simplifies collection operations (we’ll see more than that later), starting with a class called Task:

public class Streams { private enum Status { OPEN, CLOSED }; private static final class Task { private final Status status; private final Integer points; Task( final Status status, final Integer points ) { this.status = status; this.points = points; } public Integer getPoints() { return points; } public Status getStatus() { return status; } @Override public String toString() { return String.format( "[%s, %d]", status, points ); }}}Copy the code

The Task class has a concept of score (or pseudo-complexity) and two states: OPEN or CLOSED. Now suppose you have a collection of tasks:

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

Let’s start with a question: how many OPEN points are there in this task set? Prior to Java 8, to solve this problem, you used a foreach loop to iterate over a collection of tasks; But in Java 8 you can take advantage of Steams, which includes a list of elements and supports sequential and parallel processing.

// 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 );Copy the code

The console output from running this method is:

Total points: 18Copy the code

There’s a lot to be said for that. First, the Tasks collection is converted to a Steam representation; Second, the Filter operation on Steam filters out all CLOSED tasks. Third, the mapToInt operation converts the Task flow into an Integer set based on the Task::getPoints method of each task instance. Finally, the sum method is used to calculate the sum and get the final result.

Before moving on to the next example, there are a few steams to keep in mind (click here for more details). Actions on Steam can be divided into intermediate actions and late actions.

An intermediate action returns a new Steam — performing an intermediate action (such as Filter) does not perform the actual filtering, but rather creates a new Steam and puts the qualifying elements from the original steam into the newly created Steam.

Late operations, such as forEach or sum, iterate over Steam and produce results or additional results; After the late operation, the Steam processing line has been processed and is no longer usable. In almost all cases, the late action is to traverse Steam immediately.

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

// 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 );Copy the code

Here we use the Parallel method to process all tasks in parallel and use the Reduce method to compute the final result. The console output is as follows:

Total Points (all Tasks) : 26.0Copy the code

For a set, it is often necessary to group the elements according to certain conditions. This can be done quickly using the API provided by Steam as follows:

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

The console output is as follows:

{CLOSED=[[CLOSED, 8]], OPEN=[[OPEN, 5], [OPEN, 13]]}Copy the code

The final example of a task set is how to calculate the number of points per task in the set as a percentage of the set, as follows:

// 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 );Copy the code

The console output is as follows:

(19%, 50%, 30%]Copy the code

Finally, as mentioned earlier, the Steam API doesn’t just work with Java collections. Traditional IO operations (reading data line by line from a file or network) can benefit from Steam processing. Here’s a quick 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 ); }Copy the code

The Stream method onClose returns an equivalent Stream with an extra handle that is executed when the Stream’s close () method is called. The Stream API, Lambda expressions, 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 the Date/Time API (JSR 310)

Java 8 introduces a new date-time API(JSR 310) to improve Time and Date handling. Time and date management has been one of the most painful issues for Java developers. Java.util. Date and later Java.util. Calendar never solved this problem (and made it even more confusing for developers).

For these reasons, a third-party library, Joda-Time, was created to replace Java’s Time management API. The new Time and date management API in Java 8 is heavily influenced by joda-time and incorporates much of the best of Joda-time. The new Java.time package includes all classes for date, time, time zone, Instant (date-like but accurate to nanosecond), Duration, and clock manipulation. The newly designed API takes into account the immutability of these classes (lessons learned from java.util.calendar) and returns a new object if an instance needs to be modified.

Let’s take a look at the key classes in the java.time package and their respective use examples. First, the Clock class uses the time zone 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() );Copy the code

The output of this example is:

The 2014-04-12 T15: do. 1397315969360 282 zCopy the code

Second, look at the LocalDate and LocalTime classes. LocalDate contains only the date part of the ISO-8601 calendar system; LocalTime contains only the time portion of the calendar system. Objects for both classes can be built using the Clock object.

// 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 );Copy the code

The output of the above example is as follows:

The 2014-04-12 2014-04-12 11:25:54. 568 15:25:54. 568Copy the code

The LocalDateTime class contains information about LocalDate and LocalTime, but not the 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 );Copy the code

The output of this example is as follows:

: the 2014-04-12 T11 37:52. 309 2014-04-12 T15:37:52. 309Copy the code

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 and sometimes blocks the 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 );Copy the code

The output of this example is:

: the 2014-04-12 T11 47:01. 017-04:00 America/New_York T15:2014-04-12 47:01. 017 z The 2014-04-12 T08:47:01. 017-07:00 [America/Los_Angeles]Copy the code

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

// 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() );Copy the code

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: 8783Copy the code

The overall impression of the new Java 8 date and Time is positive, partly because of the positive impact of Joda-time and partly because officials are finally listening to the needs of developers. For more details, please refer to the official documentation.

4.4 Nashorn JavaScript Engine

Java 8 provides the new Nashorn JavaScript engine that allows you to develop and run JS applications on the JVM. Nashorn JavaScript engine is javax.mail. Script. Another a ScriptEngine implementation version, this kind of script engine, follow the same rules allow Java and JavaScript interaction is used, 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;" ));Copy the code

The output of this code is as follows:

jdk.nashorn.api.scripting.NashornScriptEngine
Result: 2Copy the code

4.5 Base64

Support for Base64 encoding has been added to the official Java 8 library so that it can be done without using third-party libraries, as shown in the following 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!";

        final String encoded = Base64
            .getEncoder()
            .encodeToString( text.getBytes( StandardCharsets.UTF_8 ) );
        System.out.println( encoded );

        final String decoded = new String( 
            Base64.getDecoder().decode( encoded ),
            StandardCharsets.UTF_8 );
        System.out.println( decoded );
    }
}Copy the code

The output of this example is as follows:

QmFzZTY0IGZpbmFsbHkgaW4gSmF2YSA4IQ==
Base64 finally in Java 8!Copy the code

The new Base64API also supports URL and MINE encoding and decoding. (Base64.getUrlEncoder()/base64. getUrlDecoder(), base64. getMimeEncoder()/base64. getMimeDecoder())).

BASE64 is not used for encryption, but is a BASE64 encoded string, consisting entirely of standard keyboard characters, so that the encoded string is not generated between gatewaysUNICODEUnrecognized or missing strings. Look into it a little bit moreEMAILYou'll see that actuallyEMAILIt's base64 encoded and sent. And then undo it when you receive it.Copy the code

4.6 Parallel Arrays

The Java8 release has added many new methods to support parallel array processing. The most important method is parallelSort(), which dramatically speeds up array sorting on multicore machines. The following example demonstrates the method 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 -> ThreadLocalRandom.current().nextInt( 1000000 ) ); Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) ); System.out.println(); Arrays.parallelSort( arrayOfLong ); Arrays.stream( arrayOfLong ).limit( 10 ).forEach( i -> System.out.print( i + " " ) ); System.out.println(); }}Copy the code

The code above uses the parallelSetAll() method to generate 20,000 random numbers, which are then sorted using the parallelSort() method. This program outputs the first 10 elements of an unordered and sorted array. The output of the above example code is:

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

4.7 concurrency

Based on new lambda expressions and characteristics of steam for Java 8 for Java. The util. Concurrent. ConcurrentHashMap class to add a new method to support the focus on operation; In addition, also for Java. Util. ConcurrentForkJoinPool class to add a new method to support the general thread pool operation (more content can refer to our concurrent programming courses).

Java 8 also added new Java. Util. Concurrent. The locks. StampedLock class, Support based on the capacity of the lock, the lock has the support of three model is used to read and write operations, can make the lock is a Java. Util. Concurrent. The locks. The ReadWriteLock replacement).

In Java. Util. Concurrent. Atomic package also added a lot of tools, listed as follows:

  • DoubleAccumulator
  • DoubleAdder
  • LongAccumulator
  • LongAdder

5. New Java tools

Java 8 provides 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 looks like this:

function f() { 
     return 1; 
}; 

print( f() + 1 );Copy the code

This command can be executed from the command line: JJS func.js, and the console output reads:

2Copy the code

For details, refer to the official documentation.

5.2 Class dependency analyzer: JDEPS

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

We can use JEDps to analyze the Spring Framework libraries. To minimize the results, we can analyze only one JAR file: org.springFramework.core-3.0.5.release.jar.

Jdeps org. Springframework. Core - 3.0.5. The jarCopy the code

This command produces a lot of results, but let’s look at just a few of them: dependencies are grouped by package, and “Not found” is displayed if the dependency is not 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 Java.io -> java.lang -> java.lang. Annotation -> java.lang. Ref -> java.lang -> java.lang. 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.utilCopy the code

More details can be found in the official documentation.

6. New JVM features

Metaspace (JEP 122) is used instead of PermGen space. For 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 features that increase productivity. Java 8 is not yet suitable for use in production systems, but the adoption rate is sure to increase over the next few months. Slow but improving). As a developer, it’s time to learn something about Java 8 and prepare for the upgrade.

About Spring: For enterprise-level development, we should also pay attention to the Spring community’s support for Java 8. See this article — a list of new Java 8 features supported by Spring 4

8. Reference materials

  • What’s New in JDK 8
  • The Java Tutorials
  • WildFly 8, JDK 8, NetBeans 8, Java EE
  • Java 8 Tutorial
  • JDK 8 Command-line Static Dependency Checker
  • The Illuminating Javadoc of JDK
  • The Dark Side of Java 8
  • Installing Java™ 8 Support in Eclipse Kepler SR2
  • Java 8
  • Oracle Nashorn. A Next-Generation JavaScript Engine for the JVM