未完待续。。。
概述
把函数作为参数传递进方法中,使用 Lambda 表达式可以使代码变的更加简洁紧凑。 lambda表达式的本质是匿名函数,比如以下函数:
public int add(int x, int y) {
return x + y;
}
可以转换为
(int x, int y) -> x + y;
语法
lambda表达式的语法格式如下:
(parameter1, parameter2,...) -> expression
或
(parameter1, parameter2,...) ->{statements; }
使用注意
- 参数类型不是必须(可以推导出),如:
- Comparator<String> cmp = (first, second) -> first.length() - second.length();
- 无参数时,()不可缺省,如:
- () -> {for (int i = 0; i < 10; i++) System.out.print(i);}
- 参数圆括号不是必须:一个参数无需定义圆括号;多个参数需要定义圆括号
- 大括号不是必须:如果主体仅有一个语句,就不需要使用大括号
- 返回关键字不是必须:如果主体只有一个表达式返回值,编译器会自动返回。大括号需要指定表达式返回了一个数值。
- 不能只在某一个分支返回一个值,如:
- (int x)->{if(x>=0)return 1;}
简单例子
// 不需要参数,返回值为5
() -> 5;
使用场景
Lambda表达式的应用非常广泛,它可以用于简化代码、实现函数式编程、处理集合、处理事件、并发编程等多个方面。根据不同的场景和需求,可以选择合适的函数式接口和Lambda表达式来实现相应的功能。
匿名内部
后面要用到,这里简单解释一下。
在方法中,如果需要使用一个未创建的类的实例对象,则可以直接通过new 父类,并重写父类中方法的形式,创建一个匿名类的实例对象,这样可以使得代码更简洁。
匿名类通常是继承父类或者实现一个接口。下图是语法格式:
(图来自:菜鸟教程:Java匿名类)
替代匿名内部类(实现函数式编程)
lambda表达式通常是结合函数式接口(有且只有一个抽象方法,但可以有多个非抽象方法的接口)一起使用。
如果某个方法A的传参是函数式接口类型,则可使用lamda表达式重写函数式接口中抽象方法的具体逻辑,直接传入方法A。详情见下面的例子。
Runnable接口
Thread类的构造方法,传入的参数类型是Runnable接口类型,则可在直接将lambda表达式传入new Thread方法中。
public class RunnableLambda {
// 结合Runnable使用匿名内部类
public void runnableAnonymous() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("the runnable now is using!");
}
});
thread.start();
}
// 结合Runnable使用匿名内部类2
public void runnableAnonymous2() {
//先创建好匿名内部类的实例对象,再将对象传入new Thread()方法
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("the runnable now is using!");
}
};
Thread thread = new Thread(runnable);
thread.start();
}
// 结合Runnable使用lambda表达式,直接将run方法的代码逻辑写出来传进去即可。
// 因为new Runnable()构造方法不需要传入参数,所以lambda格式使用() -> {statement}
public void runnableLambda(){
Thread thread = new Thread(() -> System.out.println("it's a lambda function"));
thread.start();
}
}
Comparator接口
是一个函数式接口,用于定义对象的比较规则
public class ComparatorLambda {
// 使用匿名内部类
public void comparatorLambda(){
List<Integer> strings = Arrays.asList(1, 2, 3);
Collections.sort(strings, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
}
//使用lambda表达式
public void comparatorLambda2(){
List<Integer> strings = Arrays.asList(1, 2, 3);
Collections.sort(strings, (Integer o1, Integer o2) -> o1 - o2);
// 或者如下形式
strings.sort((o1, o2) -> o1 - o2);
}
// 使用外部类
public void comparatorLambda3() {
List<Integer> list = Arrays.asList(1, 2, 3);
Collections.sort(list, new Comparator2());
}
}
class Comparator2 implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
}
实际使用场景可以参考算法题(见提交记录):BM89合并区间
Predicate接口
用于表示一个断言(条件),通常用于过滤集合中的元素。
以下示例,使用Lambda表达式作为filter方法的参数(filter方法的传入参数是Predicate<? super T> predicate,可以看下源码),筛选出以“A”开头的姓名。
public class PredicateLambda {
//使用匿名内部类
public List<String> predicateAnonymous() {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
List<String> result = names.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("A");
}
}).collect(Collectors.toList());
return result;
}
//使用lambda表达式
public List<String> predicateLambda() {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
List<String> result = names.stream().filter(name -> name.startsWith("A")).collect(Collectors.toList());
return result;
}
public static void main(String[] args) {
List<String> res = new PredicateLambda().predicateAnonymous();
res.forEach(name -> System.out.println(name));
}
}
Consumer接口
java.util.function.Consumer是一个函数式接口,用于表示接受一个输入并没有返回值的操作。通常用于遍历集合,并对每个元素执行某种操作。
public class ConsumerLambda {
//使用匿名内部类
public void consumerAnonymous() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer number) {
System.out.println(number);
}
});
}
//使用lambda表达式
public void consumerLambda() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.forEach(number -> System.out.println("Number: " + number));
}
public static void main(String[] args) {
new ConsumerLambda().consumerAnonymous();
new ConsumerLambda().consumerLambda();
}
}
Function接口
用于表示接受一个输入,并产生一个输出的函数
以下示例为:使用Lambda表达式作为map方法的参数,将整数列表中的每个元素平方,并将结果收集到新的列表中。
public class FunctionLambda {
//使用匿名内部类
public List<Integer> functionAnonymous() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> squaredNumbers = (List<Integer>) numbers.stream().map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer number) {
return number * number;
}
}).collect(Collectors.toList());
return squaredNumbers;
}
//使用lambda表达式
public List<Integer> functionLambda() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// map方法的传参是Function类型
List<Integer> squaredNumbers = numbers.stream().map(number -> number * number).collect(Collectors.toList());
return squaredNumbers;
}
// 调用
public static void main(String[] args) {
List<Integer> res = new FunctionLambda().functionAnonymous();
res.forEach(num -> System.out.println(num));
}
}
Supplier接口
用于表示一个供应商,通常用于延迟计算或提供默认值。
简单示例
public class SupplierLambda {
//使用匿名内部类
public int supplierAnonymous() {
Supplier<Integer> randomSupplier = new Supplier<Integer>() {
@Override
public Integer get() {
return new Random().nextInt(100);
}
};
return randomSupplier.get();
}
// 使用lambda表达式
public int supplierLambda() {
Supplier<Integer> randomSupplier = () -> new Random().nextInt(100);
int randomNumber = randomSupplier.get();
return randomNumber;
}
public static void main(String[] args) {
int res = new SupplierLambda().supplierAnonymous();
System.out.println(res);
}
}
某个方法的传参是Supplier接口类型
CompletableFuture.supplyAsync方法的传参是Supplier接口类型
public class CompletableFutureLambda {
// 先创建好匿名内部类的实例对象,supplier,再传入CompletableFuture.supplyAsync方法
public void supplierAnonymous() throws InterruptedException, TimeoutException, ExecutionException {
UserInfoService userInfoService = new UserInfoService();
long userId = 666L;
Supplier supplier = new Supplier() {
@Override
public Object get() {
return userInfoService.getUserInfo(userId);
}
};
CompletableFuture<UserInfo> userInfoCompletableFuture = CompletableFuture.supplyAsync(supplier);
UserInfo userInfo = userInfoCompletableFuture.get(2, TimeUnit.SECONDS);
System.out.println(userInfo.getAge());
}
// 直接在CompletableFuture.supplyAsync方法中new匿名内部类的实例对象
public void supplierAnonymous2() throws InterruptedException, TimeoutException, ExecutionException {
UserInfoService userInfoService = new UserInfoService();
long userId = 666L;
CompletableFuture<UserInfo> userInfoCompletableFuture = CompletableFuture.supplyAsync(new Supplier<UserInfo>() {
@Override
public UserInfo get() {
return userInfoService.getUserInfo(userId);
}
});
UserInfo userInfo = userInfoCompletableFuture.get(2, TimeUnit.SECONDS);
System.out.println(userInfo.getAge());
}
public void supplierLambda() throws InterruptedException, TimeoutException, ExecutionException {
UserInfoService userInfoService = new UserInfoService();
long userId = 666L;
CompletableFuture<UserInfo> userInfoCompletableFuture =
CompletableFuture.supplyAsync(() -> userInfoService.getUserInfo(userId));
UserInfo userInfo = userInfoCompletableFuture.get(2, TimeUnit.SECONDS);
System.out.println(userInfo.getAge());
}
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException {
CompletableFutureLambda completableFutureLambda = new CompletableFutureLambda();
completableFutureLambda.supplierLambda();
}
}
Listener接口
public class ListenerLambda {
//使用匿名内部类
public void listenerAnonymous() {
JButton button = new JButton();
button.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
e.getItem();
}
});
}
//使用lambda表达式
public void listenerLambda() {
JButton button = new JButton();
button.addItemListener(e -> e.getItem());
}
}
自定义函数式接口
// 接口定义
@FunctionalInterface
public interface IntBinaryOperator {
int apply(int a, int b);
}
// 使用
public class IntBinaryOperatorLambda {
public int binaryOperatorLambda() {
IntBinaryOperator add = (a, b) -> a + b;
int result = add.apply(3, 5);
return result;
}
public static void main(String[] args) {
int res = new IntBinaryOperatorLambda().binaryOperatorLambda();
System.out.println(res);
}
}
集合迭代
public class CollectionLambda {
//使用匿名内部类
public void collectionAnonymous() {
List<String> list = Arrays.asList("123","456");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
}
//使用lambda表达式
public void collectionLambda() {
ArrayList<String> list = new ArrayList<>(Arrays.asList("i", "live"));
list.forEach(s -> System.out.println(s));
}
}
方法引用
诸如String::length的语法形式叫做方法引用(method references),这种语法用来替代某些特定形式Lambda表达式。如果Lambda表达式的全部内容就是调用一个已有的方法,那么可以用方法引用来替代Lambda表达式。方法引用可以细分为四类:
| 方法引用类别 | 举例 |
|---|---|
| 引用静态方法 | Integer::sum |
| 引用某个对象的方法 | list::add |
| 引用某个类的方法 | String::length |
| 引用构造方法 | HashMap::new |
实例1:
// 函数式接口
@FunctionalInterface
public interface LambdaInterface {
void f();
}
// 父类
public class ReferenceLambdaSuper {
LambdaInterface sf() {
return null;
}
}
//子类
public class ReferenceLambda extends ReferenceLambdaSuper {
public static LambdaInterface staticF(){
return null;
}
public LambdaInterface f() {
return null;
}
void show() {
//调用静态方法,返回值必须是函数式接口?(不一定吧)
LambdaInterface f = ReferenceLambda::staticF;
//实例方法调用
ReferenceLambda referenceLambda = new ReferenceLambda();
LambdaInterface lambdaInterface = referenceLambda::f;
//调用父类方法
LambdaInterface superf = super::sf;
//构造方法调用
LambdaInterface tt = ReferenceLambdaSuper::new;
}
}
实例2:
public class User {
private int age;
public int getAge(){
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
Function<User, Integer> userIntegerFunction = o -> o.getAge();
Function<User, Integer> userIntegerFunction1 = User::getAge;
// 报错:int is not a functional interface
int a = User::getAge;
}
}
实例3:
/**
* @author lx
*/
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void print() {
System.out.println("静态方法");
}
public static Person instance() {
return new Person();
}
public Integer gett(Object str, Integer integer) {
setAge(integer);
return getAge();
}
public Integer gett(int integer, Object str) {
setAge(integer);
return getAge();
}
@Test
public void test() {
//一个user实例
Person user = new Person();
//类型上的实例方法引用:ClassName::methodName
Function<Person, Integer> userIntegerFunction2 = Person::getAge;
//类型上的实例方法引用:ClassName::methodName
Consumer<Person> userConsumer2 = System.out::println;
//实例上的实例方法引用:instanceReference::methodName
Supplier<Integer> supplier = user::getAge;
//类型上的静态方法引用:ClassName::methodName
Supplier<Person> userSupplier = Person::instance;
//类型上的静态方法引用:ClassName::methodName
Print print = Person::print;
//超类实例上的实例方法引用:super::methodName
Supplier<Class> SupSupplier = super::getClass;
//构造方法引用:ClassName::new
Supplier<Object> newSupplier = Person::new;
//数组构造方法引用:TypeClassName[]::new
Function<Integer, Person[]> arrayFunction = Person[]::new;
//如果内部调用gett(String str, Object integer)方法
ThFunction<Person, Integer, Integer, String> thFunction1 = new ThFunction<Person, Integer, Integer, String>() {
@Override
public Integer apply(Person o, Integer o2, String o3) {
return o.gett(o3, o2);
}
};
//那么不能使用方法引用
//因为虽然抽象方法的第一个参数就是内部调用该方法的实例,后面的参数和方法参数的顺序不一致
//参数顺序不一致,即 o2 o3 -> o3 o2
ThFunction<Person, Integer, Integer, String> thFunction2 = (o, o2, o3) -> o.gett(o3, o2);
//如果内部调用gett(Integer integer, Object str)方法
ThFunction<Person, Integer, Integer, String> thFunction3 = new ThFunction<Person, Integer, Integer, String>() {
@Override
public Integer apply(Person o, Integer o2, String o3) {
return o.gett(o2, o3);
}
};
//那么能使用方法引用
//因为抽象方法的第一个参数就是内部调用该方法的实例,后面的参数和方法参数的顺序一致,类型兼容
//参数顺序一致,即 o2 o3 -> o2 o3
ThFunction<Person, Integer, Integer, String> thFunction4 = Person::gett;
}
/**
* 自定义函数式接口,无参数无返回值
*/
@FunctionalInterface
public interface Print {
/**
* 输出
*/
void print();
}
@FunctionalInterface
public interface ThFunction<T, U, R, K> {
R apply(T t, U u, K k);
}
}
变量作用域
处理lambda表达式
参考文章: