函数式编程
1 概述
2 Lambda表达式
https://www.runoob.com/java/java8-lambda-expressions.html
3 Stream流
https://mp.weixin.qq.com/s/BjBtNRXj-R5kzb34cgHsTQ
3.1 创建流
// 创建stream的方法
//1 使用Collection下的 stream() 和 parallelStream() 方法
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); // 顺序流
Stream<String> parallelStream = list.parallelStream(); // 并行流
// 2 使用Arrays 中的stream()方法,将数组转成流
Integer[] nums = new Integer[10];
Stream<Integer> stream1 = Arrays.stream(nums);
//3 使用Stream中的静态方法:of()、iterate()、generate()
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
stream2.forEach(System.out::println); // 0 2 4 6 8 10
Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
stream3.forEach(System.out::println);
//4 使用 BufferedReader.lines() 方法,将每行内容转成流
BufferedReader reader = new BufferedReader(new FileReader("F:\\test_stream.txt"));
Stream<String> lineStream = reader.lines();
lineStream.forEach(System.out::println);
// 5 使用 Pattern.splitAsStream() 方法,将字符串分隔成流
Pattern pattern = Pattern.compile(",");
Stream<String> stringStream = pattern.splitAsStream("a,b,c,d");
stringStream.forEach(System.out::println);
3.2 中间操作
filter
过滤
private static void test1(){
List<Author> authors = getAuthors();
// 年龄<18
authors.stream()
.filter(author -> author.getAge() < 18) // 过滤
.forEach(author -> System.out.println(author.getAge())); // 迭代
}
map
流中的元素进行计算或者转换
private static void test2(){
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getName())
.forEach(name -> System.out.println(name));
authors.stream()
.map(author -> author.getAge())
.map(age-> age+10)
.forEach(age -> System.out.println(age));
}
distinct
去重
private static void test3() {
// 打印姓名 去重
List<Author> authors = getAuthors();
authors.stream()
.distinct() //去重
.forEach(author -> System.out.println(author.getName()));
}
sorted
排序
private static void test4() {
// 年龄降序排序 去重 自定义排序
List<Author> authors = getAuthors();
authors.stream()
.distinct()
.sorted(new Comparator<Author>() {
@Override
public int compare(Author o1, Author o2) {
//return o1.getAge().compareTo(o2.getAge()); //升序
return o2.getAge().compareTo(o1.getAge()); //降序
}
}).forEach(author -> System.out.println(author.getAge()));
authors.stream()
.distinct()
.sorted((o1,o2) -> o2.getAge().compareTo(o1.getAge())) //降序
.forEach(author -> System.out.println(author.getAge()));
}
limit
private static void test5() {
// 按照年龄降序 去重 输出年龄最大的两个作家姓名
List<Author> authors = getAuthors();
authors.stream()
.distinct() // 去重
.sorted((a1,a2)-> a2.getAge().compareTo(a1.getAge())) // 按照年龄降序
.limit(2) // 限制输出2个
.forEach(author -> System.out.println(author.getAge() +"==="+author.getName()));
}
skip
跳过流中的前n个元素
private static void test6() {
// 按照年龄降序 去重 跳过年龄最大的作家
List<Author> authors = getAuthors();
authors.stream()
.distinct() // 去重
.sorted((a1, a2) -> a2.getAge().compareTo(a1.getAge())) // 按照年龄降序
.skip(1)
.forEach(author -> System.out.println(author.getAge() + "===" + author.getName()));
}
flatMap
接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
private static void test8() {
// 得到所有书籍的分类 去重
List<Author> authors = getAuthors();
List<String> collect = authors.stream()
.flatMap(author -> author.getBooks().stream()) // List<Book>
.distinct()
.flatMap(book -> Arrays.stream(book.getCategory().split(",")))
.distinct()
.collect(Collectors.toList());
System.out.println(collect); //[分类1, 分类2, 分类3, 分类4, 分类5]
}
private static void test7() {
// 打印所有书籍的名字 去重
List<Author> authors = getAuthors();
authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.forEach(book -> System.out.println(book.getName()));
}
3.3 终结操作
forEach
对流中数据进行遍历操作
private static void test9() {
List<Author> authors = getAuthors();
authors.stream()
.map(Author::getName)
.forEach(System.out::println);
}
count
统计当前流中的元素的个数
private static void test10() {
// 统计书籍的数目 去重
List<Author> authors = getAuthors();
long count = authors.stream()
.flatMap(author -> author.getBooks().stream())
.distinct()
.count();
System.out.println(count);
}
max&min
private static void test12() {
// 获取所有书籍的评分最大值 最小值
List<Author> authors = getAuthors();
/* Integer max = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.max(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
}).get();*/
Integer max = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.max((o1, o2) -> o1 - o2).get();
Integer min = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(book -> book.getScore())
.min((o1, o2) -> o1 - o2).get();
System.out.println(max);
System.out.println(min);
}
collect
接收一个Collector实例,将流中元素收集成另外一个数据结构
private static void test13() {
List<Author> authors = getAuthors();
// 获取所有作者名 list集合
List<String> nameList = authors.stream()
.map(Author::getName)
.collect(Collectors.toList());
System.out.println(nameList);
// 获取所有书籍名set集合
Set<String> bookNameSet = authors.stream()
.flatMap(author -> author.getBooks().stream())
.map(Book::getName)
.collect(Collectors.toSet());
System.out.println(bookNameSet);
// 获取map
Map<String, List<Book>> map = authors.stream()
.distinct() // 去重 key 不能重复
.collect(Collectors.toMap(Author::getName, Author::getBooks));
System.out.println(map);
}
查找与匹配
anyMatch
接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
private static void test14() {
List<Author> authors = getAuthors();
/*boolean b = authors.stream()
.map(author -> author.getAge())
.anyMatch(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer > 30;
}
});*/
boolean b = authors.stream()
.map(author -> author.getAge())
.anyMatch(age -> age > 30); // 存在年龄大于30的 返回true
System.out.println(b);
}
noneMatch
接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
private static void test15() {
List<Author> authors = getAuthors();
boolean b = authors.stream()
.map(author -> author.getAge()) // 33 15 13 13
.distinct() // 33 15 13
.noneMatch(age -> age > 40); // true
System.out.println(b);
}
allMatch
接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false。
private static void test16() {
List<Author> authors = getAuthors();
boolean b = authors.stream()
.map(author -> author.getAge()) // 33 15 13 13
.distinct() // 33 15 13
.allMatch(age -> age > 30); // false
System.out.println(b);
}
findFirst
返回流中第一个元素
private static void test18() {
List<Author> authors = getAuthors();
Optional<Author> optionalAuthor = authors.stream()
.filter(author -> author.getAge() > 13)
.findFirst();
if (optionalAuthor.isPresent()){
System.out.println(optionalAuthor.get());
}else {
System.out.println("不存在满足条件的数据");
}
}
findAny
返回流中的任意元素
private static void test17() {
List<Author> authors = getAuthors();
Optional<Author> optionalAuthor = authors.stream()
.filter(author -> author.getAge() > 45)
.findAny();
if (optionalAuthor.isPresent()){
System.out.println(optionalAuthor.get());
}else {
System.out.println("不存在满足条件的数据");
}
}
reduce归并
对流中的数据依照你制定的规格计算出一个结果
T result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;
private static void test19() {
// 年龄求和
List<Author> authors = getAuthors();
Integer reduce = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(0, (result, element) -> result + element);
System.out.println(reduce);
}
private static void test20() {
// 作者的年龄最大 最下值
List<Author> authors = getAuthors();
Integer max = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(Integer.MIN_VALUE, (result, element) -> (result < element ? element : result));
Integer min = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(Integer.MAX_VALUE, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer result, Integer element) {
return element < result ? element : result;
}
});
System.out.println(max);
System.out.println(min);
}
boolean foundAny = false;
T result = null;
for (T element : this stream) {
if (!foundAny) {
foundAny = true;
result = element; // 第一个参数作为result初始化值
}
else
result = accumulator.apply(result, element);
}
return foundAny ? Optional.of(result) : Optional.empty();
private static void test21() {
List<Author> authors = getAuthors();
Optional<Integer> optional = authors.stream()
.distinct()
.map(author -> author.getAge())
.reduce(new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer result, Integer element) {
return result < element ? element:result;
}
});
optional.ifPresent(i -> System.out.println(i));
}
4 Option
4.1 概述
4.2 使用
4.2.1 创建对象
Optional.ofNullable(T value)
Optional.of(T value) // value == null throw new NullPointerException()
4.2.2 安全消费值
Optional<Author> optionalAuthor = Optional.ofNullable(author);
optionalAuthor.ifPresent(System.out::println);
4.2.3 获取值
get方法 不推荐 可能出现异常
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
4.2.4 安全获取值
- orElseGet
// 创建Optional对象
Optional<Author> optionalAuthor = Optional.ofNullable(getAuthor());
// 没有值 则返回默认值
Author author = optionalAuthor.orElseGet(() -> new Author());
- orElseThrow
// 创建Optional对象
Optional<Author> optionalAuthor = Optional.ofNullable(getAuthor());
try {
Author author = optionalAuthor.orElseThrow(() -> new RuntimeException("author==null"));
System.out.println(author);
} catch (RuntimeException e) {
e.printStackTrace();
}
4.2.5 过滤
private static void testFilter() {
// 创建Optional对象
Optional<Author> optionalAuthor = Optional.ofNullable(getAuthor());
//Optional<Author> author = optionalAuthor.filter(new Predicate<Author>() {
// @Override
// public boolean test(Author author) {
// return author.getAge() > 15;
// }
//});
//
//author.ifPresent(author1 -> System.out.println(author1.getName()));
optionalAuthor.filter(author -> author.getAge()>15).ifPresent(result -> System.out.println(result.getName()));
}
4.2.6 判断
// 判断是否为空
public boolean isPresent() {
return value != null;
}
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
4.2.7 数据转换
map
private static void testMap() {
Optional<Author> optionalAuthor = Optional.ofNullable(getAuthor());
Optional<List<Book>> optionalBooks = optionalAuthor.map(author -> author.getBooks());
optionalBooks.ifPresent(new Consumer<List<Book>>() {
@Override
public void accept(List<Book> books) {
books.forEach(book -> System.out.println(book.getName()));
}
});
}
5 函数式接口
5.1概述
只有一个抽象方法的接口称为函数式接口。
@FunctionalInterface
6 方法引用
7 高级用法
基本数据类型优化
mapToInt
private static void test23() {
List<Author> authors = getAuthors();
authors.stream()
.map(author -> author.getAge())
.map(age -> age + 10)
.filter(age -> age > 18)
.map(age -> age + 2)
.forEach(System.out::println);
// 优化 mapToInt
authors.stream()
.mapToInt(author -> author.getAge())
.map(age -> age + 10)
.filter(age -> age > 18)
.map(age -> age + 2)
.forEach(System.out::println);
}
并行流
private static void test24() {
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = stream.parallel() // 并行流
.peek(new Consumer<Integer>() { // 调试用 消费数据
@Override
public void accept(Integer num) {
System.out.println(num+"--"+Thread.currentThread().getName());
}
})
.filter(num -> num > 5)
.reduce((result, element) -> result + element)
.get();
System.out.println(sum);
}
示例使用的数据
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode //去重使用
public class Author {
private Long id;
private String name;
private Integer age;
private String intro;
private List<Book> books;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class Book {
private Long id;
private String name;
private String category;
private Integer score;
private String intro;
}
private static List<Author> getAuthors() {
Author author = new Author(1L, "张三", 33, "卡时间段圣诞节啊", null);
Author author2 = new Author(2L, "李四", 15, "卡时间段圣诞节啊2", null);
Author author3 = new Author(3L, "王五", 13, "卡时间段圣诞节啊3", null);
Author author4 = new Author(3L, "王五", 13, "卡时间段圣诞节啊3", null);
ArrayList<Book> books1 = new ArrayList<>();
ArrayList<Book> books2 = new ArrayList<>();
ArrayList<Book> books3 = new ArrayList<>();
books1.add(new Book(1L, "高数", "分类1,分类2", 5, "高数啊"));
books1.add(new Book(2L, "高数1", "分类2", 2, "高数啊1"));
books2.add(new Book(3L, "大学物理", "分类3,分类2", 4, "大学物理啊"));
books2.add(new Book(3L, "大学物理", "分类3,分类2", 4, "大学物理啊"));
books2.add(new Book(4L, "大学物理2", "分类3", 4, "大学物理啊2"));
books3.add(new Book(5L, "大学物理3", "分类4", 2, "大学物理啊3"));
books3.add(new Book(6L, "大学物理4", "分类4,分类5", 2, "大学物理啊4"));
books3.add(new Book(6L, "大学物理4", "分类4,分类5", 2, "大学物理啊4"));
author.setBooks(books1);
author2.setBooks(books2);
author3.setBooks(books3);
author4.setBooks(books3);
return new ArrayList<>(Arrays.asList(author, author2, author3, author4));
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现