lambda表达式
[原文地址为]https://www.cnblogs.com/haixiang/p/11029639.html#791844013
定义
lambda表达式是jdk1.8后新增的特性,它可以取代大部分匿名内部类,简化Java代码结构。
lambda表达式是基于函数式接口使用的。
什么是函数式接口?
函数式接口是指只含有一个必须被重写的方法的接口。
(注:只有一个必须重写的方法,并不是指只有一个方法,jdk1.8后接口中允许有已经实现的方法(必须被public static修饰),jdk1.8后也允许有非必须重写的抽象方法(须被default修饰))
@FunctionalInterface
函数式接口又称为功能性接口,故一般函数式接口都用@FunctionalInterface注解进行修饰。
(不使用该注解,jvm虚拟机也可判断出该接口是一个函数式接口,但为了防止其他同事在该接口中新增方法,最好使用注解注明)
lambda基础语法
lambda基础语法一般是基于以下6种函数式接口
//1.无返回无参数函数式接口
@FunctionalInterface
public interface noReturnNOParam{
void method();
}
//2.无返回一参数函数式接口
public interface noReturnOneParam{
void method(int a);
}
//3.无返回多参数函数式接口
public interface noReturnMultiParam{
void method(int a,int b);
}
//4.有返回无参数函数式接口
public interface ReturnNoParam{
String method();
}
//5.有返回一参数函数式接口
public interface ReturnOneParam{
String method(int a);
}
//6.有返回多参数函数式接口
public interface ReturnMultiParam{
String method(int a,int b);
}
lambda表达式的基础语法为()->{},其中()中保存参数列表,->是lambda表达式的执行符,读作goes to,{}中保存方法体。
关于lambda表达式,这里有一句口诀:
上联:左右遇一括号省
下联:左边类推类型省
横批:能省则省
解释
左右遇一括号省
左指的是若只有一个参数,则左边参数的括号可省略不写。
右指的是若方法体中只有一条Java语句,则右边的括号也可省略不写。
左边类推类型省:
jvm虚拟机的类推机制,可通过方法体中的语句,联系上下文推测出参数列表的类型,因此左边的参数类型可省略不写。
针对上述接口及口诀,下方有几个例子
public class testLambda(){
public static void main(String args[]){
//1.无返回,无参数值
noReturnNOParam emp1=()->{
System.out.println("无返回无参数值");
};
emp1.method();//这里的method是上述函数式接口中定义的方法名
//使用口诀简化版
noReturnNoParam emp1=()-> System.out.println("无返回无参数值");
emp1.method();
//注意这边参数为0个,所以左边括号不能省
//============================================================
//2.无返回,一参数值
noReturnOneParam emp2=(String a)->{
System.out.println("无返回,一参数值"+a);
};
emp2.method("11111");
//简化版
noReturnOneParam emp2=a->
System.out.println("无返回,一参数值"+a);
emp2.method("11111");
//=============================================================
//3.无返回,多参数值
noReturnMultiParam emp3=(int a,int b)->{
System.out.println("无返回,一参数值"+(a+b));
};
emp3.method(1,2);
//简化版
noReturnMultiParam emp3=(a,b)->System.out.println("无返回,多参数值"+(a+b));
emp3.method(1,2);
//======================================================================
//4.有返回,无参数值
ReturnNOParam emp4=()->{
return "无返回无参数值";
};
String return1=emp4.method();//这里的method是上述函数式接口中定义的方法名
//使用口诀简化版
noReturnNoParam emp1=()-> return "无返回无参数值";
String return1=emp4.method();
//注意这边参数为0个,所以左边括号不能省
//============================================================
//5.有返回,一参数值
ReturnOneParam emp5=(String a)->{
return "有返回,一参数值"+a;
};
String return2=emp5.method("11111");
//简化版
ReturnOneParam emp5=a->
return "无返回,一参数值"+a;
String return2=emp5.method("11111");
//=============================================================
//6.无返回,多参数值
ReturnMultiParam emp6=(int a,int b)->{
return "无返回,一参数值"+(a+b);
};
String return3=emp6.method(1,2);
//简化版
ReturnMultiParam emp6=(a,b)->return "无返回,多参数值"+(a+b);
String return3=emp6.method(1,2);
}
}
Lambda表达式常用方法示例
lambda表达式引用方法
可以利用lambda表达式的接口直接指向一个已经实现的方法
要求:
1.这个方法的参数类型及个数要与函数式接口中的方法一致
2.这个方法的返回值类型要与函数式接口中的方法一致
语法:
方法名::方法的归属者,静态方法的归属者为类名,普通方法的归属者为对象
举例:
public class lambdaUse1{
public static void main(String args[]){
ReturnMultiParam return1=fangfa1::lambdaUse1;
return1.method(1,2);
}
public static String fangfa1(int a,int b){
int c=a+b;
return "lambda表达式的用法1"+c;
}
}
//就相当于用引用的方法重写了原接口中的方法,就是lambda表达式中的goes to到引用方法的方法体中
构造方法的引用
若一个函数式接口中的方法,是一个类的构造方法,则可通过lambda表达式来创建该类的对象,
语法:类名::new
//无参构造
public Interface ItemCreaterConstruct(){
Item getItem();
}
//含参构造
public Interface ItemParamCreaterConstruct(){
Item getItem(int id,String name,double price);
}
public class emp(){
public static void main(String args[]){
//无参构造,使用lambda表达式创建对象
ItemCreaterConstruct construct=()->new Item();
Item item=construct.getItem();
//无参构造,使用lambda表达式的另一种写法创建对象
ItemCreaterConstruct construct=Item::new;
Item item=construct.getItem();
//含参构造,使用lambda表达式创建对象
ItemCreaterConstruct construct=Item::new;
Item item=construct.getItem(1,"aaa",1.1);
}
}
lambda表达式创建线程
我们以往创建线程都是通过继承Thread后重写run方法,通过lambda表达式可以简化线程的创建过程
//这里是通过Thread的一个构造方法
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
//来创建线程
//Runnable接口中只有一个run方法,则可通过lambda表达式来代替构造方法中的Runnable
Thread t=new Thread(()->{
for(int i=0;i<10;i++){
System.out.println(i)
}
});
t.start();
遍历集合
我们可以调用集合中的public void forEach(Consumer <? Super E> action)方法,通过lambda表达式的方式遍历集合中的元素。
Consumer是JDK给我们提供的一个函数式接口。
@FunctionalInterface
public interface Consumer<T>{
void acctept(T t);
}
List list=new ArraysList();
list.forEach(element->{
if(element.get(i)%2==0){
System.out.println(""+element);
}
});
删除集合中的元素
我们可以通过public boolean removeIf(Predicate<? super E> filter)方法来删除集合中的某个元素,Predicate也是JDK提供的一个函数式接口。
ArrayList<Item> items = new ArrayList<>();
items.add(new Item(11, "小牙刷", 12.05 ));
items.add(new Item(5, "日本马桶盖", 999.05 ));
items.add(new Item(7, "格力空调", 888.88 ));
items.add(new Item(17, "肥皂", 2.00 ));
items.add(new Item(9, "冰箱", 4200.00 ));
items.removeIf(ele -> ele.getId() == 7);
//通过 foreach 遍历,查看是否已经删除
items.forEach(System.out::println);
集合内元素的排序
在以前我们要为集合内的元素进行排序,就必须要用sort方法,传入比较器匿名内部类重写Compare方法,我们现在可以使用lambda表达式来简化代码
ArrayList<Item> list = new ArrayList<>();
list.add(new Item(13, "背心", 7.80));
list.add(new Item(11, "半袖", 37.80));
list.add(new Item(14, "风衣", 139.80));
list.add(new Item(12, "秋裤", 55.33));
/*
list.sort(new Comparator<Item>() {
@Override
public int compare(Item o1, Item o2) {
return o1.getId() - o2.getId();
}
});
*/
list.sort((o1, o2) -> o1.getId() - o2.getId());
System.out.println(list);
lambda表达式的闭包问题
这个问题在匿名内部类也存在,若我们放开注释则会报错,这里num我们虽然没有添加final注释,但是虚拟机在编译时会自动给其添加一个final修饰关键字。
import java.util.function.Consumer;
public class Main {
public static void main(String[] args) {
int num = 10;
Consumer<String> consumer = ele -> {
System.out.println(num);
};
//num = num + 2;
consumer.accept("hello");
}
}