流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:
- 延迟方法:返回值类型仍然是
Stream
接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余方法均为延迟方法。)
- 终结方法:返回值类型不再是
Stream
接口自身类型的方法,因此不再支持类似StringBuilder
那样的链式调用。本小节中,终结方法包括count
和forEach
方法。
13.1.4.1逐一处理:forEach
虽然方法名字叫forEach
,但是与for循环中的“for-each”昵称不同。
1
| void forEach(Consumer<? super T> action);
|
该方法接收一个Consumer
接口函数,会将每一个流元素交给该函数进行处理。
复习Consumer接口
1 2
| java.util.function.Consumer<T>接口是一个消费型接口。 Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据。
|
基本使用:
1 2 3 4 5 6 7 8
| import java.util.stream.Stream;
public class Demo12StreamForEach { public static void main(String[] args) { Stream<String> stream = Stream.of("张无忌", "张三丰", "周芷若"); stream.forEach(name‐> System.out.println(name)); } }
|
13.1.4.2过滤:filter
可以通过filter
方法将一个流转换成另一个子集流。方法签名:
1
| Stream<T> filter(Predicate<? super T> predicate);
|
该接口接收一个Predicate
函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件。

复习Predicate接口
此前我们已经学习过java.util.stream.Predicate
函数式接口,其中唯一的抽象方法为:
该方法将会产生一个boolean值结果,代表指定的条件是否满足。如果结果为true,那么Stream流的filter 方法将会留用元素;如果结果为false,那么filter
方法将会舍弃元素。
基本使用
Stream流中的filter
方法基本使用的代码如:
1 2 3 4 5 6 7
| import java.util.stream.Stream; public class Demo07StreamFilter { public static void main(String[] args) { Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若"); Stream<String> result = original.filter(s ‐> s.startsWith("张")); } }
|
在这里通过Lambda表达式来指定了筛选的条件:必须姓张。
13.1.4.3 映射:map
如果需要将流中的元素映射到另一个流中,可以使用map 方法。方法签名:
1
| <R> Stream<R> map(Function<? super T, ? extends R> mapper);
|
该接口需要一个Function
函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。

复习Function接口
此前我们已经学习过java.util.stream.Function
函数式接口,其中唯一的抽象方法为:
这可以将一种T类型转换成为R类型,而这种转换的动作,就称为“映射”。
基本使用
Stream流中的map
方法基本使用的代码如:
1 2 3 4 5 6 7 8
| import java.util.stream.Stream;
public class Demo08StreamMap { public static void main(String[] args) { Stream<String> original = Stream.of("10", "12", "18"); Stream<Integer> result = original.map(str‐>Integer.parseInt(str)); } }
|
这段代码中,map
方法的参数通过方法引用,将字符串类型转换成为了int类型(并自动装箱为Integer
类对象)。
13.1.4.4 统计个数:count
正如旧集合Collection
当中的size
方法一样,流提供count
方法来数一数其中的元素个数:
该方法返回一个long值代表元素个数(不再像旧集合那样是int值)。基本使用:
1 2 3 4 5 6 7 8 9
| import java.util.stream.Stream;
public class Demo09StreamCount { public static void main(String[] args) { Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若"); Stream<String> result = original.filter(s ‐> s.startsWith("张")); System.out.println(result.count()); } }
|
取用前几个:limit
limit
方法可以对流进行截取,只取用前n个。方法签名:
1
| Stream<T> limit(long maxSize);
|
参数是一个long型,如果集合当前长度大于参数则进行截取;否则不进行操作。基本使用:

1 2 3 4 5 6 7 8 9
| import java.util.stream.Stream;
public class Demo10StreamLimit { public static void main(String[] args) { Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若"); Stream<String> result = original.limit(2); System.out.println(result.count()); } }
|
跳过前几个:skip
如果希望跳过前几个元素,可以使用skip 方法获取一个截取之后的新流:

1 2 3 4 5 6 7 8 9
| import java.util.stream.Stream;
public class Demo11StreamSkip { public static void main(String[] args) { Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若"); Stream<String> result = original.skip(2); System.out.println(result.count()); } }
|
13.1.4.5 组合:concat
如果有两个流,希望合并成为一个流,那么可以使用Stream
接口的静态方法concat
**:
1
| static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
|
备注:这是一个静态方法,与java.lang.String
当中的concat
方法是不同的。
该方法的基本使用代码如:
1 2 3 4 5 6 7 8 9
| import java.util.stream.Stream;
public class Demo12StreamConcat { public static void main(String[] args) { Stream<String> streamA = Stream.of("张无忌"); Stream<String> streamB = Stream.of("张翠山"); Stream<String> result = Stream.concat(streamA, streamB); } }
|
13.1.5 练习:集合元素处理(传统方式)
13.1.5.1 题目
现在有两个ArrayList
集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)依次进行以下若干操作步骤:
- 第一个队伍只要名字为3个字的成员姓名;存储到一个新集合中。
- 第一个队伍筛选之后只要前3个人;存储到一个新集合中。
- 第二个队伍只要姓张的成员姓名;存储到一个新集合中。
- 第二个队伍筛选之后不要前2个人;存储到一个新集合中。
- 将两个队伍合并为一个队伍;存储到一个新集合中。
- 根据姓名创建
Person
对象;存储到一个新集合中。
- 打印整个队伍的Person对象信息。
两个队伍(集合)的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import java.util.ArrayList; import java.util.List;
public class DemoArrayListNames { public static void main(String[] args) { ArrayList<String> one = new ArrayList<>(); one.add("迪丽热巴"); one.add("宋远桥"); one.add("苏星河"); one.add("石破天"); one.add("石中玉"); one.add("老子"); one.add("庄子"); one.add("洪七公"); ArrayList<String> two = new ArrayList<>(); two.add("古力娜扎"); two.add("张无忌"); two.add("赵丽颖"); two.add("张三丰"); two.add("尼古拉斯赵四"); two.add("张天爱"); two.add("张二狗"); } }
|
而Person
类的代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Person { private String name; public Person() {} public Person(String name) { this.name = name; } @Override public String toString() { return "Person{name='" + name + "'}"; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
|
13.1.5.2 解答
既然使用传统的for循环写法,那么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class DemoArrayListNames { public static void main(String[] args) { List<String> one = new ArrayList<>(); List<String> two = new ArrayList<>(); List<String> oneA = new ArrayList<>(); for (String name : one) { if (name.length() == 3) { oneA.add(name); } } List<String> oneB = new ArrayList<>(); for (int i = 0; i < 3; i++) { oneB.add(oneA.get(i)); } List<String> twoA = new ArrayList<>(); for (String name : two) { if (name.startsWith("张")) { twoA.add(name); } } List<String> twoB = new ArrayList<>(); for (int i = 2; i < twoA.size(); i++) { twoB.add(twoA.get(i)); } List<String> totalNames = new ArrayList<>(); totalNames.addAll(oneB); totalNames.addAll(twoB); List<Person> totalPersonList = new ArrayList<>(); for (String name : totalNames) { totalPersonList.add(new Person(name)); } for (Person person : totalPersonList) { System.out.println(person); } } }
|
运行结果为:
1 2 3 4 5
| Person{name='宋远桥'} Person{name='苏星河'} Person{name='石破天'} Person{name='张天爱'} Person{name='张二狗'}
|
13.1.6 练习:集合元素处理(Stream方式)
13.1.6.1 题目
将上一题当中的传统for循环写法更换为Stream流式处理方式。两个集合的初始内容不变, Person 类的定义也不变。
13.1.6.2 解答
等效的Stream流式处理代码为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class DemoStreamNames { public static void main(String[] args) { List<String> one = new ArrayList<>(); List<String> two = new ArrayList<>(); Stream<String> streamOne = one.stream().filter(s ‐> s.length() == 3).limit(3); Stream<String> streamTwo = two.stream().filter(s ‐> s.startsWith("张")).skip(2); Stream.concat(streamOne, streamTwo).map(Person::new) .forEach(System.out::println); } }
|
运行效果完全一样:
1 2 3 4 5
| Person{name='宋远桥'} Person{name='苏星河'} Person{name='石破天'} Person{name='张天爱'} Person{name='张二狗'}
|
本文标题:第三部分 第十三章 1.Stream流(二)
文章作者:foreverSFJ
发布时间:2019-08-22 12:34:12
最后更新:2019-08-22 12:34:12
原始链接:Notes/Java/Basic/Part03/13_1_2 Stream流(二).html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明出处!
分享