为什么要学?
- 能够看懂公司的代码
- 大数量下处理集合效率高
- 代码可读性高
- 消灭嵌套地狱
面向对象思想需要关注用什么对象完成什么事情。而函数式编程主要关注对数据进行了什么操作
1. Lambda表达式
Lambda可以对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现,让我们关注对数据进行了什么操作。
基本格式
不关注类名和方法名,只关注方法内的参数和方法体(关注参数以及参数做了什么事)
(参数列表)->{代码}
例子
我们在创建线程并启动时可以使用匿名内部类的写法:
new Thread(new Runnable() {
@Override
public void run() {
sout("thread run...");
}
}).start();
new Thread(() -> {
sout("thread run...");
}).start();
练习
public static int calculate(IntBinaryOperator operator) {
int a = 10;
int b = 20;
return operator.applyAsInt(a,b);
}
public static void main(String[] args) {
// int calculate = calculate(new IntBinaryOperator() {
// @Override
// public int applyAsInt(int left, int right) {
// return left + right;
// }
// });
// Lambda表达式
int calculate = calculate((int left, int right)-> {
return left + right;
}
);
// 省略
int calculate = calculate((left, right)-> left + right);
System.out.println(calculate);
}
Lambda省略规则
- 参数类型可以省略
- 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
- 方法只有一个参数时小括号可以省略
- 若记不住这些规则,只需记住alt+回车即可
2. Stream流
stream流使用的是函数式编程模式,如同它的名字一样,它可以被用来对集合或数组进行链状流式的操作。可以更方便的让我们对集合或数组操作。
创建流
1.单列集合:
集合对象.stream()
List<Author> author = getAuthors(); Stream<Author> stream = authors.stream();
2.数组:
Arrays.stream(数组)
或者使用Stream.of
来创建Integer[] arr = {1,2,3,4,5}; Stream<Integer> stream = Arrays.stream(arr); Stream<Integer> stream2 = Stream.of(arr);
3.双列集合:转换成单列集合后再创建
Map<String,Integer> map = new HashMap<>(); map.put("aa", 10); map.put("bb", 11); Stream<Map.Entry<String,Integer>> stream = map.entrySet().stream();
中间操作
filter过滤操作
可以对流中的元素进行条件过滤,符合过滤条件的才能继续留在流中。
map(可以理解为投影操作)
colllect
把当前流转换成一个集合
- 获取一个存放所有作者名字的list集合
List<Author> author = getAuthors(); List<String> nameList = authors.stream() .map(author -> author.getName()) .collect(Collectors.tolist()) System.out.println(nameList)
- 获取一个所有书名的Set集合
List<Author> author = getAuthors(); Set<String> nameList = authors.stream() .flatMap(author -> author.getBooks().stream()) .collect(Collectors.tolist()) System.out.println(nameList)
3.获取一个Map集合,map的key作为作者名,value为List
List<Author> author = getAuthors(); Map<String, List<Book>> nameList = authors.stream() .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks())); System.out.println(nameList)
3.函数式接口
只有一个抽象方法的接口称为函数接口
JDK的函数式接口都加上了@FunctionalInerface
注解进行标注。但是无论是否加上该注解只要接口中只有一个抽象方法,都是函数式接口。
方法引用
我们只需要在写完lamda表达式发现方法体只有一行代码,并且方法的调用时使用快捷键尝试能够将其转化为方法引用即可。
基本格式:
类名
或者对象名::方法名
引用类的静态方法
格式
类名::方法名
前提:方法体中只有一行代码,并且这个代码是调用了某个类的静态方法,并且我们要把重写的抽象方法中所有的参数都按照顺序传入了这个静态方法中。
引用对象的实例方法
格式
对象名::方法名
前提:方法体中只有一行代码,并且这个代码是调用了某个类的成员方法,并且我们要把重写的抽象方法中所有的参数都按照顺序传入了这个成员方法中。
引用类的实例方法
格式
类名::方法名
前提:方法体中只有一行代码,并且这个代码是调用了第一个参数的成员方法,并且我们要把重写的抽象方法中剩余的所有参数都按照顺序传入了这个成员方法中。
构造器引用
如果方法中的一行代码是构造器的话就可以使用构造器引用。
格式
类名::new
前提:方法体中只有一行代码,并且这个代码是调用了某个类的构造方法,并且我们要把重写的抽象方法中的所有参数都按照顺序传入了这个构造方法中。