JAVA8给我带了什么——并行流和接口新功能
流,确定是笔者内心很向往的天堂,有他之后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提供了三个标准来确定用哪一个。
- 类或父类的方法优先级高于接口默认的方法。
- 如果上面不行的话,谁拥有最具体的实现的话,就用谁。
- 如果都不能确定的情况下,就必须显性的调用。来指定他要调哪一个。
举例子。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给我带了什么——并行流和接口新功能的更多相关文章
- 【Java8新特性】关于并行流与串行流,你必须掌握这些!!
写在前面 提到Java8,我们不得不说的就是Lambda表达式和Stream API.而在Java8中,对于并行流和串行流同样做了大量的优化.对于并行流和串行流的知识,也是在面试过程中,经常被问到的知 ...
- java8学习之收集器枚举特性深度解析与并行流原理
首先先来找出上一次[http://www.cnblogs.com/webor2006/p/8353314.html]在最后举的那个并行流报错的问题,如下: 在来查找出上面异常的原因之前,当然得要一点点 ...
- Java8新特性 并行流与串行流 Fork Join
并行流就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流. Java 8 中将并行进行了优化,我们可以很容易的对数据进行并 行操作. Stream API 可以声明性地通过 para ...
- 在使用Java8并行流时的问题分析
最近在使用Java8的并行流时遇到了坑,线上排查问题时花了较多时间,分享出来与大家一起学习与自查 // 此处为坑 List<Java8Demo> copy = Lists.newArray ...
- java8新特性——并行流与顺序流
在我们开发过程中,我们都知道想要提高程序效率,我们可以启用多线程去并行处理,而java8中对数据处理也提供了它得并行方法,今天就来简单学习一下java8中得并行流与顺序流. 并行流就是把一个内容分成多 ...
- Java8并行流使用注意事项
对于从事Java开发的童鞋来说,相信对于Java8的并行流并不陌生,没错,我们常常用它来执行并行任务,但是由于并行流(parallel stream)采用的是享线程池,可能会对我们的性能造成严重影响, ...
- Java8新特性 - 并行流与串行流
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流. Java8中将并行进行了优化,我们可以很容易的对数据进行并行操作.Stream API可以声明性地通过parallel()和 ...
- java8学习之自定义收集器深度剖析与并行流陷阱
自定义收集器深度剖析: 在上次[http://www.cnblogs.com/webor2006/p/8342427.html]中咱们自定义了一个收集器,这对如何使用收集器Collector是极有帮助 ...
- 避坑 | Java8使用并行流(ParallelStream)注意事项
示例分析 /** * 避坑 | Java8使用并行流(ParallelStream)注意事项 * * @author WH.L * @date 2020/12/26 17:14 */ public c ...
随机推荐
- item 6: 当auto推导出一个不想要的类型时,使用显式类型初始化的语法
本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 Item 5解释了比起显式指定类型,使用auto来 ...
- J-query extend()方法
1.如果没有冲突参数会弥在后面. 2.参数如果和前面的参数存在相同的名称,那么后面的会覆盖前面的参数值.
- LVM : 缩减文件系统的容量
有扩展就有缩减,我们在前文<LVM : 扩展文件系统的容量>中介绍了通过 LVM 扩展文件系统的方法,本文我们接着前文的 demo 介绍通过 LVM 缩减文件系统的方法.说明:本文的演示环 ...
- WordPress更新时提示无法连接到FTP服务器的解决方案
这几天在搭建主站的时候,更新wordpress时无法连接到FTP原因服务器 解决方法如下: 在WordPress目录下找到wp-config.php文件并编辑,在最后一行加上: define('FS_ ...
- eclipse添加maven环境
一.打开eclipse,选择Window->preference,如下图所示 二.Maven-> installation->add,见下图: 三.选择Directory,选择mav ...
- Redis常用操作--------SortedSet(有序集合)
1.ZADD key score member [[score member] [score member] ...] 将一个或多个 member 元素及其 score 值加入到有序集 key 当中. ...
- 第七次Scrum meeting
第七次Scrum meeting 任务及完成度: 成员 12.26 12.27 陈谋 任务1040:完成stackoverflow的数据处理后的json处理(98%) 任务1114-1:完成对网页数 ...
- 《Linux内核设计与实现》 第十八章学习笔记
调 试 一.准备开始 一个bug 一个藏匿bug的内核版本 相关内核代码的知识和运气 知道这个bug最早出现在哪个内核版本中. 1.想要成功进行调试: 让这些错误重现 抽象出问题 从代码中搜索 二. ...
- CentOS7.3安装rz、sz命令
安装命令: yum install lrzsz 关于rz.sz: lrzsz是一款在linux里可代替ftp上传和下载的程序.lrzsz是一个unix通信套件提供的X,Y,和ZModem文件传输协议. ...
- [BUAA2017软工]第1次个人项目 数独
[BUAA软工]第1次作业 个人项目 数独 一.项目地址 github地址:https://github.com/BuaaAlen/sudoku 二.PSP表格 三.解题思路描述 在拿到这个题目时,我 ...