携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
自1.8有Stream已经很久了,不过之前因为各种原因并没有系统的去学习和了解这一块,最近在项目中又使用到了,借此机会来总计和记录自己学习的过程。如有理解错误或者不正确的地方请务必纠正我。
什么是Stream流
官方给的解释为: A sequence of elements supporting sequential and parallel aggregate operations. 这是什么东西??翻译过来就是支持顺序和并行聚合操作的元素序列。 看了之后貌似明白了什么又貌似什么都没明白,然后我有去查了一下资料,比较好的解释为流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算。
Stream流生成
流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素 既然流是由源生成的元素序列,那我们就从数组、文件、集合、函数这几个方面来生成。
集合生成
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
list.add(i);
}
//这个地方直接使用stream方法转换成stream流
Stream<Integer> stream = list.stream();
文件生成
Stream<String> lines = Files.lines(Paths.get("stream.txt"));
数组生成
IntStream intStream = Arrays.stream(new int[]{1, 2 });
LongStream longStream = Arrays.stream(new long[]{1, 5, 6});
Stream API的方式
//其他类型的与之类似
Stream<String> a = Stream.of("A", "B", "C", "D");
//这个提供不限流的函数操作 其中第一个参数是初始值,第二个参数是Lambda表达式函数 limit是用来进行次数限制的 与之类似的还有generate
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);
Stream<Integer> generate = Stream.generate(() -> 1);
操作类型
- 中间操作:如果调用方法之后返回的结果是Stream对象的操作是一个中间操作。
- 终止操作:一个流有且只能有一个终止操作,当这个操作执行后,流就被关闭了,无法再被操作。
中间操作
- 过滤操作
//过滤掉所有的奇数,并把过滤结果转换成列表
Stream<Integer> stream = Stream.iterate(0, n -> n + 1).limit(20);
Stream<Integer> integerStream = stream.filter(item -> item % 2 == 0);
2.去重操作
【注意】如果使用的类型不是基本类型,必须要重写equals() 方法与 hashCode() 方法。
List<String> ls = Arrays.asList("1", "2", "2", "4", "2", "2", "8", "9");
Stream<String> distinct = ls.stream().distinct();
如果要对列表对象的某个属性进行过滤的话,可以用一下的方式
List<Person> peoples = new ArrayList<>();
peoples.add(new Person("zhangsan","23"));
peoples.add(new Person("zhangsan","23"));
peoples.add(new Person("zhangsan","23"));
peoples.add(new Person("lisi","23"));
peoples.add(new Person("lisi","23"));
peoples.add(new Person("lisi","23"));
List<Person> result = peoples.stream()
.collect(
collectingAndThen(
toCollection(() -> new TreeSet<>(comparing(Person::getName))),
ArrayList::new
)
);
result.forEach(System.out::println);
输出结果
MyMain.Person(name=lisi, age=23)
MyMain.Person(name=zhangsan, age=23)
也可以使用TreeSet来实现去重操作
TreeSet<Person> treeSet = new TreeSet<>(Comparator.comparing(Person::getName));
treeSet.addAll(peoples);
List<Person> result2 = new ArrayList<>(treeSet);
result2.forEach(System.out::println);
其实也就是上面方式的拆分,只不过看起来比较明了,算是函数编程的弊端吧,对于API熟悉的人会很容易理解,但是对于不熟悉的就显得很晦涩
3.获取列表元素
Stream<Person> limit = peoples.stream().limit(3);
4.跳过N个元素
Stream<Person> skip = peoples.stream().skip(3);
limit和skip搭配起来可以实现内存分页
5.对列进行排序(默认为升序)
//简单的排序
List<String> strings = Arrays.asList("1", "3", "2", "6", "5");
List<String> collect = strings.stream().sorted().collect(Collectors.toList());
//如果需要倒序可以这样
List<String> strings = Arrays.asList("1", "3", "2", "6", "5");
List<String> collect = strings.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
//或者对某个属性进行排序
List<Person> collect1 = peoples.stream().sorted(Comparator.comparing(Person::getAge).reversed()).collect(Collectors.toList());
6.map操作
//对年龄做处理
List<Person> streamMap = peoples.stream().map(item -> {
item.setAge("1");
return item;
}).collect(Collectors.toList());
//实现某个逻辑返回全新的数据
List<Integer> streamMap1 = peoples.stream().map(item -> item.getName().length()).collect(Collectors.toList());
7.mapToInt操作,另外mapToLong、mapToDouble两个方法与之类似
IntStream intStream = peoples.stream().mapToInt(item -> Integer.parseInt(item.age));
8.flatMap操作
List<String> ls = Arrays.asList("A B", "C D", "E F");
List<String> collect = ls.stream().flatMap(item -> Arrays.stream(item.split(" "))).collect(Collectors.toList());
输出
["A","B","C","D","E","F"]
map和flatMap区别在于,map在处理数据的时候输入一个输出一个,而flatMap是输入一个可以转换成多个输出。
9.peek
Stream.of("one", "two", "three", "four")
.filter(e -> e.length() > 3)
.peek(e -> System.out.println("Filtered value: " + e))
.map(String::toUpperCase)
.peek(e -> System.out.println("Mapped value: " + e))
.collect(Collectors.toList());
终止操作
1.forEach
//遍历输出集合中的每个元素
peoples.forEach(System.out::println);
peoples.stream().forEach(System.out::println);
peek和forEach的区别是peek属于中间操作,而forEach是终止操作 还有一个最主要的区别是peek可以返回处理结果,forEach不能返回输出结果 2.reduce
//用来进行数据累加
Integer sum = integers.reduce(0, (a, b) -> a+b);
Integer sum = integers.reduce(0, Integer::sum);
3.min
//获取最小值
List<Integer> numList = Arrays.asList(1, 2, 3, 0);
Comparator<Integer> comparator = Comparator.comparing(Integer::intValue);
Optional<Integer> minOptional = numList.stream().min(comparator);
minOptional.ifPresent(e -> System.out.println("Min: " + e));
4.max
//获取最大值
List<Integer> numList = Arrays.asList(1, 2, 3, 0);
Comparator<Integer> comparator = Comparator.comparing(Integer::intValue);
Optional<Integer> minOptional = numList.stream().max(comparator);
minOptional.ifPresent(e -> System.out.println("max: " + e));
5.count
List<Integer> data = Arrays.asList(1, 2, 3, 0);
long count = data.stream().filter(item->item>1).count();
System.out.println(count);
6.anyMatch 判断数据列表中是否存在任意一个元素符合设置的predicate条件,如果是就返回true,否则返回false。
//判断是否有name为张三或age为50的数据
peoples.stream().anyMatch(item->item.getName().equals("zhangsan") || item.getAge().equals("50"));
7.allMatch 判断数据列表中全部元素都符合设置的predicate条件,如果是就返回true,否则返回false,流为空时总是返回true。
List<String> data = Arrays.asList("1", "2", "3");
boolean b = data.stream().allMatch(a -> a.equals("1") || a.equals("2")|| a.equals("3"));
System.out.println(b);
8.noneMatch 判断数据列表中全部元素都不符合设置的predicate条件,如果是就返回true,否则返回false,流为空时总是返回true。
List<String> data = Arrays.asList("1", "2", "3");
boolean b = data.stream().noneMatch(a -> a.equals("4") || a.equals("7"));
System.out.println(b);
9.collect 它可以支持生成如下类型的结果数据:
- 一个
集合类,比如List、Set或者HashMap等,这个是最常用的 - StringBuilder对象,支持将多个
字符串进行拼接处理并输出拼接后结果 - 一个可以记录个数或者计算总和的对象(
数据批量运算统计)
// collect成list
List<Integer> data = Arrays.asList(1, 2, 3, 0);
List<Integer> collect = data.stream().filter(item -> item > 0).collect(Collectors.toList());
// collect成set
Set<Integer> collect1 = data.stream().filter(item -> item > 0).collect(Collectors.toSet());
// collect成map
Map<String, Person> collect2 = peoples.stream().filter(item -> item.getAge().equals("21")).collect(Collectors.toMap(Person::getName, item -> item));
拼接字符串
List<String> da = Arrays.asList("1","2","2","2","2");
String collect3 = da.stream().collect(Collectors.joining("-"));
System.out.println(collect3);
//也可以这样用
List<String> da = Arrays.asList("1","2","2","2","2");
String collect3 = String.join("-", da);
System.out.println(collect3);
数据批量数学运算
List<Integer> ids = Arrays.asList(10, 20, 30, 40, 50);
// 计算平均值
Double average = ids.stream().collect(Collectors.averagingInt(value -> value)); System.out.println("平均值:" + average);
// 数据统计信息
IntSummaryStatistics summary = ids.stream().collect(Collectors.summarizingInt(value -> value)); System.out.println("数据统计信息: " + summary);