# 函数式编程

Functional programming

面向函数编程是将行为抽象为一个函数,将一件事情分成若干个行为(函数),编程的本质是组合,组合的本质是范畴(Category),范畴是函数的组合。

核心思想

  • 面向对象关注什么对象完成什么事情(数据),面向函数关注完成事情的操作

  • 函数式编程,集中点在函数,函数可以作为参数,返回值,具有不可变性(传递的参数相同结果肯定相同)

优点:

  • 处理集合效率高
  • 代码可读性高、简洁
  • 减少嵌套

# Lambda 表达式

Lambda 起始于 JDK8,是 java8 中的一个语法糖,可以对匿名内部类的写法进行简化,是函数式编程的重要体现,让我们不关注对象本身而是关注数据做了什么。

# 核心原则

  • 可推导可省略

# 设计原则

  • 单一原则
  • 开放闭合原则

# 格式

1
(参数列表)->{代码}

栗子:

创建线程执行特定操作:

(匿名内部类构造方法传入 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});

关注点:括号内参数,大括号内代码

# 省略规则

  • 💥参数类型可以省略!

  • 🎈方法体只有一句代码时大括号 return 和唯一 一句代码分号可以省略

  • 😲方法只有一个参数小括号也可以省略

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

取出流中的重复元素

依照 equal () 方法来进行判重

# 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();
}

# 注意事项

  • 如果没有终结操作,中间操作不会执行
  • 流是一次性的,只能经过一个终结操作
  • 流的操作不会影响元数据

# 参考

  • 三更草堂
  • 慕课教程
更新于 阅读次数 本文阅读量:

请我喝[茶]~( ̄▽ ̄)~*

Windlinxy 微信支付

微信支付

Windlinxy 支付宝

支付宝