Java 8 新特性之Lambda表达式

376 阅读4分钟

Lambda是啥?

Lambda 表达式也称为闭包,是 JDK8 的一个新特性,可以取代大部分的匿名内部类,配合stream进行使用在集合的遍历和其他集合操作中,可以极大地优化代码结构。

JDK8 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。

Lambda如何使用?

基础语法

Java 中的 Lambda 表达式通常使用语法是 (argument) -> (body),比如:

(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }

以下是 Lambda 表达式的简单示例:

//不需要参数,返回值为10  
() -> 10
//接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
//接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
//接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
//接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)

总结Lambda表达式特征:

  • Lambda 表达式可以具有零个,一个或多个参数;
  • 可以显式声明参数的类型,也可以由编译器自动从上下文推断参数的类型;
  • 一个参数无需定义圆括号,但多个参数需要定义圆括号,并用逗号进行分隔;
  • 如果 Lambda 表达式的正文只有一条语句,则大括号可不用写,且表达式的返回值类型要与匿名函数的返回类型相同

使用环境

一种情况是:Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法的接口可以使用Lambda表达式进行实现。

JDK 8中新增的另外一个特性,接口的默认方法:default,简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。我们只需在方法名前面加个 default 关键字即可实现默认方法。

另外一种情况是:功能接口,即使用注解@FunctionalInterface标注的接口,都可以使用Lambda表达式;这个注解是修饰函数式接口的,要求接口中的抽象方法只有一个。

其实如果你对匿名内部类非常熟悉的话,理解这个就非常容易了,Lambda表达式取代了匿名内部类的书写方式。

Lambda表达式例子

  • 功能接口

    当一个接口使用注解@FunctionalInterface的时候,我们就可以利用Lambda表达式进行调用

package com.mvasoft.lambda.demo;

@FunctionalInterface
public interface WorkerInterface {
    public void doWork();
}

class WorkTest {
    public static void main(String[] args) {
        // 通过匿名内部类调用
        WorkerInterface work = new WorkerInterface() {
            @Override
            public void doWork() {
                System.out.println("通过匿名内部类调用");
            }
        };
        work.doWork();
        // 通过 Lambda 表达式调用
        // Lambda 表达式实际上是一个对象。
        // 我们可以将 Lambda 表达式赋值给一个变量,就可像其它对象一样调用。
        work = ()-> System.out.println("通过 Lambda 表达式调用");
        work.doWork();
    }
}
  • 创建线程

    线程初始化写法的优化,而且当我们使用idea写代码的时候,如果写出了之前的方式,idea也会自动提示我们进行转换,非常人性化。

//Jdk8之前写法
new Thread(new Runnable() {
    @Override
    public void run() {
      System.out.println("Before Java8");
    }
}).start();

//Jdk8写法
new Thread( () -> System.out.println("In Java8, Lambda expression") ).start();
  • 遍历输出

    输出给定数组的所有元素的简单代码

//Jdk8之前写法
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for (Integer n : list) {
    System.out.println(n);
}
// 使用 -> 的 Lambda 表达式
list.forEach(n -> System.out.println(n));
// 使用 :: 的 Lambda 表达式,一种新的表达方式
list.forEach(System.out::println);
  • 排序

    定义一个Employee

public class Employee {
    private String name;
    private int age;
    private double salary;

    public Employee() {
    }
    public Employee(String name, int age, double salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
    public double getSalary() {
        return salary;
    }

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

针对这个Employee进行排序,先按照年龄比,年龄相同按照名字比,均为升序

//初始化数据
List<Employee> employees = Arrays.asList(
        new Employee("田七",27,7777.77),
        new Employee("王五",24,5555.55),
        new Employee("张三",23,3333.33),
        new Employee("李四",24,4444.44),
        new Employee("赵六",26,6666.66)
);
//排序
public void test1(){
   Collections.sort(employees,(x,y) ->{
       if(x.getAge() == y.getAge()){
           return x.getName().compareTo(y.getName());
       }else{
           return Integer.compare(x.getAge(),y.getAge());
       }
   });

   for (Employee emp: employees) {
       System.out.println(emp);
   }
}
//结果
name='张三', age=23, salary=3333.33
name='李四', age=24, salary=4444.44
name='王五', age=24, salary=5555.55
name='赵六', age=26, salary=6666.66
name='田七', age=27, salary=7777.77

补充一个知识点:

Arrays.asList()将数组转化为集合之后,它的底层其实还是数组,不可以使用修改集合的相关方法,这个数据在《阿里巴巴 Java 开发手册》中有说明,如下:

【强制】使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方 法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。 说明:asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList 体现的是适配器模式,只是转换接口,后台的数据仍是数组。 String[] str = new String[] { "a", "b" }; List list = Arrays.asList(str); 第一种情况:list.add("c"); 运行时异常。 第二种情况:str[0]= "gujin"; 那么 list.get(0)也会随之修改。

实现为真正的集合方式:

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"))

有任何问题欢迎关注公众号【Hugh的白板】私信我,一起探讨,一起学习