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

简介: JAVA8给我带了什么——并流行和接口新功能流,确定是笔者内心很向往的天堂,有他之后JAVA在处理数据就变更加的灵动。加上lambda表达不喜欢都不行。JAVA8也为流在提供另一个功能——并行流。即是有并行流,那么是不是也有顺序流。

JAVA8给我带了什么——并流行和接口新功能
流,确定是笔者内心很向往的天堂,有他之后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(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 }
复制代码
运行结果:

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

复制代码
1 public static void main(String[] args) {
2 // TODO Auto-generated method stub
3
4 List 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 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> {
8
9 private List chars;
10
11 public DistinctCharForkJoin(List chars) {
12 this(chars, 0, chars.size());
13 }
14
15 public DistinctCharForkJoin(List chars, int start, int end) {
16
17 this.chars = chars.subList(start, end);
18 }
19
20 @Override
21 protected List compute() {
22 // TODO Auto-generated method stub
23 List tmpChars = new ArrayList();
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 rChars = rightForkJoin.join();
48
49 List 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 chars = Arrays.asList('a', 'b', 'c', 'd', 'b', 'a');
5
6 DistinctCharForkJoin task = new DistinctCharForkJoin("main", chars);
7
8 List 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 spliterator() {
2 return Spliterators.spliterator(this, Spliterator.ORDERED);
3 }
Spliterator接口:

1 public interface Spliterator {
2 boolean tryAdvance(Consumer<? super T> action);
3 Spliterator 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 {
8
9 private List chars;
10 private int index = 0;
11
12 public DistinctCharSpliterator(List chars) {
13 this.chars = chars;
14 }
15
16 public DistinctCharSpliterator(List 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 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 chars = Arrays.asList('a', 'b', 'c', 'd', 'b', 'a');
5
6 DistinctCharSpliterator distinctCharSpliterator = new DistinctCharSpliterator(chars);
7
8 Stream 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提供了三个标准来确定用哪一个。

类或父类的方法优先级高于接口默认的方法。
如果上面不行的话,谁拥有最具体的实现的话,就用谁。
如果都不能确定的情况下,就必须显性的调用。来指定他要调哪一个。
举例子。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();
}

}
复制代码
当然除了上面之外,你还是可以定义静态方法和常量。这个时候有人就会说他不是跟抽象类很像吗?是很像。可是不一样子。抽象类是不是可以实例一个字段。但是接口却不行。还有抽像类你只能单继承。接口就可以多继承了。
原文地址https://www.cnblogs.com/hayasi/p/10639994.html

相关文章
|
14天前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
|
1月前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
41 6
|
1月前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
33 2
|
5天前
|
Java
在Java中,接口之间可以继承吗?
接口继承是一种重要的机制,它允许一个接口从另一个或多个接口继承方法和常量。
23 1
|
15天前
|
Java
java线程接口
Thread的构造方法创建对象的时候传入了Runnable接口的对象 ,Runnable接口对象重写run方法相当于指定线程任务,创建线程的时候绑定了该线程对象要干的任务。 Runnable的对象称之为:线程任务对象 不是线程对象 必须要交给Thread线程对象。 通过Thread的构造方法, 就可以把任务对象Runnable,绑定到Thread对象中, 将来执行start方法,就会自动执行Runable实现类对象中的run里面的内容。
32 1
|
20天前
|
Java 开发者
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
44 4
|
27天前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。
|
25天前
|
Java
Java基础(13)抽象类、接口
本文介绍了Java面向对象编程中的抽象类和接口两个核心概念。抽象类不能被实例化,通常用于定义子类的通用方法和属性;接口则是完全抽象的类,允许声明一组方法但不实现它们。文章通过代码示例详细解析了抽象类和接口的定义及实现,并讨论了它们的区别和使用场景。
|
25天前
|
Java 测试技术 API
Java零基础-接口详解
【10月更文挑战第19天】Java零基础教学篇,手把手实践教学!
22 1
|
30天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
20 3
下一篇
无影云桌面