Java8_Lambda

2

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();
    }
}