我将继续感谢黑马程序员的 java 课程。
初爽 Stream 流
需求:这里有一个放着一些姓名的集合,我需要将姓张的、名字长度为三的姓名放进新集合并打印。
一般来说,我们可以写两个遍历用 startWith 等方法找到对应条件的姓名并存入新集合。但这很麻烦。
我们可以直接使用 Stream 流实现一个过滤:
import java.util.ArrayList;
public class demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张三丰");
list.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3).forEach(name -> System.out.println(name));
}
}输出:
张无忌
张三丰我们就完成了从“怎么做”到“做什么”的转变。
注意:filter 是惰性操作,只有在遇到 forEach 这样的终端操作时才会真正执行处理。
概述
Stream可以由数组或集合创建,对流的操作分为两种:
- 中间操作,每次返回一个新的流,可以有多个。(筛选 filter、映射 map、排序 sorted、去重组合 skip—limit)
- 终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。终端操作会产生一个新的集合或值。(遍历 foreach、匹配 find–match、规约 reduce、聚合 max–min–count、收集 collect)
特性:
- stream 不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
- stream 不会改变数据源,通常情况下会产生一个新的集合或一个值。
- stream 具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
Stream 可以传递数组,但如果数组内的数据是基本数据类型数据,会将数组作为一个元素放入 Stream。所以如果将一个 int[] 放进 stream 再 forEach 遍历,得到的结果只是一个地址值。
方法
常用的中间方法
filter
用于通过设置的条件过滤出元素。
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
// 获取空字符串的数量
long count = strings.stream().filter(string -> string.isEmpty()).count();limit
用于获取指定数量的流。
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);skip(long n)
跳过流中的前 n 个元素,返回由剩余元素组成的新流。如果流中元素不足 n 个,则返回空流。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
.skip(2) // 跳过前2个元素:1,2
.forEach(System.out::println);
// 输出:3 4 5distinct()
除流中的重复元素,底层依赖元素的 equals() 和 hashCode() 方法判断是否相同。返回一个去重后的新流。
- 对于自定义对象,要确保正确重写
equals和hashCode,否则去重可能无效。 - 是一个 有状态 的中间操作(需要记住之前出现过的元素)。
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 1, 4);
numbers.stream()
.distinct() // 去重
.forEach(System.out::println);
// 输出:1 2 3 4 (顺序保持首次出现的顺序)concat(Stream a, Stream b)
- 两个流必须是同类型的(或子类)。
- 合并后的流是 按顺序 的:全部 a 元素 → 全部 b 元素
Stream<String> streamA = Stream.of("A", "B", "C");
Stream<String> streamB = Stream.of("D", "E");
Stream<String> result = Stream.concat(streamA, streamB);
result.forEach(System.out::print);
// 输出:ABCDEmap
将流中的每个元素按照给定的映射函数转换成另一种形式(或提取某个属性),返回一个由转换后元素组成的新流。
// 将字符串转换成其长度
List<String> words = Arrays.asList("Java", "Stream", "Map");
words.stream()
.map(String::length)
.forEach(System.out::println);
// 输出:4 6 3
// 将数字转换成其平方
Stream.of(1, 2, 3)
.map(n -> n * n)
.forEach(System.out::print); // 输出:149常用终结方法
forEach
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);count
返回集合元素个数。
List<String> list = Arrays.asList("猫", "狗", "鸟");
long n = list.stream().count();
System.out.println(n); // 输出 3注意:count() 返回的是 long 类型
收集(toArray、collect)
toArray()
收集流中的数据,并放入数组。
List<String> list = Arrays.asList("苹果", "香蕉", "橙子");
String[] arr = list.stream().toArray(String[]::new);
System.out.println(Arrays.toString(arr)); // [苹果, 香蕉, 橙子]对于 toArray():
- 如果流里面是字符串,
String[]::new - 如果流里面是整数,
Integer[]::new
collect()
收集流中的数据,并放入集合。
List<String> list = Arrays.asList("红", "黄", "蓝", "红");
List<String> result = list.stream()
.filter(s -> s.startsWith("红"))
.collect(Collectors.toList());
System.out.println(result); // [红, 红] List 数据可重复Set<String> result = list.stream()
.filter(s -> s.startsWith("红"))
.collect(Collectors.toSet());
System.out.println(result); // [红] 只有一个,重复的自动去掉注意:用 collect 需要导入 java.util.stream.Collectors。
Comments NOTHING