[Reading Notes] "Java SE 8 for Busy People" - Summary of New Features of Java 8

read table of contents

back to the top

Default and static methods in interfaces

First consider a question, how to add methods to the collection library in Java? For example in Java 8 a forEach method was added to the Collection interface.

Before Java 8, for the interface, the methods in it must be abstract methods, that is to say, the implementation of the interface is not allowed in the interface, then every class that implements the Collection interface needs to implement a forEach method.

But this will affect the existing implementation while adding new methods to the interface, so the Java designers introduced the interface default method, the purpose is to solve the problem that the modification of the interface is incompatible with the existing implementation, the interface default method Methods can be used as a means of forward compatibility between libraries and frameworks.

A default method is like a normal Java method, except that the method is decorated with the default keyword.

Here's a simple example

copy code

public interface Person {
    //default method
    default String getName(String name) {
        return name;
    }
}
///////////////////////////////////////////////////////////////////////
public class Student implements Person {

}
//////////////////////////////////////////////////////////////////////
public class Test {
    public static void main(String[] args) {
        Person p = new Student();
        String name = p.getName("小李");
        System.out.println(name);
    }
}

copy code

We define a Person interface, where getName is a default method. Then write an implementation class. You can see from the result that although Student is empty, the getName method can still be implemented.

Obviously, the appearance of the default interface breaks some of the previous basic rules, and there are several issues to pay attention to when using it.

Consider if an interface defines a default method, and another parent class or interface defines a method with the same name, which one to choose?

1.  Select the interface in the parent class. If a parent class provides a concrete implementation method, the default method in the interface with the same name and parameters will be ignored.

2.  Interface conflict. If a parent interface provides a default method, and another interface also provides a method with the same name and parameter types (regardless of whether the method is a default method or not), then it must be resolved by overriding the method.

Remember the principle of "class first" , that is, when both a class and an interface have a method with the same name, only the method in the parent class will work.

The "class first" principle guarantees compatibility with Java 7. If you add a default method to an interface, it will have no effect on code written prior to Java 8.

Let's talk about static methods .

A static method is like a normal Java static method, but the permission modification of the method can only be public or not written.

Default methods and static methods make Java more feature-rich.

Four default methods were added to the Collection interface in Java 8, stream(), parallelStream(), forEach() and removeIf(). The Comparator interface also adds many default and static methods.

back to the top

Functional Interfaces and Lambda Expressions

A functional interface is an abstract interface that contains only one method.

For example, java.lang.Runnable and java.util.concurrent.Callable in the Java standard library are typical functional interfaces.

In Java 8 , an interface is marked as a functional interface through the @FunctionalInterface annotation, and the interface can only contain one abstract method.

The @FunctionalInterface annotation is not required, as long as the interface contains only one abstract method, the virtual machine will automatically determine that the interface is a functional interface.

It is generally recommended to use the @FunctionalInterface annotation on the interface to prevent others from adding new methods to the interface by mistake. If a second abstract method is defined in your interface, the compiler will report an error.

The functional interface is designed for lambdas in Java 8, and the method body of the lambda expression is actually the implementation of the functional interface.

Why use lambda expressions?

A "lambda expression" is a passable piece of code because it can be executed one or more times. Let's start by reviewing similar blocks of code that have been used in Java before.

When we execute some logic in a thread, we usually put the code in the run method of a class that implements the Runnable interface , like this:

copy code

new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++)
                    System.out.println("Without Lambda Expression");
            }}).start();

copy code

Then start a new thread by creating the instance. The run method contains the code that needs to be executed in a new thread.

Let's look at another example, if you want to use string length sorting instead of the default lexicographical sorting, you need to customize a class that implements the Comparator interface, and then pass the object to the sort method.

copy code

class LengthComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }
}
Arrays.sort(strings, new LengthComparator());

copy code

Button callbacks are another example. Put the callback operation in a method of a class that implements the listener interface.

copy code

JButton button = new JButton("click");

button.addActionListener(new ActionListener() {    
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Without Lambda Expression");
    }
});

copy code

In all three examples, the same way a piece of code is passed to other callers—a new thread, a sort method, or a button. This code will be called later.

