# 函数式编程
Functional programming
面向函数编程是将行为抽象为一个函数,将一件事情分成若干个行为(函数),编程的本质是组合,组合的本质是范畴(Category),范畴是函数的组合。
核心思想:
优点:
# Lambda 表达式
Lambda 起始于 JDK8,是 java8 中的一个语法糖,可以对匿名内部类的写法进行简化,是函数式编程的重要体现,让我们不关注对象本身而是关注数据做了什么。
# 核心原则
# 设计原则
# 格式
栗子:
创建线程执行特定操作:
(匿名内部类构造方法传入 Runnable 接口实现):
1 2 3 4 5 6
| new Thread(new Runnable(){ @Override public void run() { System.out.println(); } }).start();
|
Lambda 写法:
1 2 3
| new Thread(()->{ System.out.println(); }).start();
|
大概总结(伪代码):
1 2 3 4 5 6 7 8
| new Class(new Interface(){ @Override public T function(? a){ pass; } }); ↓ new Class((? a) -> {pass});
|
关注点:括号内参数,大括号内代码
# 省略规则
1
| new Thread(() -> System.out.println("mmyser")).start();
|
# Stream 流
Java8 的 Stream 使用的是函数式编程模式,可以用来对集合和数组进行链状流氏的操作。
# 流的使用
类
1 2 3 4 5 6 7 8 9 10
| @Data @AllArgsConstructor @NoArgsConstructor public class Author { private Long id; private String name; private Integer age; private String intro; private List<Book> books; }
|
1 2 3 4 5 6 7 8 9 10
| @Data @AllArgsConstructor @NoArgsConstructor public class Book { private Long id; private String name; private String category; private Integer score; private String intro; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 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:
1 2 3 4
| authorList.stream() .distinct() .filter(author12 -> author12.getAge() < 18) .forEach(author1 -> System.out.println(author1.getName()));
|
# 常用操作
# 创建流
单列集合(实现接口 Collection): 对象.stream
1 2
| List<Author> authors = getAuthors(); Stream<Author> stream = authors.stream();
|
数组: Arrays.stream
(数组) 或者使用 Stream.of
来创建
1 2 3
| Integer[] arr = {1,2,3,4,5}; Stream<Integer> stream = Arrays.stream(arr); Stream<Integer> stream2 = Stream.of(arr);
|
双列集合(实现接口 Map):转换成单列集合后再进行创建;
1 2 3 4 5
| 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
取出流中的重复元素
# sorted
对流中的元素进行排序
1 2 3 4 5 6 7
| 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
将流中一个对象转换成多个对象
1 2 3 4 5 6 7 8
| 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)
1 2 3 4 5
| Long num = authors.stream() .flatMap(author -> author.getBooks().stream()) .map(book -> book.getScore()) .count(); System.out.println(num);
|
# max&min
获得流中的最值
1 2 3 4 5
| 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
将流转换成一个集合
1 2 3 4
| List<String> list = authors.stream() .map(author -> author.getName()) .collect(Collectors.toList()); System.out.println(list);
|
1 2 3 4
| Set<Book> set = authors.stream() .flatMap(author -> author.getBooks().stream()) .collect(Collectors.toSet()); System.out.println(set);
|
1 2 3 4
| Map<String, Object> map = authors.stream() .distinct() .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks())); System.out.println(map);
|
# anyMatch
判断是否有任意符合匹配条件的元素(返回布尔类型)
1 2
| boolean flag = authors.stream() .anyMatch(author -> author.getAge() < 18);
|
# allMatch
用来判断是否都符合条件(返回布尔类型)
# noneMatch
判断流中元素是否都不符合匹配条件(返回布尔类型)
# findAny
获取流中任意一个元素(返回 Optional 类型)
1 2 3 4
| Optional<Author> optional = authors.stream() .filter(author -> author.getAge() >28) .findAny(); optional.ifPresent(author -> System.out.println(author));
|
# findFirst
获取流中第一个元素
# 💥reduce
对流中的数据按照指定 计算方式计算出一个结果(缩减)
内部逻辑
1 2 3 4
| T result = identity for(T element : this stream) result = accumulator.apply(result, element) return result;
|
1 2 3 4
| int sum = authors.stream() .distinct() .map(author -> author.getAge()) .reduce(0, (result, element) -> result + result);
|
reduce 一个参数重载形式内部的计算
1 2 3 4 5 6 7 8 9 10 11
| 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(); }
|
# 注意事项
- 如果没有终结操作,中间操作不会执行
- 流是一次性的,只能经过一个终结操作
- 流的操作不会影响元数据
# 参考