函数式编程思想
- 面向对象的思想
- 做一件事,找一个能解决这件事的对象,调用对象的方法完成
- 函数式编程思想
- 只要能获取结果,谁去做,怎么做不重要,重视的是结果,而不是过程
Lambda表达式
初次体验
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(123455 + "=====" + Thread.currentThread().getName());
}
}).start();
new Thread(() -> {
System.out.println(123455 + "=====" + Thread.currentThread().getName());
}).start();
}
- 由匿名内部类到lambda表达式的简化
匿名内部类的弊端和好处
- 好处: 省去实现类的定义
- 弊端: 语法太复杂
语义分析
- public abstract void run()
- 无参数:不需要任何条件即可执行的方案
- 无返回值 :不需要产生结果
- 代码块(方法体) : 方案的具体执行步骤
- 同样语义体现在Lambda语法中,更加简单
- () -> System.out.println(“多线程任务执行”);
- 前端的小括号
()
,代表着参数无,代表不需要任何条件 - 中间的一个箭头代表将前面的参数传递给后面的代码
- 后面的输出语句即业务逻辑代码
- 前端的小括号
Lambda标准格式
- 三部分
- 一些参数
- 一个剪头
- 一段代码
- 格式
- (参数列表) -> (重写方法的代码)
- () :—> 没有参数就空着,有参数就写参数,多个参数都好分割
- -> :—> 传递的意思
- {} :—>重写抽象方法的方法体
Lambda表达式
- Lambda表达式是可推导,可省略
- 可省略的内容
- (参数列表): 括号参数列表的数据类型可以省略不写
- (参数列表): 括号的参数如果只有一个,那么类型和()都可以省略
- (一些代码): 如果{}中的代码只有一行,无论是否有返回值,都可以省略({},return,分号)
- 要省略{},return,分号必须一起省略
Lambda表达式使用前提
- 使用Lambda必须要有接口,且要求接口中
有且仅有一个抽象方法
- 使用Lambda标傲世必须具有
上下文推断
有且仅有一个抽象方法的接口
---->“函数式接口”
1.函数式接口
1.1 概念
有且仅有一个抽象方法的接口
-----> 函数式接口- 主要是体现在Lambda使用的接口,满足
函数式接口
才可以进行Lambda推导 语法糖
-->更加方便,但是原理不变的代码语法- 例如for-each zengqiangfor循环,底层其实还是迭代器
- Lambda可以当做匿名内部类的
语法糖
1.2 格式
- 只要满足有且仅有一个抽象方法的接口即可
1.3 @FunctionalInterface
- 作用检测接口中是否只有一个函数式接口
- 是:编译成功
- 否:编译失败
1.4 函数式接口使用
-
一般可以作为方法的参数和返回值类型
-
Lambda表达式作为参数传递,会出现延迟加载,使用时在计算执行
1.5 Lambda表达式作为函数参数和函数的返回值
- 函数参数
public static void main(String[] args) { startThread(() -> System.out.println(Thread.currentThread().getName() + "启动了") ); } public static void startThread(Runnable thread) { new Thread(thread).start(); }
- 函数返回值
public static Comparator<String> getComparator() { /*return new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } };*/ /*return (String o1, String o2) -> { return o1.compareTo(o2); };*/ return (o1, o2) -> o1.compareTo(o2); } public static void main(String[] args) { String[] arr = new String[]{ "aa", "bbb", "ccc", "a", "ss" }; System.out.println(Arrays.toString(arr)); Arrays.sort(arr, getComparator()); System.out.println(Arrays.toString(arr)); }
2. 常用的函数式接口
- 主要是分布在
java.util.function
包中
3.1 Supplier接口
java.util.function.Supplier<T>
接口仅含有一个无参方法,T get()
Supplier<T>
接口是生产型接口,接口泛型制定什么类型,就返回什么泛型public static int getMax(Supplier<Integer> sup) { return sup.get(); } public static void main(String[] args) { int[] arr = new int[]{ 1, 5, 8, 9, 3, 4, 1, 3, 4, 4, 5, 6, 2, 13, 7, 6, 43, 1 }; int max = getMax(() -> { // 获取数组最大值 int temp = arr[0]; for (int i : arr) { if (i > temp) { temp = i; } } return temp; }); System.out.println(max); }
3.2 Consumer接口
java.util.function.Consumer接口<T>
接口仅含有一个有无参方法,void accept(T t)
Consumer接口<T>
接口是生产型接口,接口泛型制定什么类型,就返回什么泛型- 他不是生产数据,而是消费数据
public static void method(String name, Consumer<String> con) { con.accept(name); } public static void main(String[] args) { method("gcf", (String name) -> { //System.out.println(name); // 对字符串反转 }); }
3.2.1 andThen() 方法
- 如果一个方法的参数和返回值全是
Consumer
类型,name可以实现效果:数据消费时,首先做一个操作,然后再做一个操作,实现组合 - 这个方法就是
Consumer
的默认方法andThen()
andThen
是连接两个Consumer
的 —> con1.andThen(con2).accept("");