lambda表达式
本质:函数式接口的实例。
1 lambda表达式的使用
格式
- lambda表达式分为三部分:形参列表 箭头操作符 lambda体。例子:
(a, b) -> Integer.compare(a, b);
形参列表 箭头操作符 lambda体
-
形参列表:其实就是接口中的抽象方法的形参列表。
-
lambda体:其实就是重写的抽象方法的方法体。
语法格式一:无参,无返回值
@Test
public void test1() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
};
r1.run(); // 就是普通的函数调用
System.out.println("-------------------------");
Runnable r2 = () -> System.out.println("world");
r2.run();
}
语法格式二:一个参数,无返回值
@Test
public void test2() {
Consumer<String> con1 = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con1.accept("hello");
System.out.println("-------------------------");
Consumer<String> con2 = s -> System.out.println(s); // 类型推断
con2.accept("world");
}
语法格式三:两个或以上的参数,多条执行语句,可以有返回值
@Test
public void test3() {
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
System.out.println(a);
System.out.println(b);
return a.compareTo(b);
}
};
System.out.println(com1.compare(1, 2));
System.out.println("-------------------------");
Comparator<Integer> com2 = (a, b) -> {
System.out.println(a);
System.out.println(b);
return a.compareTo(b);
};
System.out.println(com2.compare(2, 1));
}
语法格式四:当lambda体只有一条语句时,可以省略大括号和return
@Test
public void test4() {
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a.compareTo(b);
}
};
System.out.println(com1.compare(1, 2));
System.out.println("-------------------------");
Comparator<Integer> com2 = (a, b) -> a.compareTo(b);
System.out.println(com2.compare(2, 1));
}
2 函数式接口
函数式接口:如果一个接口中,只声明了一个抽象方法,则此接口就被称为函数式接口。
-
我们可以在一个接口上使用
@FunctionalInterface
注解,这样做可以检查它是否是一个函数式接口。 -
lambda表达式 和 函数式接口 的关系:lambda表达式依赖于函数式接口,如果函数式接口不存在,那么也不可能存在lambda表达式。lambda表达式本质上是函数式接口的实例。
Java内置四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer<T> | T | void | 消费型接口。包含的方法:void accept(T t) |
Supplier<T> | 无 | T | 供给型接口。包含的方法:T get() |
Function<T, R> | T | R | 函数型接口。包含的方法:R apply(T t) |
Predicate<T> | T | boolean | 断定型接口。包含的方法:boolean test(T t) |
使用举例
// 消费型接口
@Test
public void test1() {
enjoy(500, new Consumer<Double>() {
@Override
public void accept(Double money) {
System.out.println("消费了" + money + "元...");
}
});
System.out.println("-------------------------");
enjoy(400, money -> System.out.println("消费了" + money + "元..."));
}
public void enjoy(double money, Consumer<Double> con) {
con.accept(money);
}
// 断定型接口
@Test
public void test2() {
List<String> list = Arrays.asList("北京", "南京", "天津", "东京");
List<String> res1 = filterString(list, new Predicate<String>() {
@Override
public boolean test(String s) {
return s.contains("京"); // 判定规则:字符串中是否含有 京
}
});
System.out.println(res1);
System.out.println("-------------------------");
List<String> res2 = filterString(list, s -> s.contains("京"));
System.out.println(res2);
}
public List<String> filterString(List<String> list, Predicate<String> pre) {
List<String> res = new ArrayList<>();
for (String s : list)
if (pre.test(s)) // 判定是否成功
res.add(s);
return res;
}
3 方法引用
方法引用:就是lambda表达式,只不过形式不同。
-
当要传递给lambda体的操作,已经有实现的方法了,可以使用方法引用。
-
要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致。
-
格式:使用操作符
::
将类(对象) 与 方法名 分割开来。 -
有如下三种使用情况:
-
(1)对象 :: 实例方法
-
(2)类 :: 静态方法
-
(3)类 :: 实例方法
-
关于Empoyee
类请参考附录
情况一:对象 :: 实例方法
// 情况一:对象 :: 实例方法
// Consumer中的void accept(T t)
// PrintStream中的void println(T t)
@Test
public void test1() {
Consumer<String> con1 = s -> System.out.println(s);
con1.accept("北京");
System.out.println("-------------------------");
Consumer<String> con2 = System.out::println; // 方法引用
con2.accept("beijing");
}
// Supplier中的T get()
// Employee中的String getName()
@Test
public void test2() {
Employee emp = new Employee(1001, "Tom", 23, 5600);
Supplier<String> sup1 = () -> emp.getName();
System.out.println(sup1.get());
System.out.println("-------------------------");
Supplier<String> sup2 = emp::getName;
System.out.println(sup2.get());
}
情况二:类 :: 静态方法
// 情况二:类 :: 静态方法
// Comparator中的int compare(T t1,T t2)
// Integer中的int compare(T t1,T t2)
@Test
public void test3() {
Comparator<Integer> com1 = (a, b) -> Integer.compare(a, b);
System.out.println(com1.compare(1, 2));
System.out.println("-------------------------");
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(2, 1));
}
// Function中的R apply(T t)
// Math中的Long round(Double d)
@Test
public void test4() {
Function<Double, Long> func = new Function<Double, Long>() {
@Override
public Long apply(Double d) {
return Math.round(d);
}
};
Function<Double, Long> func1 = d -> Math.round(d);
System.out.println(func1.apply(12.3));
System.out.println("-------------------------");
Function<Double, Long> func2 = Math::round;
System.out.println(func2.apply(12.6));
}
情况三:类 :: 实例方法
// 情况三:类 :: 实例方法
// Comparator中的int comapre(T t1,T t2)
// String中的int t1.compareTo(t2)
@Test
public void test5() {
Comparator<String> com1 = (a, b) -> a.compareTo(b);
System.out.println(com1.compare("abc", "abf"));
System.out.println("-------------------------");
Comparator<String> com2 = String::compareTo;
System.out.println(com2.compare("abc", "abm"));
}
// BiPredicate中的boolean test(T t1, T t2);
// String中的boolean t1.equals(t2)
@Test
public void test6() {
BiPredicate<String, String> pre1 = (a, b) -> a.equals(b);
System.out.println(pre1.test("abc", "abc"));
System.out.println("-------------------------");
BiPredicate<String, String> pre2 = String::equals;
System.out.println(pre2.test("abc", "abd"));
}
// Function中的R apply(T t)
// Employee中的String getName();
@Test
public void test7() {
Employee emp = new Employee(1001, "Jerry", 23, 6000);
Function<Employee, String> func1 = e -> e.getName();
System.out.println(func1.apply(emp));
System.out.println("-------------------------");
Function<Employee, String> func2 = Employee::getName;
System.out.println(func2.apply(emp));
}
4 构造器引用
// 构造器引用
// Supplier中的T get()
// 调用无参的构造器
@Test
public void test1() {
Supplier<Employee> sup = new Supplier<Employee>() {
@Override
public Employee get() {
return new Employee();
}
};
Supplier<Employee> sup1 = () -> new Employee();
System.out.println(sup1.get());
System.out.println("-------------------------");
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
}
// Function中的R apply(T t)
// 调用含有一个参数的构造器
@Test
public void test2() {
Function<Integer, Employee> func1 = id -> new Employee(id);
System.out.println(func1.apply(1001));
System.out.println("-------------------------");
Function<Integer, Employee> func2 = Employee::new;
System.out.println(func2.apply(1002));
}
// BiFunction中的R apply(T t,U u)
// 调用含有两个参数的构造器
@Test
public void test3() {
BiFunction<Integer, String, Employee> func1 = (id, name) -> new Employee(id, name);
System.out.println(func1.apply(1001, "Tom"));
System.out.println("-------------------------");
BiFunction<Integer, String, Employee> func2 = Employee::new;
System.out.println(func2.apply(1002, "Jerry"));
}
5 数组引用
// 数组引用: 可以把数组看做一个特殊的类,则写法与构造器一致
// Function中的R apply(T t)
@Test
public void test4() {
Function<Integer, String[]> func1 = len -> new String[len];
String[] arr1 = func1.apply(3);
System.out.println(Arrays.toString(arr1)); // [null, null, null]
System.out.println("-------------------------");
Function<Integer, String[]> func2 = String[]::new;
String[] arr2 = func2.apply(6);
System.out.println(Arrays.toString(arr2)); // [null, null, null, null, null, null]
}
附录
public class Employee {
private int id;
private String name;
private int age;
private double salary;
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Employee() {
}
public Employee(int id) {
this.id = id;
}
public Employee(int id, String name) {
this.id = id;
this.name = name;
}
public Employee(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", salary=" + salary + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
if (id != employee.id) return false;
if (age != employee.age) return false;
if (Double.compare(employee.salary, salary) != 0) return false;
return name != null ? name.equals(employee.name) : employee.name == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + age;
temp = Double.doubleToLongBits(salary);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}