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

 package com.aomi;

 import java.util.stream.LongStream;

 public class Main {

     public static void main(String[] args) {
// TODO Auto-generated method stub LongStream.range(, ).forEach(i -> {
System.out.print(i + " ");
});
} }

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

现在让我们把他换成并行来看看。

 package com.aomi;

 import java.util.stream.LongStream;

 public class Main {

     public static void main(String[] args) {
// TODO Auto-generated method stub LongStream.range(, ).parallel().forEach(i -> {
System.out.print(i + " ");
});
} }

运行结果:

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

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

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

转为顺序流

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

运行结果:

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

 package com.aomi;

 import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveTask; public class DistinctCharForkJoin extends RecursiveTask<List<Character>> { private List<Character> chars; public DistinctCharForkJoin(List<Character> chars) {
this(chars, 0, chars.size());
} public DistinctCharForkJoin(List<Character> chars, int start, int end) { this.chars = chars.subList(start, end);
} @Override
protected List<Character> compute() {
// TODO Auto-generated method stub
List<Character> tmpChars = new ArrayList<Character>(); // 判断不可以在拆分了
if (this.chars.size() < 3) { for (Character character : chars) {
if (!tmpChars.contains(character))
tmpChars.add(character);
} } else {// 表示可以在拆分。 int len = this.chars.size(); // 建立左边的小事件
DistinctCharForkJoin leftForkJoin = new DistinctCharForkJoin(chars, 0, len / 2); leftForkJoin.fork(); // 建立右边的小事件
DistinctCharForkJoin rightForkJoin = new DistinctCharForkJoin(chars, len / 2, len); rightForkJoin.fork(); List<Character> rChars = rightForkJoin.join(); List<Character> lChars = leftForkJoin.join(); // 俩个合并。
for (Character character : rChars) {
if (!tmpChars.contains(character))
tmpChars.add(character);
} for (Character character : lChars) {
if (!tmpChars.contains(character))
tmpChars.add(character);
} } return tmpChars;
} }

Main:

 public static void main(String[] args) {
// TODO Auto-generated method stub List<Character> chars = Arrays.asList('a', 'b', 'c', 'd', 'b', 'a'); DistinctCharForkJoin task = new DistinctCharForkJoin("main", chars); List<Character> resChars = new ForkJoinPool().invoke(task); for (Character character : resChars) { System.out.print(character +" ");
}
}

运行结果:

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

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

Spliterator接口:

 public interface Spliterator<T> {
boolean tryAdvance(Consumer<? super T> action);
Spliterator<T> trySplit();
long estimateSize();
int characteristics();
}

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

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

要注意Spliterator接口只是用去拆分任务的作用。JAVA8帮你做了很多拆分的功能。大部分你可以不用自己写。当然如果你想要自己动手。你只要实现这样子就可以了。如下

 package com.aomi;

 import java.util.List;
import java.util.Spliterator;
import java.util.function.Consumer; public class DistinctCharSpliterator implements Spliterator<Character> { private List<Character> chars;
private int index = 0; public DistinctCharSpliterator(List<Character> chars) {
this.chars = chars;
} public DistinctCharSpliterator(List<Character> chars, int start, int end) {
this.chars = chars.subList(start, end);
} @Override
public boolean tryAdvance(Consumer<? super Character> action) {
// TODO Auto-generated method stub
action.accept(this.chars.get(index++));
return index < this.chars.size();
} @Override
public Spliterator<Character> trySplit() {
// TODO Auto-generated method stub
int difLen = this.chars.size() - index; // 判断不可以在拆分了
if (difLen < 3) {
return null;
} else {// 表示可以在拆分。 DistinctCharSpliterator spliterator = new DistinctCharSpliterator(chars.subList(index, index + 2)); index = index + 2; return spliterator; }
} @Override
public long estimateSize() {
// TODO Auto-generated method stub
return this.chars.size() - index;
} @Override
public int characteristics() {
// TODO Auto-generated method stub
// 有序 元素不空 遍历过程不能删除,和修改 增加
return ORDERED + NONNULL + IMMUTABLE;
} }

Main:

 public static void main(String[] args) {
// TODO Auto-generated method stub List<Character> chars = Arrays.asList('a', 'b', 'c', 'd', 'b', 'a'); DistinctCharSpliterator distinctCharSpliterator = new DistinctCharSpliterator(chars); Stream<Character> stream = StreamSupport.stream(distinctCharSpliterator, true); stream.distinct().forEach((Character ch) -> { System.out.print(ch+" ");
}); }

运行结果:

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

Base接口:

 package com.aomi;

 public interface Base {
void call();
}

BaseA类:

 package com.aomi;

 public class BaseA implements Base {

     @Override
public void call() { } }

Main:

 package com.aomi;

 public class Main {

     public static void main(String[] args) {
// TODO Auto-generated method stub Base baseA = new BaseA(); baseA.call();
}
}

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

base类:

 package com.aomi;

 public interface Base {
void call();
void call2();
}

结果:

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

package com.aomi;

public interface Base {
void call(); default void call2() {
System.out.println("default call2");
}
}

Main修改一下吧。

 package com.aomi;

 public class Main {

     public static void main(String[] args) {
// TODO Auto-generated method stub Base baseA = new BaseA(); baseA.call2();
}
}

运行结果:

上面的代码。笔者在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();
}
}

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

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. 自从硬派网倒闭后,就没有什么好看的IT硬件网站了

    RT

  2. markdown操作手册

    **1.标题** # h1 h1自带分割线 ## h2 ### h3 #### h4 ##### h5 ###### h6 **2.圆点** - 圆点 **3.分割线,-和*都可以** --- *** ...

  3. 用EXCLE群发outlook邮件

    Outlookでメール一括送信する方法(差し込み.HTML形式.添付ファイル複数あり) メールを一括送信する方法はウェブ上にいくつも紹介されていましたが.以下のすべての条件を満たすものが見つからなかっ ...

  4. Linux下部署SSH登录时的二次身份验证环境记录(利用Google Authenticator)

    一般来说,使用ssh远程登录服务器,只需要输入账号和密码,显然这种方式不是很安全.为了安全着想,可以使用GoogleAuthenticator(谷歌身份验证器),以便在账号和密码之间再增加一个验证码, ...

  5. iOS实时查看App运行日志

    前言: 本文讨论如何实时查看输出在console控制台的日志. 一.Xcode 通过Window->Devices打开devices界面,选择我们的手机,也能看到手机中运行的进程输出的日志.如图 ...

  6. 对于windows 10使用感受

    windows 10是美国微软公司研发的新一代跨平台及设备应用的操作系统.在2015年7月29日12点起,windows 10推送全面开始,windows 7.windows 8 用户可以升级到win ...

  7. text2

    我的实践2代码已经传到GITHUb:https://github.com/jiaweihao/Test.git一下为测试结果截图:

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

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

  9. 最新一课 老师指点用Listview适配器

    上课前 <?xml version="1.0" encoding="utf-8"?>    <ScrollView xmlns:android ...

  10. java — 静态绑定和动态绑定

    绑定:一个方法的调用与方法所在的类关联起来.java中的绑定分为静态绑定和动态绑定,又被称作前期绑定和后期绑定. 静态绑定:(final.static.private)在程序执行前已经被绑定,也就是说 ...