本文最后更新于 2024-04-01,欢迎来到我的Blog! https://www.zpeng.site/

Lambda表达式例子

1.例子

//1. 使用Lambda表达式进行集合遍历
//未使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
for (String fruit : list) {
    System.out.println(fruit);
}
//使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
list.forEach(fruit -> System.out.println(fruit));

//2. 使用Lambda表达式进行排序
//未使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
Collections.sort(list, new Comparator<String>() {
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
});
//使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
Collections.sort(list, (s1, s2) -> s1.compareTo(s2));

//3. 使用Lambda表达式进行过滤
//未使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
List<String> filteredList = new ArrayList<String>();
for (String fruit : list) {
    if (fruit.startsWith("a")) {
        filteredList.add(fruit);
    }
}
//使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
List<String> filteredList = list.stream().filter(fruit -> fruit.startsWith("a")).collect(Collectors.toList());

//4. 使用Lambda表达式进行映射
//未使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
List<Integer> lengths = new ArrayList<Integer>();
for (String fruit : list) {
    lengths.add(fruit.length());
}
//使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
List<Integer> lengths = list.stream().map(fruit -> fruit.length()).collect(Collectors.toList());

//5. 使用Lambda表达式进行归约
//未使用Lambda表达式:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;
for (int i : list) {
    sum += i;
}
//使用Lambda表达式:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
int sum = list.stream().reduce(0, (a, b) -> a + b);

//6. 使用Lambda表达式进行分组
//未使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
Map<Integer, List<String>> grouped = new HashMap<Integer, List<String>>();
for (String fruit : list) {
    int length = fruit.length();
    if (!grouped.containsKey(length)) {
        grouped.put(length, new ArrayList<String>());
    }
    grouped.get(length).add(fruit);
}
//使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
Map<Integer, List<String>> grouped = list.stream().collect(Collectors.groupingBy(fruit -> fruit.length()));

//7. 使用Lambda表达式进行函数式接口的实现
//未使用Lambda表达式:
public interface MyInterface {
    public void doSomething(String input);
}
MyInterface myObject = new MyInterface() {
    public void doSomething(String input) {
        System.out.println(input);
    }
};
myObject.doSomething("Hello World");
//使用Lambda表达式:
MyInterface myObject = input -> System.out.println(input);
myObject.doSomething("Hello World");

//8. 使用Lambda表达式进行线程的创建
//未使用Lambda表达式:
Thread thread = new Thread(new Runnable() {
    public void run() {
        System.out.println("Thread is running.");
    }
});
thread.start();
//使用Lambda表达式:
Thread thread = new Thread(() -> System.out.println("Thread is running."));
thread.start();

//9. 使用Lambda表达式进行Optional的操作
//未使用Lambda表达式:
String str = "Hello World";
if (str != null) {
    System.out.println(str.toUpperCase());
}
//使用Lambda表达式:
Optional<String> str = Optional.ofNullable("Hello World");
str.map(String::toUpperCase).ifPresent(System.out::println);

//10. 使用Lambda表达式进行Stream的流水线操作
//未使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
List<String> filteredList = new ArrayList<String>();
for (String fruit : list) {
    if (fruit.startsWith("a")) {
        filteredList.add(fruit.toUpperCase());
    }
}
Collections.sort(filteredList);
//使用Lambda表达式:
List<String> list = Arrays.asList("apple", "banana", "orange");
List<String> filteredList = list.stream().filter(fruit -> fruit.startsWith("a")).map(String::toUpperCase).sorted()

2.方法引用

方法引用:若 Lambda 体中的内容有方法已经实现了,我们可以使用“方法引用”,可以理解为方法引用是Lambda表达式的另外一种表现形式。

主要有三种语法格式:

  • 对象::实例方法名

  • 类::静态方法名

  • 类::实例方法名

1.对象::实例方法名

//对象::实例方法名
@Test
public void test6(){
    Consumer<String> con0=(x)-> System.out.println(x);
    con0.accept("hello0");

    PrintStream out = System.out;
    Consumer<String> con1=out::println;
    con1.accept("hello1");

    Consumer<String> con2=System.out::println;
    con2.accept("hello2");
}

2.类::静态方法名

    @Test
    public void test7() {
        Comparator<Integer> comparable = (x, y) -> Integer.compare(x, y);
        //使用方法引用实现相同效果
        Comparator<Integer> integerComparable = Integer::compare;
        System.out.println(integerComparable.compare(4, 2));//结果:1
        System.out.println(comparable.compare(4, 2));//结果:1
    }

3.类::实例方法名

    @Test
    public void test8() {
        BiPredicate<String, String> bp = (x, y) -> x.equals(y);
        //使用方法引用实现相同效果
        BiPredicate<String, String> bp2 = String::equals;
        System.out.println(bp.test("1", "2"));//结果:false
        System.out.println(bp.test("1", "2"));//结果:false
    }
  • Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!

  • 若Lambda参数列表中的第一参数是实例方法的调用者,第二个参数是实例方法的参数时,可以使用ClassName::method

3.构造器引用

格式:类名::new

与函数式接口相结合,自动与函数式接口中方法兼容,可以把构造器引用赋值给定义的方法。需要注意构造器参数列表要与接口中抽象方法的参数列表一致。使用示例:

创建一个实体类Employee:

public class Employee {
  private Integer id;
  private String name;
  private Integer age;

  @Override
  public String toString() {
    return "Employee{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", age=" + age +
            '}';
  }
  public Employee(){

  }

  public Employee(Integer id) {
    this.id = id;
  }

  public Employee(Integer id, Integer age) {
    this.id = id;
    this.age = age;
  }

  public Employee(int id, String name, int age) {
    this.id = id;
    this.name = name;
    this.age = age;
  }
}
  @Test
  public void test9(){
    //引用无参构造器
    Supplier<Employee> supplier=Employee::new;
    System.out.println(supplier.get());
    //引用有参构造器
    Function<Integer,Employee> function=Employee::new;
    System.out.println(function.apply(21));
    BiFunction<Integer,Integer,Employee> biFunction=Employee::new;
    System.out.println(biFunction.apply(8,24));
  }
  • 注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致!

4.数组引用

数组引用的格式:type[]:new

使用示例:

    @Test
    public void test9(){
        Function<Integer,String[]> fun =(x) ->new String[x];
        System.out.println(fun.apply(10).length);

        Function<Integer,String[]> function=String[]::new;
        String[] apply = function.apply(20);
        System.out.println(apply.length);//结果:20
    }

5.优缺点

优点:

使代码更简洁,紧凑

可以使用并行流来并行处理,充分利用多核CPU的优势

有利于JIT编译器对代码进行优化

缺点:

非并行计算情况下,其计算速度没有比传统的 for 循环快

不容易调试

若其他程序员没有学过 Lambda 表达式,代码不容易看懂