深圳华企网站建设,好的做网站公司,杭州优质网站建设,织梦做仿站时 为何会发生本地地址跳转网站地址文章目录基本介绍流的创建流的各种常见操作forEach方法filter方法map方法peek方法flatMap方法limit和skip方法distinct方法sorted方法收集结果收集为数组#xff08;toArray#xff09;收集为集合#xff08;collect#xff09;收集为Map关于流的一些说明#xff08;终结操…
文章目录基本介绍流的创建流的各种常见操作forEach方法filter方法map方法peek方法flatMap方法limit和skip方法distinct方法sorted方法收集结果收集为数组toArray收集为集合collect收集为Map关于流的一些说明终结操作总结基本介绍
Java 8 API添加了一个新的抽象称为流Stream可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力让程序员写出高效率、干净、简洁的代码。
与集合相比流提供了一种可以让我们在更高概念级别上指定计算任务的数据视图
注意学习Stream必须要十分清晰的了解lamdba表达式如果lambda不清楚请参考一篇文章彻底搞懂lambda表达式 流的创建
我们在学习流之前应当先了解一下Stream这个类Stream类的类图和方法如下 对于创建流我们可以使用静态方法Stream.of来创建 该方法传入一个可变长度的参数然后就会返回对应类型的流 StreamInteger stream Stream.of(2, 3, 1, 4);如果要创建一个不包含任何元素的流可以使用Stream.empty StreamObject empty Stream.empty();我们还可以使用Stream的静态方法generate和iterate来创建无限流。
下面就通过generate创建了一个获取随机数的流 StreamDouble randomNumStream Stream.generate(Math::random);如果想要创建例如0,1,2,3这样有规律的序列流那么就可以使用iterate方法 StreamInteger iterate Stream.iterate(0, num - num1);除了上面几个静态方法对于流的创建还有许多方法例如Arrays.stream方法 在Collection中有stream方法和parallelStream方法都可以返回一个Stream流这也就说明了所有的集合都可以调用这2个方法返回对应的流 对于流我们有几点注意事项如下
流并不存储元素这些元素可能存储在底层的集合中或者是按需生成的流的操作不会改变其数据源流的操作尽可能惰性执行。这意味着直至需要其结果时操作才会执行
流的各种常见操作
这里主要介绍在流里面使用频率较高的几个操作每个方法都会给出该方法的源注释以及基本使用请参考注释和代码来进行理解 forEach方法
这个方法可以对流里面的每一个元素执行操作 StreamInteger stream Stream.of(2, 3, 1, 4);stream.forEach(System.out::println);输出结果如下
2
3
4
1filter方法
该方法可以过滤掉流中不满足要求的元素会返回一个新流 StreamInteger stream Stream.of(2, 3, 1, 4);StreamInteger newStream stream.filter(num - num 2);System.out.print(过滤之后);newStream.forEach(x - System.out.print(x ));上面代码输出如下
过滤之后3 4 map方法
当我们想要按照某种方式来转换流中的值的时候我们就可以使用map StreamInteger stream Stream.of(2, 3, 1, 4);StreamInteger newStream stream.map(num - num 1);newStream.forEach(System.out::println);上面代码输出如下
3
4
2
5peek方法
该方法可以对流中的每一个元素进行操作返回新的流 public class Dog {public String name;public Integer age;public Dog(String name, Integer age) {this.name name;this.age age;}Overridepublic String toString() {return Dog{ name name \ , age age };}
}Dog[] dogs {new Dog(tom, 1),new Dog(旺财, 2)};StreamDog dogStream Arrays.stream(dogs);StreamDog newDogStream dogStream.peek(dog - dog.age 999);newDogStream.forEach(System.out::println);上面代码输出如下
Dog{nametom, age999}
Dog{name旺财, age999}flatMap方法
该方法产生一个流它是通过将传入lambda表达式应用于当前流中所有元素所产生的结果连接到一起而获得的。注意这里的每个结果都是一个流。 ListStreamInteger streamList new ArrayList();StreamInteger stream1 Stream.of(1, 2, 3);StreamInteger stream2 Stream.of(4, 5, 6);StreamInteger stream3 Stream.of(7, 8, 9);streamList.add(stream1);streamList.add(stream2);streamList.add(stream3);StreamStreamInteger stream streamList.stream();// flatMap里面的lambda表达式应当返回一个流StreamInteger integerStream stream.flatMap(x - x);integerStream.forEach(System.out::println);上面代码输出如下
1
2
3
4
5
6
7
8
9limit和skip方法
limit方法可以对流进行裁剪只取前n个流skip方法则是跳过前n个流 由于limit和skip用法基本由于这里就用limit作为例子 StreamInteger stream Stream.of(1, 2, 3, 4, 5, 6);StreamInteger newStream stream.limit(4);newStream.forEach(System.out::println);上面代码输出如下
1
2
3
4distinct方法
这个方法相当于去重 StreamInteger stream Stream.of(1, 2, 3, 3, 1, 4);StreamInteger newStream stream.distinct();newStream.forEach(System.out::println);代码输出如下
1
2
3
4sorted方法
这个方法一看就知道是排序用的 该方法有2个一个带有Comparator就是用于指定排序方式的 StreamInteger stream Stream.of(4, 1, 3, 2);StreamInteger newStream stream.sorted();newStream.forEach(System.out::println);代码输出如下
1
2
3
4收集结果
在上面我们都只是对流进行操作现在来讲解下如何将流里面的数据收集到集合中。 收集为数组toArray
我们可以调用流里面的toArray方法传入对应的类型数组即可 StreamString namesStream Stream.of(tom, luck, jerry);String[] names namesStream.toArray(String[]::new);System.out.println(Arrays.toString(names));上面代码输出如下
[tom, luck, jerry]收集为集合collect
调用stream里面的collect方法然后传入指定的Collector实例即可Collector提供了大量用于生成常见收集器的工厂方法。
Collector类的方法如下 可以发现有很多方法这里先介绍几个常用的其他的方法在后面文章中进行说明。 ListInteger nums Arrays.asList(1,2,3,1,4);toList()可以将结果收集为List ListInteger list nums.stream().collect(Collectors.toList());toSet()可以将结果收集为Set SetInteger set nums.stream().collect(Collectors.toSet());toCollection()可以指定收集的集的种类 TreeSetInteger treeSet nums.stream().collect(Collectors.toCollection(TreeSet::new));在Collector这个类里面还有其他的很多方法建议大家去看看这个类的文档对每个方法都有个影响需要用到某种操作的时候查找文档即可。 收集为Map
Map也是集合但是Map收集要比如ListSet等要麻烦一点所以这里单独说明一下toMap方法如下 我们需要指定k和v是什么其实就是对于每一个元素用什么来作为k和v StreamString namesStream Stream.of(tom, jack, lucy);MapCharacter, String namesMap namesStream.collect(Collectors.toMap(k - k.charAt(0), v - v.toUpperCase()));System.out.println(namesMap);上面代码就用字符串的第一个字符作为k然后用字符串的大写作为v。上面代码输出如下
{tTOM, jJACK, lLUCY}使用toMap还有一点需要说明就是key不能冲突看下面代码就会产生key冲突 StreamString namesStream Stream.of(tom, jack, lucy,ttpfx);MapCharacter, String namesMap namesStream.collect(Collectors.toMap(k - k.charAt(0), v - v.toUpperCase()));System.out.println(namesMap);如果产生key冲突那么collect方法会抛出一个一个IllegalStateException异常 对于key冲突的情况我们应该给出解决key冲突的逻辑toMap还有一个重载的方法用于解决key冲突。也就是保留新值还是旧值 我们遇到key冲突旧保存最新的值即可 StreamString namesStream Stream.of(tom, jack, lucy, ttpfx);MapCharacter, String namesMap namesStream.collect(Collectors.toMap(k - k.charAt(0),v - v.toUpperCase(),(oldV, newV) - newV));System.out.println(namesMap);上面代码输出如下
{tTTPFX, jJACK, lLUCY}对于toMap都有一个等价的toConcurrentMap 关于流的一些说明终结操作
我们先来看下面代码 StreamInteger stream Stream.of(2, 3, 1, 4);stream.forEach(System.out::println);StreamInteger newStream stream.filter(x - x 2);newStream.forEach(System.out::println);上面代码逻辑很简单就是先输出流里面的元素然后过滤一下最后再输出。按理说这个代码应该是没有问题的我们运行一下 可以发现报错了报错的原因就是说流已经关闭了很奇怪啊我们明明没有执行close操作
造成流关闭的原因就是 forEach方法。还记得在文章开始的说明吗流是惰性执行的在流执行终止操作前流其实都没有执行。而forEach就是一个终止操作。对于终结方法我们可以简单理解为就是返回值不是Stream的方法。
我们用代码验证一下Stream的惰性执行 ListInteger list new ArrayList();list.add(1);StreamInteger stream list.stream();list.add(2);long count stream.count();System.out.println(count);大家想一下count是多少由于Stream是惰性执行的那么count显然应该就是2 总结
在这篇文章中介绍了Stream的一些基本使用对于Stream还有许多的方法没有说明这些会在后面的文章中进行说明。Stream里面还有一个很重要的Optional这个将在下一篇文章中进行说明。