3.Stream流(最重要)
3.1概述
Java8的Stream使用的是函数式编程榄式,如同它的名字一样,它可以被用来对集合成数组进行链状流式的操作。可以更方便的让我们对集合或数组操作。
3.2 案例数据准备
Author
package com.tian;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Author {
private Long id;
private String name;
private Integer age;
private String intro;
private List<Book> books;
}
Book
package com.tian;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Book {
private Long id;
private String name;
private String category;
private Integer score;
private String intro;
}
StreamDemo
package com.tian;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class StreamDemo {
public static void main(String[] args) {
List<Author> authors = getAuthors();
System.out.println(authors);
}
private static List<Author> getAuthors(){
Author author = new Author(1L, "zhangsan1", 33, "张三", null);
Author author2 = new Author(2L, "zhangsan2", 15, "张三", null);
Author author3 = new Author(3L, "zhangsan3", 14, "张三", null);
Author author4 = new Author(3L, "zhangsan4", 14, "张三", null);
List<Book> book1 = new ArrayList<Book>();
List<Book> book2 = new ArrayList<Book>();
List<Book> book3 = new ArrayList<Book>();
book1.add(new Book(1L,"光明1","哲学",88,"光明与黑暗的战斗"));
book1.add(new Book(2L,"光明2","哲学",77,"光明与黑暗的战斗"));
book2.add(new Book(3L,"光明3","哲学",66,"光明与黑暗的战斗"));
book2.add(new Book(3L,"光明3","哲学",55,"光明与黑暗的战斗"));
book2.add(new Book(4L,"光明4","哲学",44,"光明与黑暗的战斗"));
book3.add(new Book(5L,"光明5","哲学",33,"光明与黑暗的战斗"));
book3.add(new Book(6L,"光明6","哲学",22,"光明与黑暗的战斗"));
book3.add(new Book(6L,"光明6","哲学",11,"光明与黑暗的战斗"));
author.setBooks(book1);
author2.setBooks(book2);
author3.setBooks(book3);
author4.setBooks(book3);
ArrayList<Author> authorList = new ArrayList<Author>(Arrays.asList(author, author2, author3, author4));
return authorList;
}
}
3.3 快速入门
List<Author> authors = getAuthors();
//打印所有年龄小于18的作家的名字,并且要注意去重
authors.stream()//把集合转换成流
.distinct() //去重
.filter(author -> author.getAge()<18) //筛选年龄小于18的
.forEach(author -> System.out.println(author.getName())); //打印
//zhangsan2
//zhangsan3
//必须要有终结操作 这里就是forEach
创建流
单列集合 集合对象.stream()
List<Author> authors = getAuthors();
authors.stream()
数组 Arrays.stream(数组)
或者使用Stream.of
来创建
Integer[] arr={1,2,3,4,5};
Stream<Integer> stream = Arrays.stream(arr);
stream.distinct()
.filter(integer -> integer%2==0)
.forEach(integer -> {
System.out.println(integer);
});
// 2 4
//了解即可
Stream<Integer> arr1 = Stream.of(arr);
arr1.distinct().forEach();
双列集合:转换成单列集合再创建
Map<String, Integer> map = new HashMap<>();
map.put("张三1",18);
map.put("张三2",19);
map.put("张三3",20);
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
Stream<Map.Entry<String, Integer>> stream1 = entrySet.stream();
stream1.distinct()
.filter(stringIntegerEntry -> stringIntegerEntry.getValue()>19)
.forEach(stringIntegerEntry -> System.out.println(stringIntegerEntry.getKey()+"---"+stringIntegerEntry.getValue()));
//张三3---20
filter操作
//打印所有姓名长度大于1的作家的名字
authors.stream()
.filter(author -> author.getName().length()>1)
.forEach(author -> System.out.println(author));
map
可以把对流中的元素进行计算或转换
//打印所有作家的姓名
// authors.stream().forEach(author -> System.out.println(author.getName()));
//参数Author 返回值String
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getName())
.forEach(s -> System.out.println(s));
authors.stream()
.map(author -> author.getAge())
.map(age->age+10)
.forEach(age-> System.out.println(age));
}
distinct
去重
注意:distinct方达是依赖object的equals方法来判断是否是相同对象的。所以需要注意重写equals方法。
//打印所有作家名称 并不能重复
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.forEach(author -> System.out.println(author));
sorted
可以对流中的元素进行排序
# 如果调用了空参的sorted()方法 需要流中的元素必须实现Comparable
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Objects;
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Author implements Comparable<Author>{
private Long id;
private String name;
private Integer age;
private String intro;
private List<Book> books;
@Override
public int compareTo(Author o) {
return o.getAge()-this.getAge();//降序
}
}
List<Author> authors = getAuthors();
//对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素
authors.stream()
.distinct()
.sorted()
.forEach(author -> System.out.println(author.getAge()));
# 有参的sorted()方法
//对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素
authors.stream()
.distinct()
.sorted((o1, o2) -> o2.getAge()-o1.getAge()) //降序
.forEach(author -> System.out.println(author.getAge()));
limit
可以设置流的最大长度,超出的部分将被抛弃
List<Author> authors = getAuthors();
//对流中的元素按照年龄进行降序排序,并且要求不能有重复的元素,然后打印年龄最大的两个作家的姓名
authors.stream()
.distinct()
.sorted((o1, o2) -> o2.getAge()-o1.getAge()) //降序
.limit(2)
.forEach(author -> System.out.println(author.getName()));
skip
通过流中的前n个元素,返回剩下的元素
//打印除了年龄最大的作家外的其他作家 要求不能有重复元素,并且年龄降序
authors.stream()
.distinct()
.sorted((o1, o2) -> o2.getAge()-o1.getAge()) //降序
.skip(1)
.forEach(author -> System.out.println(author.getName()));
flatMap
map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素
// 例一
//打印所有书籍的名字,要求对重复的元素进行去重
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(book -> System.out.println(book.getName()));
//例二
List<Author> authors = getAuthors();
//打印现有数据的所有分类 要求对分类进行去重 不能出现这种格式:哲学,爱情
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct() //去重书籍
.flatMap(book -> Arrays.stream(book.getCategory().split(",")))
.distinct() //去重分类
.forEach(category->{
System.out.println(category);
});
终结操作
forEach
//输出所有作家的名字
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getName())
.distinct()
.forEach(name-> System.out.println(name));
count
可以获取当前流中元素的个数
//打印这些作家的所出书籍的题目,注意删除重复元素
List<Author> authors = getAuthors();
long count = authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.count();
System.out.println(count);
max&min
//分别获取这些作家的所出书籍的最高分和最低分并打印
List<Author> authors = getAuthors();
Optional<Integer> max = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.max((score1, score2) -> score1 - score2);
System.out.println(max.get());
Optional<Integer> min = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.min((score1, score2) -> score1 - score2);
System.out.println(min.get());
collect
把当前流转换成一个集合
//获取一个存放所有作者名字的List集合
List<Author> authors = getAuthors();
List<String> nameList = authors.stream()
.map(author -> author.getName())
.collect(Collectors.toList());
System.out.println(nameList);
//获取一个所有书名的set集合
Set<Book> collect = authors.stream()
.flatMap(author -> author.getBooks().stream())
.collect(Collectors.toSet());
System.out.println(collect);
//获取一个Map集合,map的key为作者名,value为List<Book>
Map<String, List<Book>> map = authors.stream()
.distinct()
.collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
System.out.println(map);
3.4 查找与匹配
anyMatch
可以用来判断是否有任意符合条件的元素,结果为boolean类型
//判断是否有年龄在29以上的作家
List<Author> authors = getAuthors();
boolean b = authors.stream()
.anyMatch(author -> author.getAge() > 29);
System.out.println(b);
allMatch
可以用来判断是否都符合匹配条件,结果为boolean类型,如果都符合结果为true,否则结果为false
//判断是否所有的作家都是成年人
boolean b1 = authors.stream()
.allMatch(author -> author.getAge() > 18);
System.out.println(b1);
noneMatch
可以用来判断是否都不符合匹配条件,结果为boolean类型,如果都不符合结果为true,否则结果为false
//否所有的作家年龄都没有超过100岁
boolean b2 = authors.stream()
.noneMatch(author -> author.getAge() > 100);
System.out.println(b2);
findAny
获取流中的任意一个元素,该方法没有办法保证获取的一定是流中的第一个元素
//获取任意一个年龄大于18的作家,如果存在输出他的名字
List<Author> authors = getAuthors();
Optional<Author> optionalAuthor = authors.stream()
.filter(author -> author.getAge() > 18)
.findAny();
optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
findFirst
获取流中的第一个元素
//获取一个年龄最小的作家,并输出他的姓名
Optional<Author> first = authors.stream()
.sorted(((o1, o2) -> o1.getAge() - o2.getAge()))
.findFirst();
first.ifPresent(author -> System.out.println(author.getName()));
3.5 reduce归并
对流中的数据按眠你旨定的计算方式计算出一个结果。(缩减操作)
reduce的作用是把stream中的元素给组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素和初始化值进行计算,计算结果再和后面的元素计算。
reduce两个参数的重载形式内部的计算方法如下:
T result=identity;
for (T element: this stream )
result= accumulator.apply(result, element)
return result;
其中identity就是我们可以通过方法参数传入的初始值,accumulator的apply具体进行什么计算也是我们通过方法参数来确定的。
//使用reduce求所有作者年龄的和
List<Author> authors = getAuthors();
Integer sum = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(0, (result, element) -> result + element);
System.out.println(sum);
//使用reduce求所有作者中年龄的最大值
Integer max = authors.stream()
.map(author -> author.getAge())
.reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
System.out.println(max);
//使用reduce求所有作者中年龄的最小值
Integer min = authors.stream()
.map(author -> author.getAge())
.reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);
System.out.println(min);
Optional<Integer> reduce = authors.stream()
.map(author -> author.getAge())
.reduce((result, element) -> result > element ? element : result);
reduce.ifPresent(age-> System.out.println(age));
3.5注意事项
- 惰性求值I (如果没有终结操作,没有中间操作是不会得到执行的)
- 流是一次性的(一旦一个流对象经过一个终结操作后。这个流就不能再被使用)
- 不会影响原数据(我们在流中可以多数据做很多处理。但是正常情况下是不会影响原来集合中的元素的。这往往也是我们期望的)