JAVA8给我带了什么——并行流和接口新功能

流,肯定是笔者心里很向往的天堂,有他以后JAVA在处理数据就变动加的灵动。加上lambda表达不喜欢都不行。JAVA8也为流在提供另外一个功能——并行流。便是有并行流,那么是否是也有顺序流。没有错。我前面操做的通常都是顺序流。在JAVA8里面并行流和顺序流是能够转变的。来看一个例子——笔者打印数字。java

 1 package com.aomi;
 2 
 3 import java.util.stream.LongStream;
 4 
 5 public class Main {
 6 
 7     public static void main(String[] args) {
 8         // TODO Auto-generated method stub
 9 
10         LongStream.range(0, 10).forEach(i -> {
11             System.out.print(i + " ");
12         });
13     }
14 
15 }

LongStream.range这个方法是来获取数字的。这里表示得到0到10,但不含10 的数字。运行结果:编程

如今让咱们把他换成并行来看看。框架

 1 package com.aomi;
 2 
 3 import java.util.stream.LongStream;
 4 
 5 public class Main {
 6 
 7     public static void main(String[] args) {
 8         // TODO Auto-generated method stub
 9 
10         LongStream.range(0, 10).parallel().forEach(i -> {
11             System.out.print(i + " ");
12         });
13     }
14 
15 }

运行结果:ide

俩个结果相比一下,咱们就能够明显他们发生了变化。咱们只是加一个parallel函数就发生好多的变化。笔者原本是要讲他们之间的性能比较的。不敢,由于笔者试好还有个例子。却发现有时候顺序流都比并行流来快。上面是顺序流转并行流。在来看一下相反的。函数

1 public static void main(String[] args) {
2         // TODO Auto-generated method stub
3 
4         List<Integer> datas = Arrays.asList(1,2,3,4,56);
5         
6         datas.parallelStream().forEach(i -> {
7             System.out.print(i + " ");
8         });
9     }

parallelStream函数就是用来建一个并行流的。运行结果:性能

转为顺序流this

1 public static void main(String[] args) {
2         // TODO Auto-generated method stub
3 
4         List<Integer> datas = Arrays.asList(1,2,3,4,56);
5         
6         datas.parallelStream().sequential().forEach(i -> {
7             System.out.print(i + " ");
8         });
9     }

 运行结果:spa

咱们都知道流里面用到了JAVA7里面的分支和合并的框架来进行的。古代有一个词叫分而治之。把一个事情分为几个小事件。然面各自处理。因此了解代码里面是什么样子折分红小事件是很是重要的。他有俩个关键字Fork和Join。Fork方法你能够理解为拆分,并压入线程队列中。而Join就是合并的意思了。来笔者来写一个试。线程

 1 package com.aomi;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 import java.util.concurrent.RecursiveTask;
 6 
 7 public class DistinctCharForkJoin extends RecursiveTask<List<Character>> {
 8 
 9     private List<Character> chars;
10 
11     public DistinctCharForkJoin(List<Character> chars) {
12         this(chars, 0, chars.size());
13     }
14 
15     public DistinctCharForkJoin(List<Character> chars, int start, int end) {
16 
17         this.chars = chars.subList(start, end);
18     }
19 
20     @Override
21     protected List<Character> compute() {
22         // TODO Auto-generated method stub
23         List<Character> tmpChars = new ArrayList<Character>();
24 
25         // 判断不能够在拆分了
26         if (this.chars.size() < 3) {
27 
28             for (Character character : chars) {
29                 if (!tmpChars.contains(character))
30                     tmpChars.add(character);
31             }
32 
33         } else {// 表示能够在拆分。
34 
35             int len = this.chars.size();
36 
37             // 创建左边的小事件
38             DistinctCharForkJoin leftForkJoin = new DistinctCharForkJoin(chars, 0, len / 2);
39 
40             leftForkJoin.fork();
41 
42             // 创建右边的小事件
43             DistinctCharForkJoin rightForkJoin = new DistinctCharForkJoin(chars, len / 2, len);
44 
45             rightForkJoin.fork();
46 
47             List<Character> rChars = rightForkJoin.join();
48 
49             List<Character> lChars = leftForkJoin.join();
50 
51             // 俩个合并。
52             for (Character character : rChars) {
53                 if (!tmpChars.contains(character))
54                     tmpChars.add(character);
55             }
56 
57             for (Character character : lChars) {
58                 if (!tmpChars.contains(character))
59                     tmpChars.add(character);
60             }
61 
62         }
63 
64         return tmpChars;
65     }
66 
67 }

