Java 8 新特性之Lambda表达式

Reading time ~3 minutes

1. 概述

1.1 简介

Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使 Java 的语言表达能力得到了提升。

1.2 为什么要使用 Lambda 表达式

1. 实例

比如说我们要为 TreeSet 添加一个比价器,如果用原来的匿名内部类实现如下

@Test
public void test1() {
    Comparator<Integer> com = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    };

    TreeSet<Integer> ts = new TreeSet<>(com);

    TreeSet<Integer> ts2 = new TreeSet<>(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    });

    ts2.addAll(Arrays.asList(4, 5, 7, 3, 2, 1, 8, 6, 9));
    System.out.println(ts2.toString());
}

Lambda 表达式实现如下

@Test
public void test2() {
    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
    TreeSet<Integer> ts = new TreeSet<>(com);
    ts.addAll(Arrays.asList(4, 5, 7, 3, 2, 1, 8, 6, 9));
    System.out.println(ts.toString());
}

2. 实例

对一个 List 里面的对象进行操作

实体类

public class Employee implements Serializable {

    private int id;
    private String name;
    private int age;
    private double salary;
    // 省略 getter 和 setter 方法
}

基础数据

List<Employee> emps = Arrays.asList(
        new Employee(1, "张三", 18, 9999.99),
        new Employee(2, "李四", 59, 6666.66),
        new Employee(3, "王五", 28, 3333.33),
        new Employee(4, "赵六", 8, 7777.77),
        new Employee(5, "田七", 38, 5555.55)
);
普通实现

我们有两个需求,一个是“获取公司中年龄小于 35 的员工信息”,一个是“获取公司中工资大于 5000 的员工信息”

/**
 * 需求:获取公司中年龄小于 35 的员工信息
 *
 * @param emps
 * @return
 */
public List<Employee> filterEmployeeAge(List<Employee> emps) {
    List<Employee> list = new ArrayList<>();
    for (Employee emp : emps) {
        if (emp.getAge() <= 35) {
            list.add(emp);
        }
    }
    return list;
}

@Test
public void test3() {
    List<Employee> list = filterEmployeeAge(emps);

    for (Employee employee : list) {
        System.out.println(employee);
    }
}

/**
 * 需求:获取公司中工资大于 5000 的员工信息
 *
 * @param emps
 * @return
 */
public List<Employee> filterEmployeeSalary(List<Employee> emps) {
    List<Employee> list = new ArrayList<>();
    for (Employee emp : emps) {
        if (emp.getSalary() >= 5000) {
            list.add(emp);
        }
    }
    return list;
}

这样的话我要神队每个需求都写个方法,如果再增加需求,还需要再写

优化方式一:策略设计模式

定义一个接口

public interface MyPredicate<T> {
    public boolean test(T t);
}
/**
 * 策略设计模式
 *
 * @param emps
 * @param mp
 * @return
 */
public List<Employee> filterEmployee(List<Employee> emps, MyPredicate<Employee> mp) {
    List<Employee> list = new ArrayList<>();
    for (Employee employee : emps) {
        if (mp.test(employee)) {
            list.add(employee);
        }
    }
    return list;
}

/**
 * 根据不同的需求实现不同的策略
 */
@Test
public void test4() {
    List<Employee> list = filterEmployee(emps, new FilterEmployeeForAge());
    for (Employee employee : list) {
        System.out.println(employee);
    }

    System.out.println("---------------------------------------");

    List<Employee> list2 = filterEmployee(emps, new FilterEmployeeForSalary());
    for (Employee employee : list2) {
        System.out.println(employee);
    }
}
优化方式二:匿名内部类
/**
 * 匿名内部类
 */
@Test
public void test5() {
    List<Employee> list = filterEmployee(emps, new MyPredicate<Employee>() {
        @Override
        public boolean test(Employee t) {
            return t.getId() <= 103;
        }
    });

    for (Employee employee : list) {
        System.out.println(employee);
    }
}
优化方式三:Lambda 表达式
/**
 * Lambda 表达式
 */
@Test
public void test6() {
    List<Employee> list = filterEmployee(emps, (e) -> e.getAge() <= 35);
    list.forEach(System.out::println);

    System.out.println("------------------------------------------");

    List<Employee> list2 = filterEmployee(emps, (e) -> e.getSalary() >= 5000);
    list2.forEach(System.out::println);
}
优化方式四:Stream API
/**
 * Stream API
 */
@Test
public void test7() {
    emps.stream()
            .filter((e) -> e.getAge() <= 35)
            .forEach(System.out::println);

    System.out.println("----------------------------------------------");

    emps.stream()
            .map(Employee::getName)
            .limit(3)
            .sorted()
            .forEach(System.out::println);
}

2. Lambda 表达式的基础语法

  1. Java8 中引入了一个新的操作符 -> 该操作符称为箭头操作符或 Lambda 操作符,箭头操作符将 Lambda 表达式拆分成两部分:
    • 左侧:Lambda 表达式的参数列表(即接口抽象方法的参数列表)
    • 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体(即接口的实现)
  2. Lambda 表达式需要“函数式接口”的支持
    • 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解 @FunctionalInterface 修饰,可以检查是否是函数式接口
    • 函数式接口可以有默认方法和静态方法。
    • 任何满足单一抽象方法法则的接口,都会被自动视为函数接口。这包括 Runnable 和 Callable 等传统接口,以及您自己构建的自定义接口。

2.1 无参数,无返回值

() -> System.out.println("Hello Lambda!");

1. 实例

@Test
public void t1(){
    Runnable r1 = () -> System.out.println("Hello Lambda!");
    r1.run();
}

2.2 有一个参数,并且无返回值

(x) -> System.out.println(x)

1. 实例

@Test
public void t2(){
    Consumer<String> con = (x) -> System.out.println(x);
    con.accept("Hello Lambda!");
}

2. 实例

如果只有一个参数的情况下小括号是可以省略的

@Test
public void t3(){
    Consumer<String> con = x -> System.out.println(x);
    con.accept("Hello Lambda!");
}

2.3 有两个以上的参数,有返回值,并且 Lambda 体中有多条语句

1. 实例

@Test
public void t4() {
    Comparator<Integer> com = (x, y) -> {
        System.out.println("函数式接口");
        return Integer.compare(x, y);
    };
}

2.4 若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写

1. 实例

@Test
public void t5(){
    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
}

Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断”,如果写类型的话如下

@Test
public void t6(){
    Comparator<Integer> com = (Integer x,Integer y) -> Integer.compare(x, y);
}

转载请注明出处:
文章地址:Java 8 新特性之Lambda表达式
文章作者:凌风
原始连接:https://huangxubo.me/blog/java/java8-lambda/
许可协议:转载请注明原文链接及作者。

CentOS 7 中搭建PPTP、L2TP、IPSec 服务

VPN(Virtual Private Network,即“虚拟私人网络”)是一种通过在数据传输过程中加密的方式来保障数据传输安全的通信方式,L2TP是其中的一种加密方式。 Continue reading

Cnet OS 安装 Shadowscoks-libev 客户端

Published on December 21, 2019

OpenResty 编译安装

Published on December 20, 2019