为什么使用 Lambda 表达式?
Lambda 是一个匿名函数,可以理解是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更加简洁、灵活的代码。作为一种更紧凑的代码风格,使 Java 的语言表达能力得到了提升。
import org.junit.Test;
import java.util.Comparator;
import java.util.TreeSet;
public class TestLembda {
// 原来的匿名内部类
@Test
public void test1 () {
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
TreeSet<Integer> treeSet = new TreeSet<>(comparator);
}
// Lambda 表达式
@Test
public void test2 () {
Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);
TreeSet<Integer> treeSet = new TreeSet<>(comparator);
}
}
一、Lambda 表达式基础语法
Java 8 中引入了一个新的操作符 “ ->” 该操作符称为箭头操作符或 Lambda 操作符,箭头操作符将 Lambda 拆分成两部分
左侧:Lambda 表达式的参数列表,对应接口中抽象方法的参数列表
右侧:Lambda 表达式所需要执行的功能,即 Lambda 体,对抽象方法的实现
语法格式格式一:方法无参数无返回值
()-> System.out.println("Hello, Lambda!");
@Test
public void test1 () {
int num = 0; // 局部内部类使用的变量再 jdk 1.7 之前必须是 final,现在依然是 final 只是可以省略
// final 的变量不允许修改
Runnable runnable = new Runnable() {
@Override
public void run() {
// 内部类使用的变量
System.out.println("Hello, world!" + num);
}
};
runnable.run();
// num++;
System.out.println("---------------------------------------");
Runnable runnable1 = () -> System.out.println("Hello, world!");
runnable1.run();
}
语法格式二:有一个参数并且无返回值
@Test
public void test2 () {
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("Hello, world!");
}
语法格式三:只有一个参数,小括号可以省略
语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
多条语句一定要在一对大括号内
@Test
public void test3 () {
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
}
语法格式五:有两个以上的参数,有返回值,若 Lambda 体中只有一条语句
返回值和大括号都可以省略
语法格式六:
Lambda 表达式的参数列表的数据类型可以忽略不写,因为 JVM 编译器通过上下文推断出数据类型,即 “类型推断”。根据接口中定义的数据类型,当然了如果是泛型,根据指定的 T 来推断。
函数式接口:接口中只有一个抽象方法的接口(多了没法直接映射过去),可以使用 @FunctionalInterface 修饰,用来检查是否是函数式接口。
public interface MyCalculate<T, R> {
public R compute(T t1, T t2);
}
// 调用 Collections.sort() 方法,通过定制排序比较两个 Employee (先按照年龄比,年龄相同按照姓名比)
// 使用 Lambda 作为参数传递
@Test
public void test() {
List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 99999.99),
new Employee("李四", 50, 2222.22),
new Employee("王五", 16, 666.66),
new Employee("赵六", 16, 666.66),
new Employee("钱六", 15, 3333.33));
Comparator<Employee> comparator = (e1, e2) -> {
if (e1.getAge().equals(e2.getAge())) {
return e1.getName().compareTo(e2.getName());
} else {
return Integer.compare(e1.getAge(), e2.getAge());
}
};
// 自定义排序,前一个是 List 集合,后一个是自定义的排序方法
Collections.sort(employees, comparator);
for (Employee employee : employees) {
System.out.println(employee);
}
}
// 声明函数式接口,接口中声明抽象方法,public String getValue(String str)
// 声明类 TestLambda,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值
// 再将一个字符串的第 2 个和第 4 个索引位置进行截取子串
@Test
public void test2() {
String str = "abcdefghijk";
System.out.println(handleStr(str, (s) -> s.toUpperCase()));
System.out.println("----------------------------------");
System.out.println(handleStr(str, (s) -> s.substring(2, 4)));
}
public String handleStr(String str, HandleString handleString) {
return handleString.getValue(str);
}
// 声明一个带两个反省的函数式接口,泛型类型为 T 为参数,R 为返回值
// 接口中声明对应的抽象方法
// 再 TestLambda 类中声明方法,使用接口作为参数,计算两个 long 类型参数的和
// 再计算两个 long 类型的乘积
@Test
public void test3 () {
System.out.println(compute(12L, 14L, (a, b) -> a + b));
System.out.println(compute(13L, 44L, (a, b) -> a * b));
}
public long compute(Long num1, Long num2, MyCalculate<Long, Long> cal) {
return cal.compute(num1, num2);
}