文章目录
- 1 概述
- 2 获取Stream对象
- 3 常用API
- 4 收集Stream流
- 5 总结
1 概述
Stream类用于简化集合和数组操作的API。
Stream类提供了很多可以简化集合操作的api,比如过滤元素
示例如下:
假如一个List集合中存储着字符串,从这些字符串中找到以“1”开头并长度为3的字符串加入一个新的List集合中。
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("123");
list.add("145435");
list.add("145");
list.add("234");
list.add("5435");
list.add("189");
ArrayList<String> newList = new ArrayList<>();
for (String s : list) {
if (s.startsWith("1") && s.length() == 3) {
newList.add(s);
}
}
System.out.println(newList);
}
使用stream可以简化上面的写法
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("123");
list.add("145435");
list.add("145");
list.add("234");
list.add("5435");
list.add("189");
ArrayList<String> newList = new ArrayList<>();
list.stream().filter(s -> s.startsWith("1")).filter(s -> s.length() == 3).forEach(s -> newList.add(s));
System.out.println(newList);
}
Stream流其中的一些接口返回的还是Stream对象,可以支持链式编程。
通常使用步骤可以分为:
-
获取集合和数组的Stream流
-
放置元素
-
使用Stream流的api方便操作元素
Stream当中的方法可以分为: -
获取Stream流
-
中间方法:返回的还是Stream对象
-
终结方法:无返回,代表Stream使用结束
2 获取Stream对象
//集合
Collection<String> list = new ArrayList<>();
Stream<String> s = list.stream();
//Map
Map<String, Integer> map = new HashMap<>();
Stream<String> keyStream = map.keySet().stream();
Stream<Integer> valueStream = map.values().stream();
Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();
//数组
String[] strs = {"4324", "243324"};
Stream<String> strStream = Arrays.stream(strs);
Stream<String> strStream1 = Stream.of(strs);
Collection接口中提供了stream方法用于返回stream流
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
是一个默认方法。
Map中可以返回key、value和entry类型的stream流
数组返回stream流借助于Arrays工具类,其中Stream中的静态方法of也是借助于Arrays工具类返回Stream流
public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
}
3 常用API
先创建一个List集合
ArrayList<String> list = new ArrayList<>();
list.add("123");
list.add("145435");
list.add("145");
list.add("234");
list.add("5435");
list.add("189");
- 过滤和遍历
//Stream<T> filter(Predicate<? super T> predicate);
//void forEach(Consumer<? super T> action);
list.stream().filter(s -> s.startsWith("1")).forEach(s -> System.out.println(s));
filter
返回一个stream
对象,forEach
返回空,用于遍历元素。
输出:
123
145435
145
189
- 统计元素个数
//long count();
long size = list.stream().filter(s -> s.startsWith("1")).count();
System.out.println(size);
输出
4
- 取前几个元素或跳过前几个元素
//Stream<T> limit(long maxSize);
list.stream().filter(s -> s.startsWith("1")).limit(2).forEach(System.out::println);
//Stream<T> skip(long n);
list.stream().filter(s -> s.startsWith("1")).skip(2).forEach(System.out::println);
输出
123
145435
145
189
这两个方法的参数都只能取大于等于0的值,否则会报异常。limit当值大于size
时,取全部元素,skip
当值大于size
时,不返回任何元素。
- 加工元素
//<R> Stream<R> map(Function<? super T, ? extends R> mapper);
list.stream().map(s -> "map: " + s).forEach(System.out::println);
输出:
map: 123
map: 145435
map: 145
map: 234
map: 5435
map: 189
入参是一个函数式接口Function,重写apply方法,用于操作修改元素。
还可以构建对象
list.stream().map(s -> new Number(s)).forEach(System.out::println);
Number是一个类,包含了一个有参构造,可以通过map构造一个Number对象的stream流。
- 合并流
Stream<String> s1 = list.stream().filter(s -> s.startsWith("1"));
Stream<String> s2 = Stream.of("213","231");
Stream<Object> s3 = Stream.concat(s1, s2);
s3.forEach(System.out::println);
concat是Stream接口中的一个静态方法。
public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
Objects.requireNonNull(a);
Objects.requireNonNull(b);
@SuppressWarnings("unchecked")
Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
(Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
return stream.onClose(Streams.composedClose(a, b));
}
接收的泛型必须是两个的公共父类
输出:
123
145435
145
189
213
231
- 去除重复
list.stream().distinct().forEach(System.out::println);
去除重复的元素,依赖于hashCode
方法和equals
方法
4 收集Stream流
将Stream操作后的数据转回集合和数组中去
//收集到List集合中
Stream<String> s1 = list.stream().filter(s -> s.startsWith("1"));
List<String> newList = s1.collect(Collectors.toList());
//List<String> newList1 = s1.toList(); //也是stream被收集过了,不能再使用
System.out.println(newList);
//收集到Set集合中
Set<String> newSet = s1.collect(Collectors.toSet()); //1
System.out.println(newSet);
注释1处报错
流只能收集一次,收集一次之后,就不能再使用了。
Stream<String> s1 = list.stream().filter(s -> s.startsWith("1"));
Object[] strs = s1.toArray();
System.out.println(Arrays.toString(strs));
转换成数组,就直接使用toArray
方法,返回的是一个Object
数组,因为Stream
流中可以引入其他类型的元素
如果能够确定Stream中的元素都是同一种类型,则可以直接通过toArray
的一个api去操作
String[] strs = s1.toArray(String[]::new);
提供一个构造,构造传入的是特定类型数组长度,数组长度会通过toArray传入。
5 总结
- Stream流用于简化数组和集合的操作
- 其中常用方法有
filter
过滤集合元素、forEach
遍历集合元素、map
加工集合元素、count
统计元素个数、concat
拼接Stream流、distinct
去重等 - Stream操作集合和数组元素之后需要转回集合或数组
- 通过提供的
toArray
、toList
、collect
方法来完成收集转化