# 函数式编程
Functional programming
面向函数编程是将行为抽象为一个函数,将一件事情分成若干个行为(函数),编程的本质是组合,组合的本质是范畴(Category),范畴是函数的组合。
核心思想:
面向对象关注什么对象完成什么事情(数据),面向函数关注完成事情的操作
函数式编程,集中点在函数,函数可以作为参数,返回值,具有不可变性(传递的参数相同结果肯定相同)
优点:
- 处理集合效率高
- 代码可读性高、简洁
- 减少嵌套
# Lambda 表达式
Lambda 起始于 JDK8,是 java8 中的一个语法糖,可以对匿名内部类的写法进行简化,是函数式编程的重要体现,让我们不关注对象本身而是关注数据做了什么。
# 核心原则
- 可推导可省略
# 设计原则
- 单一原则
- 开放闭合原则
# 格式
(参数列表)->{代码}
栗子:
创建线程执行特定操作:
(匿名内部类构造方法传入 Runnable 接口实现):
new Thread(new Runnable(){ | |
@Override | |
public void run() { | |
System.out.println(); | |
} | |
}).start(); |
Lambda 写法:
new Thread(()->{ | |
System.out.println(); | |
}).start(); |
大概总结(伪代码):
new Class(new Interface(){ | |
@Override | |
public T function(? a){ | |
pass; | |
} | |
}); | |
↓ | |
new Class((? a) -> {pass}); |
关注点:括号内参数,大括号内代码
# 省略规则
💥参数类型可以省略!
🎈方法体只有一句代码时大括号 return 和唯一 一句代码分号可以省略
😲方法只有一个参数小括号也可以省略
new Thread(() -> System.out.println("mmyser")).start(); |
# Stream 流
Java8 的 Stream 使用的是函数式编程模式,可以用来对集合和数组进行链状流氏的操作。
# 流的使用
类
@Data | |
@AllArgsConstructor | |
@NoArgsConstructor | |
public class Author { | |
private Long id; | |
private String name; | |
private Integer age; | |
private String intro; | |
private List<Book> books; | |
} |
@Data | |
@AllArgsConstructor | |
@NoArgsConstructor | |
public class Book { | |
private Long id; | |
private String name; | |
private String category; | |
private Integer score; | |
private String intro; | |
} |
authorList.stream() | |
.distinct()// 去重 | |
// 过滤器 | |
.filter(new Predicate<Author>() { | |
@Override | |
public boolean test(Author author) { | |
return author.getAge() < 18; | |
} | |
}) | |
// 增强循环 | |
.forEach(new Consumer<Author>() { | |
@Override | |
public void accept(Author author) { | |
System.out.println(author.getName()); | |
} | |
}); |
lambda:
authorList.stream() | |
.distinct() | |
.filter(author12 -> author12.getAge() < 18) | |
.forEach(author1 -> System.out.println(author1.getName())); |
# 常用操作
# 创建流
单列集合(实现接口 Collection): 对象.stream
List<Author> authors = getAuthors(); | |
Stream<Author> stream = authors.stream(); |
数组: Arrays.stream
(数组) 或者使用 Stream.of
来创建
Integer[] arr = {1,2,3,4,5}; | |
Stream<Integer> stream = Arrays.stream(arr); | |
Stream<Integer> stream2 = Stream.of(arr); |
双列集合(实现接口 Map):转换成单列集合后再进行创建;
Map<String,Integer> map = new HashMap<>(); | |
map.put("蜡笔小新",19); | |
map.put("黑子",17); | |
map.put("日向翔阳",16); | |
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream(); |
# 中间操作
# filter
通过条件过滤流中的元素
# map
将流中的元素进行转换和计算
# distinct
取出流中的重复元素
依照 equal () 方法来进行判重
# sorted
对流中的元素进行排序
authors.stream() | |
.sorted((o1, o2) -> o1.getAge() - o2.getAge()) | |
.forEach(author -> System.out.println(author)); | |
// | |
authors.stream() | |
.sorted(Comparator.comparingInt(Author::getAge)) | |
.forEach(System.out::println); |
无参方法要求元素需要实现 Comparable 接口( compareTo()
方法)
# limit
设置流的最大长度
# skip
跳过流中的 n 个元素
# flatMap
将流中一个对象转换成多个对象
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
对流中的元素进行遍历并进行具体操作
# count
获取流中元素的个数 (返回类型 long)
Long num = authors.stream() | |
.flatMap(author -> author.getBooks().stream()) | |
.map(book -> book.getScore()) | |
.count(); | |
System.out.println(num); |
# max&min
获得流中的最值
Optional<Integer> optional = authors.stream() | |
.flatMap(author -> author.getBooks().stream()) | |
.map(book -> book.getScore()) | |
.max((score1, score2) -> score1 - score2); | |
System.out.println(optional.get()); |
# collect
将流转换成一个集合
List<String> list = authors.stream() | |
.map(author -> author.getName()) | |
.collect(Collectors.toList()); | |
System.out.println(list); |
Set<Book> set = authors.stream() | |
.flatMap(author -> author.getBooks().stream()) | |
.collect(Collectors.toSet()); | |
System.out.println(set); |
Map<String, Object> map = authors.stream() | |
.distinct() | |
.collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks())); | |
System.out.println(map); |
# anyMatch
判断是否有任意符合匹配条件的元素(返回布尔类型)
boolean flag = authors.stream() | |
.anyMatch(author -> author.getAge() < 18); |
# allMatch
用来判断是否都符合条件(返回布尔类型)
# noneMatch
判断流中元素是否都不符合匹配条件(返回布尔类型)
# findAny
获取流中任意一个元素(返回 Optional 类型)
Optional<Author> optional = authors.stream() | |
.filter(author -> author.getAge() >28) | |
.findAny(); | |
optional.ifPresent(author -> System.out.println(author)); |
# findFirst
获取流中第一个元素
# 💥reduce
对流中的数据按照指定 计算方式计算出一个结果(缩减)
内部逻辑
T result = identity | |
for(T element : this stream) | |
result = accumulator.apply(result, element) | |
return result; |
int sum = authors.stream() | |
.distinct() | |
.map(author -> author.getAge()) | |
.reduce(0, (result, element) -> result + result); |
reduce 一个参数重载形式内部的计算
boolean foundAny = false; | |
T result = null; | |
for(T element : this stream){ | |
if(!foundAny = true) { | |
foundAny = true; | |
result = element; | |
} else { | |
result = accumulator.apply(result, element); | |
} | |
return foundAny ? Optional.of(result) : Optional.emmpty(); | |
} |
# 注意事项
- 如果没有终结操作,中间操作不会执行
- 流是一次性的,只能经过一个终结操作
- 流的操作不会影响元数据
# 参考
- 三更草堂
- 慕课教程