Passing code around in Java is not very easy, it is impossible to pass code blocks around. You have to construct an object of a class that contains the required code in one of its methods.

The lambda expression is actually the implementation of the passing of the code block. Its grammatical structure is as follows:

(parameters) -> expression 或者 (parameters) -> {statements;}

Parameters in parentheses can omit their type, and the compiler will deduce the type of the parameter according to the context. You can also specify the parameter type explicitly. If there are no parameters, the parentheses can be empty.

The method body, if there are multiple lines of function statements enclosed in curly brackets, if there is only one line of function statements, the curly brackets can be omitted.

new Thread(() -> {
            for (int i = 0; i < 100; i++)
                System.out.println("Lambda Expression");
        }).start();
Comparator<String> c = (s1, s2) -> Integer.compare(s1.length(), s2.length());
button.addActionListener(e -> System.out.println("Lambda Expression"));

You can see that lambda expressions make the code simpler, replacing anonymous inner classes.

Let's talk about method references , which are a shorthand form of lambda expressions. A method reference can be used if the lambda expression just calls a specific already existing method.

Use the " :: " operator to separate the method name from the object or class name. Here are four use cases:

  • object::instance method
  • class::static method
  • class::instance method
  • class::new
Arrays.sort(strings, String::compareToIgnoreCase);
// Equivalent to
Arrays.sort(strings, (s1, s2) -> s1.compareToIgnoreCase(s2));

The code above is the third case, again simplifying the lambda expression.

back to the top

Stream API

When dealing with collections, it is common to iterate over all elements and process each of them. For example, we want to count all elements whose length is greater than 3 in an array of string type.

copy code

String[] strArr = { "Java8", "new", "feature", "Stream", "API" };
        int count = 0;
        for (String s : strArr) {
            if (s.length() > 3)
                count++;
        }

copy code

Usually we use this code for statistics, and there is no error, but it is difficult to be calculated in parallel. This is also the reason why Java8 introduced a large number of operators. In Java8, the operators that achieve the same function are as follows:

long count = Stream.of(strArr).filter(w -> w.length() > 3).count();

The stream method produces a Stream for a list of strings . The filter method will return a Stream that only contains strings whose length is greater than 3, and then count them by the count method.

A Stream is superficially similar to a Collection, allowing you to mutate and retrieve data, but it's actually quite different:

  1. Stream itself does not store elements . Elements may be stored in the underlying collection, or generated on demand.
  2. The Stream operator does not mutate the source object . Instead, they return a Stream that holds the new results.
  3. Stream operators may be executed lazily . Meaning they will wait until the result is needed before executing.

Streams are more readable than looping operations. and can be computed in parallel:

long count = Arrays.asList(strArr).parallelStream().filter(w -> w.length() > 3).count();

Just change the stream method to parallelStream to allow Stream to perform filtering and statistical operations in parallel.

Stream follows the principle of " what to do, not how to do it ". Just describe what needs to be done, regardless of how the program is implemented.

Stream is much like Iterator, one-way, it can only be traversed once. But Stream can implement multi-threaded parallel computing with only one line of code.

When using Stream, there are three phases:

  1. Create a Stream.
  2. An intermediate operation that converts an initial Stream to another Stream in one or more steps .
  3. Use a terminating operation to produce a result. This action forces his previous delayed action to execute immediately. After this, the Stream will not be used anymore.

From the perspective of three stages, corresponding to three types of methods, the first is the creation method of Stream.

copy code

// 1. Individual values
Stream stream = Stream.of("a", "b", "c");
// 2. Arrays
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 3. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();

copy code

Intermediate operations include: map (mapToInt, flatMap, etc.), filter, distinct, sorted, peek, limit, skip, parallel, sequential, unordered.

终止操作包括:forEach、forEachOrdered、toArray、reduce、collect、min、max、count、anyMatch、allMatch、noneMatch、findFirst、findAny、iterator。

How to use each method of Stream will not be expanded. For a more detailed introduction, see this article: https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

back to the top

New date and time API

Java8 introduced a new date and time API, located under the java.time package.

The new date and time API borrows from the Joda Time library, written by the same person, but they are not exactly the same, with many improvements.

