Java 8系列之Lambda表达式(一)

    Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。

  Lambda 表达式 − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)

  更多的新特性可以参阅官网:What's New in JDK 8


Lambda表达式

lambda表达式的语法由参数列表、->和函数体组成。函数体既可以是一个表达式,也可以是一个语句块:

表达式:表达式会被执行然后返回执行结果。

语句块:语句块中的语句会被依次执行,就像方法中的语句一样—— 

    return语句会把控制权交给匿名方法的调用者

    break和continue只能在循环中使用

    如果函数体有返回值,那么函数体内部的每一条路径都必须返回值

   表达式函数体适合小型lambda表达式,它消除了return关键字,使得语法更加简洁。

简单实现:

    场景: 有一组员工数据,需要根据年龄、工资等不同的过滤条件,进行数据过滤。

    基础实现:编写不同的过滤方法,按照各自的条件进行过滤,返回数据。

    缺陷:冗余代码过多,只是条件不同,其余基本一致。

    优化:使用策略模式,定义接口,按照条件实现不同的接口,使用时传入不同的接口即可,使用lambda更为简便。

定义的接口,声明为泛型

/*
* describe 接口,方便过滤,声明为一个泛型
*/
public interface MyPredicate<T> {
    boolean test(T t);
}

按条件实现接口(根据不同的条件实现多个类,也可以使用匿名内部类)

/*
    自定义按员工年龄过滤
*/
public class FilterEmployeeByAge implements MyPredicate<Employee> {
    @Override
    public boolean test(Employee employee) {
        return employee.getAge() > 35;
    }
}

使用接口来实现过滤

    // 如果按不同的条件过滤,会产生冗余代码
    // 优化方式1:
    @Test
    public void test4() {
        // 添加条件,只需要实现MyPredicate接口,添加到此处即可
        // List<Employee> list = filterEmployees(employees, new FilterEmployeeByAge());
        List<Employee> list = filterEmployees(employees, new FilterEmployeeBySalary());
        for (Employee item: list) {
            System.out.println(item);
        }
    }

    // 此时使用接口来操作
    public List<Employee> filterEmployees(List<Employee> list, MyPredicate<Employee> mp){
        List<Employee> emps = new ArrayList<>();
        for (Employee item: list) {
            if(mp.test(item)) {
                emps.add(item);
            }
        }
        return emps;
    }

    // 优化方式2:匿名内部类
    @Test
    public void test5() {
        List<Employee> list = filterEmployees(employees, new MyPredicate<Employee>() {
            // 匿名内部类 实现过滤条件
            @Override
            public boolean test(Employee employee) {
                return employee.getSalary() < 5000;
            }
        });
        for (Employee item:list) {
            System.out.println(item);
        }
    }
    
    // 优化方式3:Lambda 表达式实现(依赖接口及以上的过滤方法)
    @Test
    public void test6() {
        List<Employee> list = filterEmployees(employees, (e) -> e.getSalary() < 5000);
        list.forEach(System.out::println);
    }

    // 优化方式4:Lambda 配合stream实现(不依赖接口)
    @Test
    public void test7() {
        // 转换为stream,配合filter实现过滤
        employees.stream()
                 .filter((e) -> e.getSalary() < 5000)
                 .limit(2)
                 .forEach(System.out::println);

        System.out.println("------------------------------------");
        // 过滤后提取姓名
        employees.stream()
                 .filter(e -> e.getSalary() < 5000)
                 .map(Employee::getName)
                 .forEach(System.out::println);
    }

语法介绍:

/**
 * 一、lambda 表达式的基础语法: Java8中引入了一个新的操作符‘->’,箭头操作符或Lambda操作符
 *     箭头操作符把表达式分为两部分
 *     左侧:Lambda 表达式的参数列表
 *     右侧:Lambda 表达式中所需执行的功能,Lambda体
 *
 * 语法格式一:无参数、无返回值
 *      () -> System.out.println("Hello Lambda!")
 *
 * 语法格式二:有一个参数,无返回值
 *      (x) -> System.out.println(x);
 *
 * 语法格式三:有一个参数,无返回值,小括号可以省略
 *       x  -> System.out.println(x);
 *
 * 语法格式四:有两个及以上参数,有返回值,并且lambda体中有多条语句
 *      (x,y) -> {...}
 *      Comparator<Integer> comparator = (x, y) -> {
 *             System.out.println("函数式接口");
 *             return Integer.compare(x, y);
 *         };
 *
 * 语法格式五:有两个及以上参数,有返回值,并且lambda体中只有一条语句,return、大括号可以省略
 *      (x, y) -> Integer.compare(x, y);
 *
 * 语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出对应数据类型(类型推断)
 *      (Integer x, Integer y) -> Integer.compare(x, y);
 *      (x, y) -> Integer.compare(x, y);
 *
 * 二、Lambda 表达式需要函数式接口的支持
 *     函数式接口:接口中只有一个抽象方法的接口。 可以使用注解 @FunctionalInterface 修饰 [ 检测是否是函数式接口 ]
 *
 */

测试程序,基本都添加了注释:

public class LambdaBase {

    // 语法格式一:无参数、无返回值
    @Test
    public void test1() {
        int num = 0; // jdk1.7之前需要声明为final,1,8无需声明,默认为final
        // 匿名内部类实现
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World" + num);
            }
        };
        r.run();
        System.out.println("------------------------");
        // Lambda实现
        Runnable lr = () -> System.out.println("Hello Lambda" + num);
        lr.run();
    }

    // 语法格式二:有一个参数,无返回值
    @Test
    public void test2() {
        // lambda右侧就是对Consumer中accept方法的实现
        Consumer<String> consumer = (x) -> System.out.println(x);
        consumer.accept("Lambda语法二,一个参数,无返回值");
    }

    // 语法格式三:有一个参数,小括号可以省略
    @Test
    public void test3() {
        Consumer<String> consumer = x -> System.out.println(x);
        consumer.accept("语法格式三:有一个参数,小括号可以省略");
    }

    // 语法格式四:有多个参数,Lambda中有多条语句,有返回值
    @Test
    public void test4() {
        Comparator<Integer> comparator = (x, y) -> {
            System.out.println("函数式接口");
            return Integer.compare(x, y);
        };
        System.out.println(comparator.compare(4, 5));
    }

    // 语法格式五:有两个及以上参数,有返回值,并且lambda体中只有一条语句,return、大括号可以省略
    @Test
    public void test5() {
        Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);
        System.out.println(comparator.compare(5,4));
    }

    /*********************************************************************************/

    @Test
    public void test6() {
        // lambda表达式实现函数式接口
        int result = operation(10, (x) -> x + x);
        System.out.println(result);
        System.out.println(operation(200, x -> x * x));
    }

    // 调用函数式接口进行计算
    public Integer operation(Integer num, MyFunction<Integer> myFunction) {
        return myFunction.getValue(num);
    }

}

test6中函数式接口:

待续。

参考:

  尚硅谷_Java8新特性

猜你喜欢

转载自blog.csdn.net/x3499633/article/details/81078497