函数式编程-Stream流
示例
1、Lambda表达式
1)基本格式
(参数列表) -> {代码}
匿名内部类上 alt+回车 可以自动生成Lambda表达式
2)eg1、创建线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("...");
}
}).start();
// 接口中只有一个抽象方法需要重写
// 关注的是 run 方法的参数和 方法体
new Thread(()->{
System.out.println("...");
}
).start();
3)eg2、IntBinaryOperator
public static int calculateNum(IntBinaryOperator operator) {
int a = 10;
int b = 20;
return operator.applyAsInt(a, b);
}
public static void main(String[] args) {
int res = calculateNum(new IntBinaryOperator() {
@Override
public int applyAsInt(int left, int right) {
return left + right;
}
});
res = calculateNum(((int left, int right) -> {
return left + right;
}));
// 进一步简化
res = calculateNum((left, right) -> left + right);
}
2、Stream流
1)使用目的
可以更方便的地操作集合
2)数据准备
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Book {
private Integer bookId;
private String bookName;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Author {
private Integer id;
private String name;
private List<Book> books;
}
3)快速入门
推荐先用匿名内部类写,再用 alt + 回车 生成 lambda 表达式
public static void main(String[] args) {
List<Author> authors = getAuthors();
authors.stream() // 把集合转换成流
.distinct() // 去重
.filter(author -> author.getId() < 2) // 取 id < 2 的元素
.forEach(author -> System.out.println(author.getId()));// 终结操作
}
private static List<Author> getAuthors() {
List<Author> authors = new ArrayList<>();
Author aa = new Author(1, "aa", null);
Author dd = new Author(1, "aa", null);
Author bb = new Author(2, "bb", null);
Author cc = new Author(3, "cc", null);
authors.add(aa);
authors.add(dd);
authors.add(bb);
authors.add(cc);
return authors;
}
操作数组:Arrays.stream(数组名);
或者:Stream.of(数组名);
操作双列集合:
HashMap<Integer, String> map = new HashMap<>();
Stream<Map.Entry<Integer, String>> stream = map.entrySet().stream();
4)中间操作
a、filter
筛选过滤
b、map
对流中元素进行计算或映射
List<Author> authors = getAuthors();
// 从 Author 中提取 name 并转换为 String 类型
authors.stream() // 把集合转换成流
.map(Author::getName)
.forEach(System.out::println);
authors.stream() // 把集合转换成流
.map(Author::getId) // 提取 id
.map(id -> id + 10) // 将 id + 10 再输出
.forEach(System.out::println);
c、distinct
去重,依赖 Object 的 equals 方法,如果要自定义去重规则,可以重写 equals 方法
d、sorted
排序
authors.stream() // 把集合转换成流
.distinct() // 去重
.sorted((o1, o2) -> o2.getId() - o1.getId()) // id 降序,不要记这个,容易记错,最好的方法是测试,不对就换个顺序即可
.forEach(System.out::println);
e、limit
设置流的最大长度,超出部分将被抛弃
authors.stream() // 把集合转换成流
.distinct() // 去重
.sorted((o1, o2) -> o2.getId() - o1.getId()) // id 降序
.limit(2) // 取前两个元素
.forEach(System.out::println);
f、skip
跳过前 n 个元素
authors.stream() // 把集合转换成流
.distinct() // 去重
.sorted((o1, o2) -> o2.getId() - o1.getId()) // id 降序
.skip(2) // 跳过前面 2 个元素
.forEach(System.out::println);
g、flatMap
相比于 map,flatMap 可以将一个对象转换为多个对象作为流中元素,常用于对象中有集合对象的情况
authors.stream() // 把集合转换成流
.flatMap(author -> author.getBooks().stream())
.forEach(System.out::println);
5)终结操作
a、forEach
遍历流
b、count
获取流中的元素个数
c、min&max
获取流中的最值
Optional<Integer> max = authors.stream() // 把集合转换成流
.flatMap(author -> author.getBooks().stream())
.map(Book::getBookId)
.max((o1, o2) -> o2 - o1);// 对 book_id 降序排序并取最大值
System.out.println(max.get());
d、collect
将当前流转化为集合
List<String> list = authors.stream() // 把集合转换成流
.map(Author::getName)
.collect(Collectors.toList()); // 提取 作家名 并转换为 List
System.out.println(list);
Map<String, List<Book>> map = authors.stream() // 把集合转换成流
.distinct() // 去重
.collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
System.out.println(map);
e、查找与匹配
anyMatch
判断是否有任意符合匹配条件的元素,返回值为 boolean
allMatch
判断是否所有元素都符合匹配条件,返回值为 boolean
noneMatch
判断是否所有元素都不符合匹配条件,返回值为 boolean
findAny
获取流中任意一个元素,可以设置条件
findFirst
获取流中第一个元素,可以设置条件
f、reduce 归并
将流中的数据按照自己制定的计算方式计算出一个结果(缩减操作),其具体作用是把stream中的元素组合起来,我们可以传入一个初始值,它会按照我们的计算方式依次拿流中的元素和初始化值进行计算,计算结果在和后面的元素进行计算
Integer sum = authors.stream() // 把集合转换成流
.distinct()
.map(Author::getId)
.reduce(0/*初始值*/, (result/*初始值*/, element/*流中元素*/) -> result + element);
System.out.println(sum);
3、Optional
作用:避免空指针异常
4、函数式接口
只有一个抽象方法的接口,通常都在接口上加上@FunctionalInterface
注解进行标识验证,但无论加不加,只要接口中只有一个抽象方法,都叫做函数式接口
5、方法引用
1)引用类的静态方法
类名::方法名
2)引用对象的实例方法
对象名::方法名
3)引用类的实例方法
类名::方法名
4)构造器引用
类名::new
6、高级用法-并行流
1)定义
当流中有大量元素时,可以使用并行流提高效率,运用在多线程环境中
2)用法
Integer sum = authors.stream() // 把集合转换成流
.parallel() // 使用并行流
.distinct()
.map(Author::getId)
.reduce(0/*初始值*/, (result/*初始值*/, element/*流中元素*/) -> result + element);
System.out.println(sum);