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

  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(, ).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(, ).parallel().forEach(i -> {
  11. System.out.print(i + " ");
  12. });
  13. }
  14.  
  15. }

运行结果:

俩个结果相比一下,我们就可以明显他们发生了变化。我们只是加一个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函数就是用来建一个并行流的。运行结果:

转为顺序流

  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. }

运行结果:

我们都知道流里面用到了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. DistinctCharSpliterator spliterator = new DistinctCharSpliterator(chars.subList(index, index + 2));
  38.  
  39. index = index + 2;
  40.  
  41. return spliterator;
  42.  
  43. }
  44. }
  45.  
  46. @Override
  47. public long estimateSize() {
  48. // TODO Auto-generated method stub
  49. return this.chars.size() - index;
  50. }
  51.  
  52. @Override
  53. public int characteristics() {
  54. // TODO Auto-generated method stub
  55. // 有序 元素不空 遍历过程不能删除,和修改 增加
  56. return ORDERED + NONNULL + IMMUTABLE;
  57. }
  58.  
  59. }

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类马上就报错。现在笔者在加上一个默认的方法会什么呢?

  1. package com.aomi;
  2.  
  3. public interface Base {
  4. void call();
  5.  
  6. default void call2() {
  7. System.out.println("default call2");
  8. }
  9. }

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:

  1. public interface A {
  2.  
  3. default void call() {
  4. System.out.println("A call");
  5. }
  6. }

B:

  1. public interface B extends A {
  2. default void call() {
  3. System.out.println("B call");
  4. }
  5. }

C:

  1. public class C implements A, B {
  2.  
  3. }

D:

  1. public static void main(String[] args) {
  2. // TODO Auto-generated method stub
  3.  
  4. C c = new C();
  5.  
  6. c.call();
  7.  
  8. }

运行结果:

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

不好意思好像报错了。所以只能苦一下了。显性调用。

  1. package com.aomi;
  2.  
  3. public class C implements B, A {
  4.  
  5. public void call() {
  6. B.super.call();
  7. }
  8. }

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

JAVA8给我带了什么——并行流和接口新功能的更多相关文章

  1. 【Java8新特性】关于并行流与串行流,你必须掌握这些!!

    写在前面 提到Java8,我们不得不说的就是Lambda表达式和Stream API.而在Java8中,对于并行流和串行流同样做了大量的优化.对于并行流和串行流的知识,也是在面试过程中,经常被问到的知 ...

  2. java8学习之收集器枚举特性深度解析与并行流原理

    首先先来找出上一次[http://www.cnblogs.com/webor2006/p/8353314.html]在最后举的那个并行流报错的问题,如下: 在来查找出上面异常的原因之前,当然得要一点点 ...

  3. Java8新特性 并行流与串行流 Fork Join

    并行流就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流. Java 8 中将并行进行了优化,我们可以很容易的对数据进行并 行操作. Stream API 可以声明性地通过 para ...

  4. 在使用Java8并行流时的问题分析

    最近在使用Java8的并行流时遇到了坑,线上排查问题时花了较多时间,分享出来与大家一起学习与自查 // 此处为坑 List<Java8Demo> copy = Lists.newArray ...

  5. java8新特性——并行流与顺序流

    在我们开发过程中,我们都知道想要提高程序效率,我们可以启用多线程去并行处理,而java8中对数据处理也提供了它得并行方法,今天就来简单学习一下java8中得并行流与顺序流. 并行流就是把一个内容分成多 ...

  6. Java8并行流使用注意事项

    对于从事Java开发的童鞋来说,相信对于Java8的并行流并不陌生,没错,我们常常用它来执行并行任务,但是由于并行流(parallel stream)采用的是享线程池,可能会对我们的性能造成严重影响, ...

  7. Java8新特性 - 并行流与串行流

    并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API可以声明性地通过parallel()和 ...

  8. java8学习之自定义收集器深度剖析与并行流陷阱

    自定义收集器深度剖析: 在上次[http://www.cnblogs.com/webor2006/p/8342427.html]中咱们自定义了一个收集器,这对如何使用收集器Collector是极有帮助 ...

  9. 避坑 | Java8使用并行流(ParallelStream)注意事项

    示例分析 /** * 避坑 | Java8使用并行流(ParallelStream)注意事项 * * @author WH.L * @date 2020/12/26 17:14 */ public c ...

随机推荐

  1. pyenv+virtual 笔记

    Pyenv + virtualEnv 设置 安装这两个组件是为了适应不同版本的python在同一个系统下的运行:例如现在最明显就是python2.7和python3.6的两个版本,很多库依旧是使用了P ...

  2. 干货,比较全面的c#.net公共帮助类(Common.Utility)

    Common.Utility 初衷 网上有各式各样的帮助类,公共类,但是比较零碎,经常有人再群里或者各种社交账号上问我有没有这个helper,那个helper,于是萌生了收集全部helper的念头,以 ...

  3. Mysql读写分离方案-Amoeba环境部署记录

    Mysql的读写分离可以使用MySQL Proxy,也可以使用Amoeba.Amoeba(变形虫)项目是一个类似MySQL Proxy的分布式数据库中间代理层软件,是由陈思儒开发的一个开源的java项 ...

  4. 《Linux内核设计与实现》读书笔记 4 进程调度

    第四章进程调度 进程调度程序可看做在可运行太进程之间分配有限的处理器时间资源的内核子系统.调度程序是多任务操作系统的基础.通过调度程序的合理调度,系统资源才能最大限度地发挥作用,多进程才会有并发执行的 ...

  5. 使用代理创建连接池 proxyPool

    配置文件properties url=jdbc:mysql://127.0.0.1:3306/mine?characterEncoding=UTF-8 user=root password=1234 ...

  6. 个人项目Individual Project:迷宫求解

    源码的github链接:           https://github.com/zhangxue520/test 1.1问题描述: a.问题描述:以一个m * n的长方阵表示迷宫,0和1分别表示迷 ...

  7. 剑指offer:字符串的排列

    题目描述: 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: ...

  8. Windows 7 64位安装cURL

    安装cURL. 1, 下载64位的SSL版cURL,网址: http://curl.download.nextag.com/download/curl-7.21.7-win64-ssl-sspi.zi ...

  9. 传参在mybatis的sql映射文件中正确获取

    1.单个参数: 非自定义对象 传参:getStuById(Integer id): 取值:#{id} 单个基本类型参数,随便取值都行:#{ok} 对象: 传参:saveStudent(Student ...

  10. Aop事务小结(事务管理器和自身构建)

    声明市事务是利用AOP来实现的. 1.采用事务管理器AOP: <!--3.配置事务切面:控制住连接池 --> <bean id="transactionManager&qu ...