Lambda表达式
1.Lambda简介
Lambda表达式是JDK8的一个新特性,可以取代大部分的匿名内部类,写出更优雅的java代码,尤其在集合的遍历和其他集合操作中可以极大地优化代码结构。
JDK也提供了大量的内置函数式接口供我们使用,使得Lambda表达式的运用更加方便,高效。
2.对接口的要求
虽然使用Lambda表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用Lambda表达式来实现。Lambda规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法。
JDK8中有另一个新特性:default,被default修饰的方法会有默认实现,不是必须被实现的方法,所以不影响Lambda表达式的使用。
3.@FunctionalInterface
修饰函数式接口的,要求接口中的抽象方法只有一个。这个注解往往会和lambda表达式一起出现。
作用:验证当前接口是否只有一个需要被实现的方法,如果不满足,就编译报错。
所有它就是为lambda表达式而生的。
@FunctionalInterface
public interface MyInterface {
void a();
default void b(){
};
}
4.Lambda基础语法-准备工作
语法形式为() -> {},其中()用来描述参数列表,{}用来描述方法体,->为lambda运算符,读作(goes to)
package lambda;
public interface LambdaInterface {
}
/**
* 无返回无参数
*/
@FunctionalInterface
interface NoReturnNoParam{
void method();
}
/**
* 无返回有一个参数
*/
@FunctionalInterface
interface NoReturnOneParam{
void method(int a);
}
/**
* 无返回有多个参数
*/
@FunctionalInterface
interface NoReturnMultiParam{
void method(int a,int b);
}
/**
* 有返回无参数
*/
@FunctionalInterface
interface ReturnNoParam{
int method();
}
/**
* 有返回有一个参数
*/
@FunctionalInterface
interface ReturnOneParam{
int method(int a);
}
/**
* 有返回有多个参数
*/
@FunctionalInterface
interface ReturnMultiParam{
int method(int a,int b);
}
5.Lambda基本语法-测试
package lambda;
/**
* @author 葡萄
* 基础语法测试
*/
public class LambdaTest01 {
public static void main(String[] args) {
//无参无返回
NoReturnNoParam noReturnNoParam = () -> {
System.out.println("ok");
System.out.println("ok");
};
noReturnNoParam.method();
//一个参数无返回
NoReturnOneParam noReturnOneParam = (int a) -> {
System.out.println(a);
System.out.println(a);
};
noReturnOneParam.method(10);
//多个参数无返回
NoReturnMultiParam noReturnMultiParam = (int a,int b) -> {
System.out.println(a);
System.out.println(b);
};
noReturnMultiParam.method(10,20);
//无参有返回
ReturnNoParam returnNoParam = () -> {
System.out.println("ok");
return 110;
};
System.out.println(returnNoParam.method());
//一个参数有返回
ReturnOneParam returnOneParam = (int a) -> {
return a+1000;
};
System.out.println(returnOneParam.method(10));
//多个参数有返回
ReturnMultiParam returnMultiParam = (int a,int b) -> {
return a+b;
};
System.out.println(returnMultiParam.method(10,20));
}
}
6.Lambda基本语法-简化
package lambda;
/**
* @author 葡萄
* 基础语法测试-简化
*/
public class LambdaTest02 {
public static void main(String[] args) {
int num = 1000;
//1.简化参数类型,可以不写参数类型,但是必须所有参数都不写
NoReturnMultiParam noReturnMultiParam = (a,b) -> {
System.out.println(a+b);
};
//2.简化参数小括号,如果只有一个参数,则可以省略参数小括号
NoReturnOneParam noReturnOneParam = a -> {
System.out.println(a);
System.out.println(a);
};
//3.简化方法体大括号,如果方法体只有一条语句,则可以省略方法体大括号
NoReturnMultiParam noReturnMultiParam1 = (a,b) -> System.out.println(a+b);
//4.如果方法体只有一条语句,并且是return语句,则可以省略方法体大括号
ReturnMultiParam returnMultiParam = (a,b) -> a+b;
ReturnMultiParam returnMultiParam1 = (a,b) -> num;
ReturnMultiParam returnMultiParam3 = (a,b) -> num();
ReturnMultiParam returnMultiParam2 = new ReturnMultiParam() {
@Override
public int method(int a, int b) {
return num();
}
};
}
public static int num(){
return 10000;
}
}
7.Lambda表达式常用示例
7.1Lambda表达式引用方法
有时候我们不是必须要自己重写匿名内部类的方法,我们可以利用lambda表达式的接口快速指向一个已经被实现的方法。
- 语法:方法归属者::方法名 — 静态方法的归属者为类名,普通方法归属者为对象
- 静态方法
- 接口 对象名 = 类名::静态方法名;
- 成员对象
- 对象 对象名 = new 对象();
- 接口 接口对象名 = 对象名::成员方法;
- 要求:
- 1.参数数量和类型要和接口中定义的一致
- 2.返回值类型要与接口中定义的一致
package lambda;
/**
* @author 葡萄
* 基础语法测试-成员方法和静态方法的引用
*/
public class LambdaTest03 {
public static void main(String[] args) {
//使用有一个参数,并带有返回值
ReturnOneParam returnOneParam = a -> {
return a+100;
};
System.out.println(returnOneParam.method(100));
//使用有一个参数,并带有返回值
ReturnOneParam returnOneParam2 = a -> num();
System.out.println(returnOneParam2.method(100));
//使用有一个参数,并带有返回值 调用的某个类的静态方法
ReturnOneParam returnOneParam3 = LambdaTest03::numOne;
System.out.println(returnOneParam3.method(100));
//使用有一个参数,并带有返回值 调用的某个类的成员方法
LambdaTest03 lambdaTest03 = new LambdaTest03();
ReturnOneParam returnOneParam4 = lambdaTest03::two;
System.out.println(returnOneParam4.method(100));
System.out.println("-------------");
//不能调用静态方法
// LambdaTest03 lambdaTest04 = new LambdaTest03();
// LambdaTest03.num();
// ReturnOneParam returnOneParam5 = lambdaTest04::numOne;
// System.out.println(returnOneParam4.method(100));
}
/**
* 这是LambdaTest03里面的一个静态方法
* @return
*/
public static int num(){
return 10000;
}
/**
* 这是LambdaTest03里面的一个静态方法
* @return
*/
public static int numOne(int a){
return a+10000;
}
/**
* 这是LambdaTest03里面的一个成员方法
* @return
*/
public int two(int a){
return a+100000;
}
}
7.2构造方法的引用
一般我们需要声明接口,该接口作为对象的生成器,通过 类名::new 的方式来实例化对象,然后调用方法返回对象。
- 语法 ItemCreatorBlankConstruct construct2 = Item::new;
package lambda;
/**
* @author 葡萄
* 基础语法测试-构造方法的引用
*/
public class LambdaTest04 {
public static void main(String[] args) {
//使用无参构造方法来引用
ItemCreatorBlankConstruct construct = () -> new Item();
Item item1 = construct.getItem();
System.out.println(item1);
ItemCreatorBlankConstruct construct2 = Item::new;
Item item2 = construct2.getItem();
System.out.println(item2);
//有参的构造方法
ItemCreatorParamConstruct construct3 = Item::new;
Item item3 = construct3.getItem(1,"葡萄",100);
System.out.println(item3.name);
}
}
public class Item {
int id;
String name;
double price;
public Item(int id,String name,double price){
this.id = id;
this.name = name;
this.price = price;
}
public Item(){
}
}
interface ItemCreatorBlankConstruct{
Item getItem();
}
interface ItemCreatorParamConstruct{
Item getItem(int id,String name,double price);
}
7.3Lambda表达式创建线程
我们以往都是通过Thread对象,然后通过匿名内部类重写run()方法,一提到匿名内部类我们就应该想到可以使用lambda表达式来简化线程的创建过程。
package lambda;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author 葡萄
* 基础语法测试-创建线程对象
*/
public class LambdaTest05 {
public static void main(String[] args) {
//Runnable
new Thread(
new Runnable() {
@Override
public void run() {
System.out.println("ok");
}
}
).start();
new Thread(()-> System.out.println("ok")).start();
new Thread(()->{
System.out.println("ok");
System.out.println("ok");
}).start();
ExecutorService executorService = Executors.newCachedThreadPool();
//Runnable
executorService.submit(()->{
System.out.println("我是runnable的接口实现");
});
//Callable
executorService.submit(()->{
return "完成";
});
executorService.submit(()->"完成");
}
}
7.4Lambda遍历集合
我们可以调用集合的public void forEach(Consumer<? super E> action)方法,通过lambda表达式的方式遍历集合中的元素。以下是Consumer接口的方法以及遍历集合的操作。Consumer接口是jdk为我们提供的一个函数式接口。
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
//...
}
- Lambda遍历简单集合
package lambda;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author 葡萄
* 基础语法测试-遍历简单集合
*/
public class LambdaTest06 {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
// List<Integer> integerList = new ArrayList<>();
// integerList.add(1);
// integerList.add(2);
// integerList.add(3);
// integerList.add(4);
// integerList.add(5);
// integerList.add(6);
for (Integer integer : list) {
System.out.print(integer+"\t");
}
System.out.println();
System.out.println("------");
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i)+"\t");
}
System.out.println();
System.out.println("------");
//lambda的遍历
list.forEach((t)->{
System.out.print(t+"\t");
});
System.out.println();
System.out.println("------");
list.forEach(t->{
System.out.print(t+"\t");
});
System.out.println();
System.out.println("------");
list.forEach(t->System.out.print(t+"\t"));
System.out.println();
System.out.println("------");
list.forEach(System.out::print);
}
}
- Lambda遍历复杂集合
package lambda;
import java.util.ArrayList;
import java.util.List;
/**
* @author 葡萄
* 基础语法测试-遍历复杂集合
*/
public class LambdaTest07 {
public static void main(String[] args) {
List<Item> itemList = new ArrayList<>();
itemList.add(new Item(1,"饺子",10.00));
itemList.add(new Item(2,"汤圆",5.22));
itemList.add(new Item(3,"奶茶",20.56));
itemList.add(new Item(4,"布丁",22.33));
itemList.add(new Item(5,"芋圆",16.05));
//以前的遍历方法
for (int i = 0; i < itemList.size(); i++) {
System.out.println(itemList.get(i)+"\t");
}
for (Item item : itemList) {
System.out.println(item);
}
System.out.println("---------");
//使用lambda表达式遍历
itemList.forEach(item -> System.out.println(item));
System.out.println("---------");
itemList.forEach(item -> System.out.println(item.getName()));
System.out.println("---------");
itemList.forEach(System.out::println);
}
}
其中的Item类如下
package lambda;
public class Item {
int id;
String name;
double price;
public Item(int id,String name,double price){
this.id = id;
this.name = name;
this.price = price;
}
public Item(){
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Item{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
7.5删除集合中的某个元素
我们通过public boolean removeIf(Predicate<? super E> filter)方法来删除集合中的某个元素,Predicate也是jdk为我们提供的一个函数式接口,可以简化程序的编写。
package lambda;
import java.util.ArrayList;
import java.util.List;
/**
* @author 葡萄
* 基础语法测试-集合元素删除
*/
public class LambdaTest08 {
public static void main(String[] args) {
List<Item> itemList = new ArrayList<>();
itemList.add(new Item(1,"饺子",10.00));
itemList.add(new Item(2,"汤圆",5.22));
itemList.add(new Item(3,"奶茶",20.56));
itemList.add(new Item(4,"布丁",22.33));
itemList.add(new Item(5,"芋圆",16.05));
itemList.forEach(System.out::println);
System.out.println("---------");
//删除id=2的元素
for (Item item : itemList) {
if (item.getId()==2){
itemList.remove(item);
break;
}
}
itemList.forEach(System.out::println);
System.out.println("---------");
//使用lambda移除id=5
itemList.removeIf(item -> item.getId()==5);
itemList.forEach(System.out::println);
System.out.println("---------");
}
}
7.6集合内元素的排序
在以前我们若要为集合内的元素排序,就必须调用sort方法。传入比较器匿名内部类重写compare方法,我们现在可以使用lambda表达式来简化代码。
package lambda;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @author 葡萄
* 基础语法测试-集合元素排序
*/
public class LambdaTest09 {
public static void main(String[] args) {
List<Item> itemList = new ArrayList<>();
itemList.add(new Item(1,"饺子",10.00));
itemList.add(new Item(2,"汤圆",5.22));
itemList.add(new Item(3,"奶茶",20.56));
itemList.add(new Item(4,"布丁",22.33));
itemList.add(new Item(5,"芋圆",16.05));
itemList.forEach(System.out::println);
System.out.println("---------");
// Collections.sort(itemList, new Comparator<Item>() {
// @Override
// public int compare(Item o1, Item o2) {
// return (int) (o1.getPrice()- o2.getPrice());
// }
// });
// Collections.sort(itemList,(o1,o2)->{
// return (int) (o1.getPrice()- o2.getPrice());
// });
Collections.sort(itemList, (o1,o2)->(int) (o1.getPrice()- o2.getPrice()));
itemList.forEach(System.out::println);
System.out.println("---------");
}
}