网页左边,向下滑有目录索引,可以根据标题跳转到你想看的内容 |
---|
Lambda表达式是java8中的新特性(JDK1.8版本更新的) |
---|
- 可以替代只有一个抽象函数的接口实现
- 告别匿名内部类
- 代码简介易懂
- 提升集合、框架的迭代、遍历、过滤数据的操作
Lambda的特点 |
---|
- 函数式编程
- 参数类型自动推断
- 代码量少,简洁
- 适用于任何有函数式接口的地方
函数式接口 |
---|
就是有且只能有一个抽象方法的接口称为函数式接口 |
package com.company;
import java.util.ArrayList;
/**
* 函数式接口,有且只能有一个抽象方法的的接口
*
* 注解@FunctionalInterface
* 此注解作用就是标识一个接口为函数式接口,如果此接口中定义了两个以上的抽象方法,将会报错
* 因为它不满足函数式接口特性,不能称之为函数式接口
*
* 此注解可以不加,但是为了可读性,也为了让别人看到你的代码,知道你这是一个函数式接口,从而不会在你的接口中加抽象方法
*
* 还是加上为好
*/
@FunctionalInterface
public interface Test {
ArrayList<Integer> test(int[] arr, int flag);
}
一、函数式接口编程思想以及如何演变为lambda
仔细看下面这个接口,它只有一个抽象方法,一般这样的可以直接通过lambda表达式来实现,因为lambda表达式的作用就是可以当做方法的参数进行传递,既然它是一个函数,那么就可以做逻辑实现,它可以当参数传递,在不同场景实现为一个接口的抽象方法,实现不同逻辑
package com.company;
import java.util.ArrayList;
public interface Test {
ArrayList<Integer> test(int[] arr, int flag);
}
package com.company;
import java.util.ArrayList;
/**
* 客户端
*/
public class Main{
public static void main(String[] args) {
int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12};
ArrayList<Integer> list = new ArrayList<>();
/**非接口编程思想,通常我们将逻辑封装到一个方法中,这里只做演示,就不单独写方法了*/
//获取数组中>5的元素
for (int i = 0;i < arr.length;i++){
if(arr[i]>5){
list.add(arr[i]);
}
}
System.out.println(list.toString());
list.clear();
//获取数组中<5的元素
for (int i = 0;i < arr.length;i++){
if(arr[i]<5){
list.add(arr[i]);
}
}
System.out.println(list.toString());
list.clear();
/**
* 可以看到上面的代码几乎重复,仅仅条件不一样,可维护和可优化的地方也不多
* 接下来介绍
* 接口式编程思想
*/
//匿名实现接口方法,传递数组,并传递flag,如果flag为1表示大于,为其它值表示小于
Test test = new Test() {
@Override
public ArrayList<Integer> test(int[] arr, int flag) {
ArrayList<Integer> returnList = new ArrayList<>();
for (int i = 0;i < arr.length;i++){
if(flag == 1? (arr[i]>5?true:false) : (arr[i]<5?true:false)){
returnList.add(arr[i]);
}
}
return returnList;
}
};
//获取数组中>5的元素
System.out.println(test.test(arr, 1).toString());
//获取数组中<5的元素
System.out.println(test.test(arr, 2).toString());
/**
* 可见上面接口式编程有了更好的可维护性和可优化性,还有很高的扩展性
*
* 但是依然有不足的地方
*
* 接下来介绍函数式思想,lambda表达式
*
* Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
*
* Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。&&&&&&&&&&&&&&&&&&重点作用
*
* 使用 Lambda 表达式可以使代码变的更加简洁紧凑。
*
*
* lambda 表达式的语法格式如下:
* parameters:参数,expression:表达式,statements:代码块
*
* (parameters) -> expression
* 或
* (parameters) ->{ statements; }
*
* // 1. 不需要参数,返回值为 5
* () -> 5
*
* // 2. 接收一个参数(数字类型),返回其2倍的值
* x -> 2 * x
*
* // 3. 接受2个参数(数字),并返回他们的差值
* (x, y) -> x – y
*
* // 4. 接收2个int型整数,返回他们的和
* (int x, int y) -> x + y
*
* // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
* (String s) -> System.out.print(s)
*/
Test test1 = (int[] e,int q)->{
ArrayList<Integer> returnList = new ArrayList<>();
for (int i = 0;i < e.length;i++){
if(q == 1? (e[i]>5?true:false) : (e[i]<5?true:false)){
returnList.add(e[i]);
}
}
return returnList;
};
//获取数组中>5的元素
System.out.println(test1.test(arr,1).toString());
//获取数组中<5的元素
System.out.println(test1.test(arr,2).toString());
/**
* 上面的例子只是帮助你们理解,lambda表达式真正方便之处,可以通过线程来体现
*/
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("我是通过匿名函数创建的Runnable接口实现");
}
}).start();
//可以明显看出,lambda表达式更加简洁,并具有函数式接口编程的思想
new Thread(()-> System.out.println("我是通过lambda创建的Runnable接口实现") ).start();
}
}
二、接收lambda表达式的多种方式
随便介绍2个,剩下的都是相同的道理
package com.company;
import java.util.ArrayList;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 客户端
*/
public class Main{
public static void main(String[] args) {
//接收lambda表达式的方式1,就是被函数式接口直接接收,此方式不限制输入和输出的数量,就是参数和返回值不限制
Runnable runnable = ()-> System.out.println("我是runnable接口");
runnable.run();
//方式2使用Function接收 Function<参数类型,返回值类型>,1输入,1输出,表示必须传一个参数,返回一个值
Function<String,Integer> f1 = (str)->{return str.length();};
Integer strLength = f1.apply("测试字符串");
System.out.println(strLength);
//方式3使用Supplier<返回值类型> ,0输入,1输出,不能传参,必须返回一个值
Supplier<String> supplier = ()->{return "你好";};
Supplier<String> supplier2 = ()->"你好111";//写法2,()->值;表示直接返回值
System.out.println(supplier.get()+supplier2.get());
//方式4,BiFunction<参数类型,参数类型,返回值类型>,2输入1输出
BiFunction<String,Integer,String> biFunction = (str,num)->str+num;
System.out.println(biFunction.apply("1234", 5));
}
}
三、方法的引用
package com.company;
import java.util.function.Supplier;
/**
* 客户端
*/
public class Main{
public Main(){
System.out.println("构造方法");
}
static String getString(){
return "aaaaaaaaa";
}
String getInst(){
return "实例方法";
}
public static void main(String[] args) {
//Supplier<返回类型> 1输出函数式接口,这是使用普通的lambda表达式
Supplier<String> supplier1 = ()->"字符串1";
System.out.println(supplier1.get());
//使用方法实现lambda
// Supplier<String> supplier2 = ()->getString(); 因为是在当前类的方法,可以直接通过方法名调用,一般不是在当前类,需要类名,也就是下面的用法
Supplier<String> supplier2 = ()->Main.getString();
System.out.println(supplier2.get());
/**静态方法引用,类名::静态方法,底层就是用lambda表达式实现对应(args)->类名.静态方法名(参数表)**/
supplier2 = Main::getString;
System.out.println(supplier2.get());
/**实例方法引用,实例名::实例方法,对应lambda为(args)->实例名.实例方法(args)**/
Main main = new Main();
supplier2 = main::getInst;
System.out.println(supplier2.get());
/**对象方法引用 类名::对象方法名 对应 (inst,args) -> 类名.对象方法(args) 和实例方法引用差不多
*
* 它可以使用任意对象的实例方法,比如String::compareToIgnoreCase
*
* 但是使用比较麻烦,也用的比较少,就不多做介绍了
* **/
/**构造方法引用 类名::new 对应 (args)->new 类名(args)**/
Supplier<Main> supplier3 = Main::new;
System.out.println(supplier3.get());
}
}