Below are some commonly used classes. The first is Instant , an Instant object that represents a point on the timeline.

Instant.now() returns the current instant ( Greenwich Mean Time ). Instant.MIN and Instant.MAX are a billion years ago and a billion years later.

The following code can calculate the running time of an algorithm:

copy code

Instant start = Instant.now();
runAlgorithm();
Instant end = Instant.now();
Duration timeElapsed = Duration.between(start, end);
long millis = timeElapsed.toMillis();

copy code

A Duration object represents the amount of time between two instants. It can be converted into various time units through different methods.

The absolute time mentioned above does not apply to life, so the new Java API provides two kinds of human time, local date/time and time with time zone .

LocalDate is a date with year, month and day. It can be created using the static methods now or of.

copy code

LocalDate today = LocalDate.now();
LocalDate myBirthday = LocalDate.of(1994, 03, 15);
// use Enum
myBirthday = LocalDate.of(1994, Month.MARCH, 15);

System.out.println(today); // 2017-10-23
System.out.println(myBirthday); // 1994-03-15

copy code

Here are some common methods in LocalDate:

LocalTime represents a certain time of day, and you can also use now or of to create an instance.

LocalTime rightNow = LocalTime.now();
LocalTime bedTime = LocalTime.of(2, 0);
System.out.println(rightNow); // 01:26:17.139
System.out.println(bedTime); // 02:00

LocalDateTime represents a date and time, and the usage is similar to the above.

The above date and time classes belong to local time. Let's talk about the time with time zone.

ZonedDateTime creates a time zoned time by setting the id of the time zone.

ZonedDateTime beijingOlympicOpenning = ZonedDateTime.of(2008, 8, 8, 20, 0, 0, 0, ZoneId.of("Asia/Shanghai"));
System.out.println(beijingOlympicOpenning); // 2008-08-08T20:00+08:00[Asia/Shanghai]

The updated API also adds a new formatter class DateTimeFormatter . DateTimeFormatter provides three formatting methods to print date/time:

  • predefined standard formats
String formattered = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(beijingOlympicOpenning);
System.out.println(formattered); // 2008-08-08T20:00:00

The DateTimeFormatter class provides a variety of predefined standard formats to use.

  • Locale Dependent Format

The standard format is mainly used for machine-readable timestamps. In order for people to understand the date and time, you need to use a locale-dependent format.

Java8 provides 4 styles, SHORT, MEDIUM, LONG, FULL.

String formattered = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).format(beijingOlympicOpenning);
System.out.println(formattered); //Friday, August 8, 2008 08:00:00 PM CST
  • custom format

Or you can also customize the format of date and time.

String formattered = DateTimeFormatter.ofPattern("E yyyy-MM-dd HH:mm").format(beijingOlympicOpenning);
System.out.println(formattered); // Fri 2008-08-08 20:00

  The following figure shows some common pattern elements.

The new API provides a parse static method for parsing a date/time from a string and a method for converting to and from legacy classes (java.util.Date, java.sql.Time, java.txt.DateFormat, etc.).

back to the top

Miscellaneous improvements

 Java8 only adds a new method to the String class, which is join , which implements the splicing of strings and can be regarded as the inverse operation of the split method.

String joined = String.join(".", "www", "cnblogs", "com");
System.out.println(joined); // www.cnblogs.com

The number wrapper class provides the BYTES static method, which returns the length in bytes.

All eight wrapper classes provide a static hashCode method.

The five types Short, Integer, Long, Float, and Double provide sum, max, and min, respectively, for use as aggregate functions in stream operations.

Methods added to collection classes and interfaces:

Java 8 provides some convenience methods ( Files.lines and Files.list ) for reading file lines and accessing directory entries using streams. It also provides a method for Base64 encoding/decoding.

Java8 has also improved GUI programming ( JavaFX ), concurrency and other aspects, which are not listed in this article.

Please indicate the original link for reprint: http://www.cnblogs.com/justcooooode/p/7701260.html

back to the top

References

"Java SE 8 for Busy People"

http://study.163.com/course/introduction/1003856028.htm

https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325126709&siteId=291194637