Java8_Lambda
Java8 新特性 lambda
Java8中的lambda表达式主要有以下几个作用:
- 简化代码:lambda表达式可以让你用更少的代码来实现函数式接口,避免使用匿名内部类的冗余代码。
- 支持并行处理:lambda表达式可以配合流(stream)API来实现数据的并行处理,提高程序的性能。
- 延迟执行:lambda表达式可以作为参数传递给其他方法,实现对代码块的延迟执行,例如在日志输出时可以提高效率。
- 增强集合操作:lambda表达式可以结合集合类的新方法,如forEach、removeIf、sort等,实现更灵活的集合操作。
lambda的语法
// Java 8之前:
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
// Java 8方式:
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
// 更简洁的写法:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
// 更简洁的写法:
Collections.sort(names, (a, b) -> b.compareTo(a));
函数式接口
函数式接口是一种只有一个抽象方法的接口,可以用@FunctionalInterface注解标记。函数式接口可以被赋值给lambda表达式,也可以作为方法的参数或返回值类型,实现对代码块的传递和调用。函数式接口是函数式编程的基础,Java 8中提供了很多内置的函数式接口,如Consumer(消费型),Supplier(供给型),Function(函数型)和Predicate(断言型)。
- Consumer(消费型)接口:它是一个有参无返回值的接口,表示接受一个输入参数并且无返回的操作。它的抽象方法是void accept(T t)。
- Supplier(供给型)接口:它是一个无参有返回值的接口,表示提供一个结果。它的抽象方法是T get()。
- Function(函数型)接口:它是一个有参有返回值的接口,表示对一个输入参数进行处理并返回一个结果。它的抽象方法是R apply(T t)。
- Predicate(断言型)接口:它是一个有参返回布尔值的接口,表示对一个输入参数进行判断。它的抽象方法是boolean test(T t)。
public static void printInfo(Consumer<String> consumer) {
consumer.accept("Hello, world!");
}
// 调用方法
printInfo(s -> System.out.println(s));
```java
public static int getRandomNumber(Supplier<Integer> supplier) {
return supplier.get();
}
// 调用方法
int num = getRandomNumber(() -> (int)(Math.random() * 100));
```java
public static String convertString(Function<String, String> function) {
return function.apply("Hello, world!");
}
// 调用方法
String result = convertString(s -> s.toUpperCase());
```java
public static boolean checkString(Predicate<String> predicate) {
return predicate.test("Hello, world!");
}
// 调用方法
boolean flag = checkString(s -> s.length() > 10);
MethodReference(方法引用)
- 引用静态方法
List<String> list = Arrays.asList("a","b","c");
list.forEach(Colon::print); // Colon::print 等同于 s -> Colon.print(s)
public static void print(String s) {
System.out.println(s);
}
- 引用实例方法
String content = "Hello JDK8";
Function<Integer, String> func = content::substring;
// content::substring 等同于 i -> content.substring(i)
String result = func.apply(1);
System.out.println(result);
- 引用构造方法
BiFunction<String, Integer, User> biFunction = User::new;
// User::new 等同于 (s,i) -> new User(s,i)
User user = biFunction.apply("小明", 20);
System.out.println(user.toString());
四大函数接口例子
- 假设有一个学生类Student,包含姓名,年龄,成绩三个属性,如下:
public class Student {
private String name;
private int age;
private int score;
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
// 省略getters和setters
}
假设有一个学生管理类StudentManager,包含一个学生列表,提供以下方法:
addStudent:使用Consumer接口作为参数,表示添加一个学生到列表中
getStudent:使用Supplier接口作为参数,表示从列表中随机获取一个学生
updateStudent:使用Function接口作为参数,表示对列表中的每个学生进行更新操作
removeStudent:使用Predicate接口作为参数,表示根据条件删除列表中的学生
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class StudentManager {
private List<Student> list; // 学生列表
public StudentManager() {
list = new ArrayList<>();
}
// 使用Consumer接口作为参数,表示添加一个学生到列表中
public void addStudent(Consumer<Student> consumer) {
// 创建一个新的学生对象
Student student = new Student("张三", 18, 80);
// 调用Consumer接口的accept方法,对学生对象进行消费(可以修改属性值)
consumer.accept(student);
// 将学生对象添加到列表中
list.add(student);
}
// 使用Supplier接口作为参数,表示从列表中随机获取一个学生
public Student getStudent(Supplier<Integer> supplier) {
// 调用Supplier接口的get方法,获取一个随机数作为索引
int index = supplier.get();
// 从列表中获取对应索引的学生对象
return list.get(index);
}
// 使用Function接口作为参数,表示对列表中的每个学生进行更新操作
public void updateStudent(Function<Student, Student> function) {
// 遍历列表中的每个学生对象
for (int i = 0; i < list.size(); i++) {
// 调用Function接口的apply方法,对学生对象进行处理,并返回一个新的学生对象
Student newStudent = function.apply(list.get(i));
// 用新的学生对象替换原来的学生对象
list.set(i, newStudent);
}
}
// 使用Predicate接口作为参数,表示根据条件删除列表中的学生
public void removeStudent(Predicate<Student> predicate) {
// 遍历列表中的每个学生对象
for (int i = 0; i < list.size(); i++) {
// 调用Predicate接口的test方法,对学生对象进行判断
boolean flag = predicate.test(list.get(i));
// 如果判断结果为true,表示满足删除条件,则从列表中移除该学生对象
if (flag) {
list.remove(i);
i--; // 索引要回退一位,防止漏删
}
}
}
// 打印列表中的所有学生信息
public void printAll() {
for (Student student : list) {
System.out.println(student);
}
}
}
- 假设有一个测试类Test,用来测试四大函数式接口的应用,如下:
public class Test {
public static void main(String[] args) {
// 创建一个学生管理对象
StudentManager manager = new StudentManager();
// 调用addStudent方法,使用Consumer接口作为参数,表示添加一个学生到列表中
manager.addStudent(s -> s.setName("李四")); // 修改学生姓名为李四
// 调用getStudent方法,使用Supplier接口作为参数,表示从列表中随机获取一个学生
Student student = manager.getStudent(() -> (int)(Math.random() * manager.getList().size())); // 随机生成一个索引值
System.out.println("随机获取的学生是:" + student);
// 调用updateStudent方法,使用Function接口作为参数,表示对列表中的每个学生进行更新操作
manager.updateStudent(s -> {
s.setAge(s.getAge() + 1); // 年龄加一岁
s.setScore(s.getScore() + 10); // 成绩加十分
return s; // 返回更新后的学生对象
});
// 调用removeStudent方法,使用Predicate接口作为参数,表示根据条件删除列表中的学生
manager.removeStudent(s -> s.getScore() < 90); // 删除成绩低于90分的学生
// 打印列表中的所有学生信息
manager.printAll();
}
}