今天在Java学习中,遇到了starm这个操作方式,了解后发现很多操作都很实用并且在项目开发中经常用到,特写下此篇博客用来记录。
目录
- 一、Stream基础概念
- Stream操作中的惰性计算
- 创建Stream
- 二、常用的Stream操作方法
- filter
- map
- sorted
- distinct
- count
- reduce
- forEach
- 三、总结
一、Stream基础概念
Stream是Java 8中引入的全新API,可以极大地方便我们对集合、数组等数据源进行连续操作。它可以简化我们的代码,使代码更加易于维护和理解。Stream实际上是一种惰性计算的方式,只有需要输出结果时,才会开始计算。
Stream操作中的惰性计算
Stream只是对于原有数据的操作方式,数据本身并没有改变。因此,在对Stream进行操作时,实际上是将操作指令存储在操作流中并未计算执行,直到需要输出结果时才会被触发。这种方式可以减少计算量和开销,提高效率。
创建Stream
可以从很多种数据源中创建Stream,例如List、Set或者任何其他实现了Iterable接口的类。创建方式很简单,使用stream()
或parallelStream()
方法即可。
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream(); // 串行Stream
Stream<String> parallelStream = list.parallelStream(); // 并行Stream
二、常用的Stream操作方法
常用的Stream操作包括:过滤、映射、排序、去重、计数、归约等等。
filter
过滤方法filter
用于对Stream中的元素进行筛选,只保留符合指定条件的元素。其函数式接口为Predicate<T>
,其方法为boolean test(T t)
,接受一个T类型的对象,并返回一个boolean
类型值。当该方法返回true
时,说明该元素符合条件,将被保留在Stream中。
例如以下代码:
List<String> list = Arrays.asList("apple", "banana", "orange", "pear");
Stream<String> stream = list.stream().filter(s -> s.length() > 5);
其中的lamdba表达式s -> () > 5
用于筛选长度大于5的字符串。
map
映射方法map
用于将Stream中的元素根据指定规则进行转换。其函数式接口为Function<T, R>
,其方法为R apply(T t)
,接受一个T类型的对象,并返回一个R类型的对象。实质上,map方法就是对Stream中各元素做一个同类型的映射。
例如以下代码:
List<String> list = Arrays.asList("apple", "banana", "orange", "pear");
Stream<Integer> stream = list.stream().map(String::length);
其中的方法引用String::length
用于将每个字符串对象转换成其长度值。
sorted
排序方法sorted
用于对Stream中的元素进行排序。其函数式接口为Comparator<T>
,其方法为int compare(T o1, T o2)
,接受两个T类型的对象,并返回一个int
类型值。当返回值为负数时,说明o1应排在o2前面;当返回值为正数时,说明o1应排在o2后面;当返回值为0时,说明o1与o2的顺序不确定。
例如以下代码:
List<String> list = Arrays.asList("apple", "banana", "orange", "pear");
Stream<String> stream = list.stream().sorted();
其中,Stream将使用默认的排序规则对元素进行排序。
distinct
去重方法distinct
用于将Stream中的重复元素去除,只保留一个。其使用equals方法进行比较,因此需要保证数据源中的元素正确实现了equals方法。
例如以下代码:
List<String> list = Arrays.asList("apple", "banana", "orange", "banana");
Stream<String> stream = list.stream().distinct();
其中,Stream中的元素"banana"出现了两次,但在调用distinct方法后,只保留了一次的"banana"元素。
count
计数方法count
用于返回Stream中元素的数量,返回值为long
类型。
例如以下代码:
List<String> list = Arrays.asList("apple", "banana", "orange", "pear");
long count = list.stream().count();
其中,count方法返回的值为4,即Stream中元素的数量。
reduce
归约方法reduce
用于将Stream中的元素归约成一个值。其函数式接口为BinaryOperator<T>
,其方法为apply(T t1, T t2)
,用于对两个T类型值进行归约,返回一个T类型值。reduce方法接受两个参数:第一个参数表示归约操作的初始值,可以为任意类型的对象;第二个参数为一个BinaryOperator类型的对象,用于对Stream中所有元素递归地进行归约操作。
例如以下代码:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
int sum = list.stream().reduce(0, Integer::sum);
forEach
forEach
方法用于对Stream中的每个元素执行指定的操作,其函数式接口为Consumer<T>
,其方法为void accept(T t)
。forEach
是一个终端操作,对于同一个Stream只能进行一次,一旦执行了终端操作,该Stream就不能再重复使用了。
例如以下代码:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream().forEach(System.out::println);
其中,先通过stream
方法将集合转换为Stream流,接着使用forEach
方法对每个整数进行输出,最终输出结果为:
1
2
3
4
5
三、总结
Stream是Java 8中非常重要的一个API,可以极大地方便我们对列表、集合等数据源进行连续操作。Stream操作可以极大地简化我们的代码,提高效率,因此在Java编程中应该熟练使用Stream。需要注意的是,在对Stream进行操作时,应该注意Stream的惰性计算特性,以避免不必要的计算开销。