1.Lambda表达式简介
Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构。
JDK 也提供了大量的内置函数式接口(接口中只有一个方法)供我们使用,使得 Lambda 表达式的运用更加方便、高效。
@FunctionalInterface //标识此接口是一个函数式接口
public interface Runnable {
/
When an object implementing interface Runnable
is used
to create a thread, starting the thread causes the object’s
run
method to be called in that separately executing
thread.
The general contract of the method run
is that it may
take any action whatsoever.
@see java.lang.Thread#run()
/
public abstract void run();
}
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
闭包 :把一个方法作为参数传递给另外一个方法 (一个方法可以使用另一个方法的局部变量)**
2. Lamda表达式在操作接口的要求
Lambda 表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用 Lambda 表达式来实现。Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法
jdk 8 中有另一个新特性:default, 被 default 修饰的方法会有默认实现,不是必须被实现的方法,所以不影响 Lambda 表达式的使用
@FunctionalInterface : 函数式接口 ,该注解只能标记在”有且仅有一个抽象方法“的接口上,这个注解往往会和 lambda 表达式一起出现
接口中只有一个方法需要被必须实现的接口 ,可以使用Lamda表达式
3.Lambda 基础语法
通过以下六个接口,讲解Lambda表达式的语法:
/*无参无返回值/
@FunctionalInterface
public interface NoReturnNoParam {
void method();
}
/*多参数无返回/
@FunctionalInterface
public interface NoReturnMultiParam {
void method(int a, int b);
}
/*一个参数无返回/
@FunctionalInterface
public interface NoReturnOneParam {
void method(int a);
}
/*多个参数有返回值/
@FunctionalInterface
public interface ReturnMultiParam {
int method(int a, int b);
}
/** 无参有返回/
@FunctionalInterface
public interface ReturnNoParam {
int method();
}
/*一个参数有返回值/
@FunctionalInterface
public interface ReturnOneParam {
int method(int a);
}
语法形式为 () -> {},其中 () 用来描述参数列表,{} 用来描述方法体,-> 为 lambda运算符 ,读作(goes to)。
下面看一下使用Lamda表达式实现上述六个接口 :
public class TestLamda {
public static void main(String[] args) {
/
() : 接口中方法的参数
-> : 指向接口的实现
{ }: 接口中抽象方法的实现
/
NoReturnNoParam nrnp = ()->{
System.out.println(“我是iLamda表达式实现的方法。。。”);
} ;
nrnp.method();
NoReturnMultiParam nrmp = (int a,int b)->{
int c = a + b ;
System.out.println(c);
} ;
nrmp.method(10, 20);
NoReturnOneParam nrop = (int a)->{
System.out.println(a + 100);
};
nrop.method(10);
ReturnMultiParam rmp = (int a,int b)->{
return a b ;
};
int x = rmp.method(3, 5);
System.out.println(x);
ReturnNoParam rnp = ()->{
return 100;
};
int y = rnp.method();
System.out.println(y);
ReturnOneParam rop = (int a)->{
return a + 3;
};
int z = rop.method(10);
System.out.println(z);
}
}
针对Lamda表达式的简化:
public class TestLamda {
public static void main(String[] args) {
//如果接口方法的实现 只有 一行代码 花括弧可以省略
NoReturnNoParam nrnp = ()-> System.out.println(“AAAAAAAAA”);
nrnp.method();
//如果 说 有返回值的 方法的实现也是只有一行代码 也可以上略 花括弧 而且还可以省略 return
ReturnNoParam rnp = ()-> 125%24 ;
int method = rnp.method();
System.out.println(method);
//参数可以省略 类型 如果是多个参数 要省略 就全部省略
ReturnMultiParam rmp = (x,y) ->{
return x*y ;
};
int a = rmp.method(10, 20);
System.out.println(a);
//如果说只有一个 参数 可以省略 类型 和 花括弧的
NoReturnOneParam nrop = m->{
System.out.println(m);
};
}
}
4.Lambda表达式引用方法 (了解)
使用Lamda表达式实现接口的抽象方法时 ,可以不去实现 ,而是使用已经存在的一个方法 ,直接交给抽象方法
public class Exe1 {
public static void main(String[] args) {
//使用Lamda表达式 实现
// ReturnOneParam rop = a -> a2;
// int method = rop.method(100);
// System.out.println(method);
/ReturnOneParam rop = a-> doubleNum(a);
int method = rop.method(5);
System.out.println(method);
/
/**
也可以使用 此种方式 给一个函数式接口 赋值一个静态方法
类型 :: 方法名
/
/ReturnOneParam rop = Exe1::doubleNum;
int method = rop.method(100);
System.out.println(method);/
/
也可以使用一个实例方法 给函数式接口中的方法 实现
必须使用对象 操作方法
语法 : 对象 ::方法名
/
Exe1 e = new Exe1();
ReturnOneParam rop = e::addTwo;
int method = rop.method(100);
System.out.println(method); //102
}
/
要求
1.参数数量和类型要与接口中定义的一致
2.返回值类型要与接口中定义的一致
/
public static int doubleNum(int a) {
return a * 2;
}
public int addTwo(int a) {<br /> return a + 2;<br /> }<br />}
5.构造方法引用(了解)
一般我们需要声明接口,该接口作为对象的生成器,通过 类名::new 的方式来实例化对象,然后调用方法返回对象
public class Exe2 {
public static void main(String[] args) {
/
Lamda表达式的普通用法 new Item();的结果 作为 接口中的返回值
/
ItemCreatorBlankConstruct icbc = ()-> new Item();
//使用Item中的 new 构造方法 创建 接口的方法的返回值
ItemCreatorBlankConstruct icbc1 = Item::new ;
Item item = icbc1.getItem();
/
这个语法 Item对象中 必须有对用的构造方法 才可以使用
/
ItemCreatorParamContruct icpc = Item::new ;
Item item2 = icpc.getItem(1, “手机”, 2000);
}
}
6.Lamda表达式实现线程
public class TestLamdaAndThread {
public static void main(String[] args) {
Runnable r1 = ()->{
for(int i=0;i<100;i++){
System.out.println(i);
}
};
Runnable r2 = ()->{
for(int i=65;i<=122;i++){
System.out.println((char)i);
}
};
Thread t1 = new Thread(r1,”数字”);
Thread t2 = new Thread(r2,”字符”);
t1.start();
t2.start();
}
}
7、Lamda表达式对集合的遍历
public class TestCollection {
public static void main(String[] args) {
List
lists.add(“张三丰”);
lists.add(“张五级”);
lists.add(“张四风”);
lists.add(“张无缝”);
lists.add(“谢逊”);
lists.add(“带一丝”);
//普通的遍历
lists.forEach(System.out::println);
System.out.println(“-=======”);
//遍历 2
lists.forEach(e->{
if(e.startsWith(“张”)){
System.out.println(e);
}
});
}
}
8.Lamda表达式删除集合中的数据
我们通过public boolean removeIf(Predicate<? super E> filter)方法来删除集合中的某个元素,Predicate 也是 jdk 为我们提供的一个函数式接口,可以简化程序的编写。
public class TestCollection2 {
public static void main(String[] args) {
List
lists.add(2);
lists.add(3);
lists.add(4);
lists.add(2);
lists.add(2);
lists.add(2);
System.out.println(lists.size());
//利用Lamda表达式 判断删除集合中的元素
lists.removeIf(e-> e==2);
lists.forEach(System.out::println);
}
}
9 .集合内元素的排序
在以前我们若要为集合内的元素排序,就必须调用 sort 方法,传入比较器匿名内部类重写 compare 方法,我们现在可以使用 lambda 表达式来简化代码。
因为比较器 接口 也是一个函数式接口 :
public class TestCollection3 {
public static void main(String[] args) {
List
lists.add(new Item(1, “手机”, 2000));
lists.add(new Item(2, “相机”, 5000));
lists.add(new Item(3, “洗衣机”, 3000));
lists.add(new Item(4, “冰箱”, 4000));
lists.add(new Item(5, “Ipad”, 1000));
lists.add(new Item(6, “电脑”, 9000));
//对商品排序 根据价格
/lists.sort(new Comparator
@Override
public int compare(Item o1, Item o2) {
if(o1.getPrice() - o2.getPrice() >0){
return 1;
}else if(o1.getPrice() - o2.getPrice() <0){
return -1;
}
return 0;
}
});
//使用Lamda表达式 实现函数式接口
lists.sort((o1,o2)->{
if(o1.getPrice() - o2.getPrice() >0){
return -1;
}else if(o1.getPrice() - o2.getPrice() <0){
return 1;
}
return 0;
});
lists.forEach(e -> System.out.println(e));
}
}
10 .Lambda表达式中的闭包问题
这个问题我们在匿名内部类中也会存在,如果我们把注释放开会报错,告诉我 num 值是 final 不能被改变。这里我们虽然没有标识 num 类型为 final,但是在编译期间虚拟机会帮我们加上 final 修饰关键字
在内部类中使用外部的局部变量 ,那么这个变量必须是final类型 ,不能被改变
public class Test {
public static void main(String[] args) {
int num = 10;
Consumer<String> consumer = ele -> {<br /> //在这里使用了num 那么上面的num变量一定是 final 虚拟机自动加的<br /> System.out.println(num); //1 <br /> };
// num = num + 2; //2 <br /> consumer.accept("hello");<br /> <br /> // 1 和 2 指示的代码是 互斥的 <br /> }<br />}