Java 8 Actual Warfare - Book Notes Chapter 1 (02)

Posted by Richter on Wed, 08 May 2019 07:25:04 +0200

From Method to Lambda

Then the last Predicate, let's go ahead and see if we continue to simplify the code.

It's useful to pass methods as values, but it's a bit annoying if there are a lot of things like isHeavyApple and isGreenApple that might define a bunch of methods only once or twice. To solve this problem, Java 8 introduces a new notation (anonymous functions or Lambda), which you can write as follows:

List<Apple> isRedApples = filterApples(FilteringApples.apples, apple -> "red".equals(apple.getColor()));

Or:

List<Apple> appleList = filterApples(FilteringApples.apples, apple -> apple.getWeight() < 120
                && "red".equals(apple.getColor()));

Even if you don't need to use the filter Apples method, you can solve it directly by using the filter method in Stream.

List<Apple> isGreenApple = apples.stream().filter(apple -> "green".equals(apple.getColor()))
                .collect(Collectors.toList());

Cool. It looks good. So you don't even need to write definitions for a one-time approach; the code looks simpler and clearer because you don't have to find out what code you're passing.

flow

In the process of screening apples, one of the methods used in Stream is Stream, which is totally different from InputStream and OutputStream. Stream is a core new feature of Java 8. It is a new set of API s for collections processing. There are many methods like filter, which are very simple and concise to use. Stream can simplify most of the code and use multi-core CPU in parallel. It can effectively improve the performance of collections processing.

This chapter is just a brief introduction to the use of streams, and the detailed use of streams will be mentioned in the following chapters.

Now, there's a string of strings that need to be filtered and capitalized for sorting, which we did before Java 8:

List<String> stringList = Arrays.asList("a1", "a2", "b1", "c1", "c2", "c4", "c3");

List<String> cList = new ArrayList<>();
for (String s : stringList) {
    // Screen out strings starting with c
    if (s.startsWith("c")) {
        // To add to the collection, convert the string starting with c to uppercase
        cList.add(s.toUpperCase());
    }
}

// sort
Collections.sort(cList);

// Traversal printing
for (String s : cList) {
    System.out.println(s);
}

This code looks like a headache and needs to be written for such a long period of time. Stream can be used to optimize in Java 8:

List<String> stringList = Arrays.asList("a1", "a2", "b1", "c1", "c2", "c4", "c3");

stringList.stream()
        // Screen out strings starting with c
        .filter(s -> s.startsWith("c"))
        // Convert the string just beginning with c to uppercase
        .map(String::toUpperCase)
        // sort
        .sorted()
        // Cyclic traversal
        .forEach(System.out::println);

That's great. It only takes a short line of code to do it! However, using Stream also has its drawbacks, its performance is not as efficient as foreach to solve this problem, Stream supports and. Using parallelism can make great use of the advantages of multi-core CPUs, such as: these codes were originally processed with a single core, but now there is an 8-core CPU, so its processing speed will be eight times faster than that of a single core.

Let's compare, generate a 0-100 number and write it into a file, which is more efficient for sequential flow VS parallel flow.

Sequential flow:

long startTime = System.currentTimeMillis();
OutputStream out = new FileOutputStream(new File("D:/integer1.txt"));

IntStream.rangeClosed(0, 100)
        .forEach(i -> {
            try {
                Thread.sleep(100L);
                out.write(i);
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        });

long endTime = System.currentTimeMillis();
System.out.println("Sequential flow:" + (endTime - startTime));

Parallel flows:

long startTime = System.currentTimeMillis();
OutputStream out = new FileOutputStream(new File("D:/integer2.txt"));

IntStream.rangeClosed(0, 100)
        .parallel().forEach(i -> {
    try {
        Thread.sleep(100L);
        out.write(i);
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
    }
});

long endTime = System.currentTimeMillis();
System.out.println("Parallel flows:" + (endTime - startTime));

Execution results (I 5-6200U laptop execution results):

Sequential flow: 10251
 Parallel flow: 2620

Efficiency is obviously much faster than sequential flow. However, parallel streaming is not omnipotent. If you remove sleep and add the number to 1 million, you will find that it takes longer to run than sequential streaming.

Removing sleep and generating numbers of 0-1 million takes time:

Sequential flow: 2775
 Parallel flow: 3346

As to why parallel flow is sometimes less efficient than sequential flow, this article will explain later.

Default method

The default method is a new feature in Java 8, which makes interface upgrades smoother because subclasses do not have to explicitly implement methods in interfaces anymore.

For example, in Java 8, you can directly call the sort method in the List interface, which is implemented by default method as shown below in the Java 8 List interface:

default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

This means that no entity classes in List need to implement sort explicitly, and in previous Java versions, these entity classes could not be compiled and passed unless an implementation of sort was provided. However, there are some problems with the default method. A class can implement multiple interfaces, so many interfaces have the same default method. Does this mean that there is some form of multi-inheritance in Java? If it is multi-inheritance, will there be problems like diamond inheritance in C++? These problems will be explained and solved in future articles.

Chapter 1 summarizes:

  1. Understanding some of the core new features in Java 8, such as Lambda expressions, Stream, default methods.
  2. Understanding the simplicity of Lambda expressions and Stream for code.
  3. Benefits of parallel flow.
  4. The benefits of default methods in Java 8.

Code case:

chap1

Topics: Java Lambda less