Main:设计

 1 public static void main(String[] args) {
 2         // TODO Auto-generated method stub
 3 
 4         List<Character> chars = Arrays.asList('a', 'b', 'c', 'd', 'b', 'a');
 5 
 6         DistinctCharForkJoin task = new DistinctCharForkJoin("main", chars);
 7 
 8         List<Character> resChars = new ForkJoinPool().invoke(task);
 9 
10         for (Character character : resChars) {
11 
12             System.out.print(character +" ");
13         }
14     }

运行结果:

大家必定很奇怪为何笔者会讲到JAVA7带来的东西呢?JAVA8引入了一个新的接口——Spliterator接口。人称可分迭代器。若是你有心去看一个接口List的话,你可能会发现一个方法。以下

1 default Spliterator<E> spliterator() {
2         return Spliterators.spliterator(this, Spliterator.ORDERED);
3     }

Spliterator接口:

1 public interface Spliterator<T> {
2     boolean tryAdvance(Consumer<? super T> action);
3     Spliterator<T> trySplit();
4     long estimateSize();
5     int characteristics();
6 }

讲JAVA7里面的分支/合并的目地就是为了理解Spliterator接口的做用。以下

  • tryAdvance:用于遍历当前的元素。若是还有的话,就返回true;
  • trySplit:用于拆分。若是当前不能够在拆分的话,就返回null;跟上面的compute方法很像。
  • estimateSize:表示还须要遍历的元素有多少。
  • characteristics:表示当前处理的数据是什么样子的。好比是否有序,每一元素是否为null。上面Spliterator接口的代码是笔者去掉大部分复制出来。这个值都在代码中。做用大家能够本身去看一下代码就是知道。

要注意Spliterator接口只是用去拆分任务的做用。JAVA8帮你作了不少拆分的功能。大部分你能够不用本身写。固然若是你想要本身动手。你只要实现这样子就能够了。以下

 1 package com.aomi;
 2 
 3 import java.util.List;
 4 import java.util.Spliterator;
 5 import java.util.function.Consumer;
 6 
 7 public class DistinctCharSpliterator implements Spliterator<Character> {
 8 
 9     private List<Character> chars;
10     private int index = 0;
11 
12     public DistinctCharSpliterator(List<Character> chars) {
13         this.chars = chars;
14     }
15 
16     public DistinctCharSpliterator(List<Character> chars, int start, int end) {
17         this.chars = chars.subList(start, end);
18     }
19 
20     @Override
21     public boolean tryAdvance(Consumer<? super Character> action) {
22         // TODO Auto-generated method stub
23         action.accept(this.chars.get(index++));
24         return index < this.chars.size();
25     }
26 
27     @Override
28     public Spliterator<Character> trySplit() {
29         // TODO Auto-generated method stub
30         int difLen = this.chars.size() - index;
31 
32         // 判断不能够在拆分了
33         if (difLen < 3) {
34             return null;
35         } else {// 表示能够在拆分。
36 
37             
38             DistinctCharSpliterator spliterator = new DistinctCharSpliterator(chars.subList(index, index + 2));
39 
40             index = index + 2;
41 
42             return spliterator;
43 
44         }
45     }
46 
47     @Override
48     public long estimateSize() {
49         // TODO Auto-generated method stub
50         return this.chars.size() - index;
51     }
52 
53     @Override
54     public int characteristics() {
55         // TODO Auto-generated method stub
56         // 有序 元素不空 遍历过程不能删除,和修改 增长
57         return ORDERED + NONNULL + IMMUTABLE;
58     }
59 
60 }

Main:

 1 public static void main(String[] args) {
 2         // TODO Auto-generated method stub
 3 
 4         List<Character> chars = Arrays.asList('a', 'b', 'c', 'd', 'b', 'a');
 5 
 6         DistinctCharSpliterator distinctCharSpliterator = new DistinctCharSpliterator(chars);
 7 
 8         Stream<Character> stream = StreamSupport.stream(distinctCharSpliterator, true);
 9 
10         stream.distinct().forEach((Character ch) -> {
11 
12             System.out.print(ch+" ");
13         });
14 
15     }

运行结果:

上面的例子有一点烂。可是你们能够复制作一下继点去看看他的执行过程。就能够看出不少东西来。主要是理解这个原理就能够了。
流的并行功能并无让笔者有多心动。真正让笔者感受不错的要属于JAVA8对接口的升级。什么意思?笔者不清楚有多少我的写个框架或是读过框架源码,通常框架里面都会用到一些面向接口的编程模式。那个或多或少会有这样子感受。一但项目发布出去,这个时候你想要修改接口。好比在接口里面增长一个新的功能方法。这样子时候你就不得不考虑一下外面有多少我的在实现你如今框架的接口。由于你增长一个接口的新方法。别人也要跟着实现,否则的必定会报错或是运行时候报错。无论哪种都是设计者不想看到的。
JAVA8如今可让你定义接口的默认方法。什么思意呢?让笔得写一个例子。

Base接口:

1 package com.aomi;
2 
3 public interface Base {
4     void call();
5 }

BaseA类:

 1 package com.aomi;
 2 
 3 public class BaseA implements Base {
 4 
 5     @Override
 6     public void call() {
 7         
 8     }
 9 
10 }

Main:

 1 package com.aomi;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         // TODO Auto-generated method stub
 7 
 8         Base baseA = new BaseA();
 9 
10         baseA.call();
11     }
12 }

上面的代码没有什么特别的。如今笔者在加一个方法。看一个他会不会有问题。以下

base类:

1 package com.aomi;
2 
3 public interface Base {
4     void call();
5     void call2();
6 }

结果:

看到吧。BaseA类立刻就报错。如今笔者在加上一个默认的方法会什么呢?

package com.aomi;

public interface Base {
    void call();

    default void call2() {
        System.out.println("default call2");
    }
}

Main修改一下吧。

 1 package com.aomi;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         // TODO Auto-generated method stub
 7 
 8         Base baseA = new BaseA();
 9 
10         baseA.call2();
11     }
12 }

运行结果:

上面的代码。笔者在BaseA类里面并无实现call2的方法。显然如今的功能对咱们写框架的人来写太棒了。在也不用担忧增长一个接方法而去考虑有多少我的用这个接口了。
那么问题来了。咱们在写代码的过程当中,必定会遇到方法相同的状况吧。这个时候JAVA8提供了三个标准来肯定用哪个。

  1. 类或父类的方法优先级高于接口默认的方法。
  2. 若是上面不行的话,谁拥有最具体的实现的话,就用谁。
  3. 若是都不能肯定的状况下,就必须显性的调用。来指定他要调哪个。

举例子。A和B都是接口。其中B继承了A。同时C实现了A和B。这个时候调用C会是什么样子。
A:

public interface A {

    default void call() {
        System.out.println("A call");
    }
}

B:

public interface B  extends A {
    default void call() {
        System.out.println("B call");
    }
}

C:

public class C implements A, B {

}

D:

public static void main(String[] args) {
        // TODO Auto-generated method stub

        C c = new C();
        
        c.call();

    }

运行结果:

上面A和B都是接口。他们有call方法。其中关键是B继承了。说明B拥有A的一切方法。那么是否是说B就是最具体实现的。若是大家只用第一个标准的话,那是确定不行的。
仍是简单一点,咱们把B继承A的这个关系去掉,在来看看。

很差意思好像报错了。因此只能苦一下了。显性调用。

package com.aomi;

public class C implements B, A {

    public void call() {
        B.super.call();
    }
}

 固然除了上面以外,你仍是能够定义静态方法和常量。这个时候有人就会说他不是跟抽象类很像吗?是很像。但是不同子。抽象类是否是能够实例一个字段。可是接口却不行。还有抽像类你只能单继承。接口就能够多继承了。

相关文章
相关标签/搜索