Jdk1.8新特性之Lambda表达式

Posted madyanyan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jdk1.8新特性之Lambda表达式相关的知识,希望对你有一定的参考价值。

近期公司的新项目中使用了很多jdk1.8新特性,特来做个小结

一.Lambda表达式的使用

 lambda表达式也叫函数式编程 :Lambda需要函数式接口支持,并且接口中的抽象方法只能有一个
函数式接口:接口中只有一个抽象方法的接口,称之为函数式接口。可以使用@FunctionalInterface修饰,该注解可以检查是否是函数式接口。

自己的理解就是可以 lambda表达式向数据一样传递

直接上代码体会

 //原来匿名内部类
    @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);
    }

    //现在的 Lambda 表达式
    @Test
    public void test2() {
        //比较器
        Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

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

 

 

JDK1.8之前处理需求

1.new集合 2.遍历 3.if判断

 //需求:获取工资大于 5000 的员工的信息
    public List<Employee> filterEmployeeBySalary(List<Employee> employees) {
        List<Employee> list = new ArrayList<>();

        for (Employee employee : employees) {
            if (employee.getSalary() >= 5000) {
                list.add(employee);
            }
        }

        return list;
    }

   

 

可以发现弊端:当需求有变更 新增过滤条件 又需要遍历一遍 if判断  实际需要的代码只有一句if (employee.getAge() > 18)  却要写大量冗余代码 很恶心

 

 //需求:获取年龄大于 18  的员工的信息
    public List<Employee> filterEmployeeByAge(List<Employee> employees) {
        List<Employee> list = new ArrayList<>();

        for (Employee employee : employees) {
            if (employee.getAge() > 18) {
                list.add(employee);
            }
        }

        return list;
    }

 

 优化思路:策略模式

1.定义接口  作为过滤条件

public interface MyPredicate<T> {
    
    public boolean test(T t);

}

 2.接口实现  设置过滤条件

public class FilterEmployeeBySalary implements MyPredicate<Employee>{

    @Override
    public boolean test(Employee t) {
        return t.getSalary() >= 5000;
    }

}
public class FilterEmployeeByAge implements MyPredicate<Employee> {

    @Override
    public boolean test(Employee t) {
        return t.getAge() > 18;
    }

}

3.定义filter方法 传入需要过滤集合,和过滤条件接口

  //优化方式一:策略设计模式
    public List<Employee> filterEmployees(List<Employee> employees, MyPredicate<Employee> mp) {
        List<Employee> list = new ArrayList<>();

        for (Employee employee : employees) {
            if (mp.test(employee)) {
                list.add(employee);
            }
        }
        return list;
    }

4.测试

@Test
    public void test4() {
        List<Employee> list = filterEmployees(employees, new FilterEmployeeBySalary());

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

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

        List<Employee> list2 = filterEmployees(employees, new FilterEmployeeByAge());

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

 

使用匿名内部类简化代码

 //优化方式二:策略设计模式 + 匿名内部类
    @Test
    public void test5() {
        List<Employee> list = filterEmployees(employees, new MyPredicate<Employee>() {
            @Override
            public boolean test(Employee t) {
                return t.getSalary() >= 5000;
            }
        });

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

 

使用lambda表达式 更加简洁

 //优化方式三:策略设计模式 + Lambda 表达式
    @Test
    public void test6() {
        List<Employee> list = filterEmployees(employees, (e) -> e.getSalary() >= 5000);
        list.forEach(System.out::println);
    }

 

弊端:每增加一个过滤条件都需要写一份实现类

能不能不写接口和实现类就实现对集合的过滤?答案是肯定的

在JDK1.8中 引入流操作,使用Stream+Lambda表达式  极大简化代码

//优化方式四:Stream API
    @Test
    public void test7() {
        employees.stream()
                .filter((e) -> e.getSalary() >= 5000)
                .forEach(System.out::println);

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

        employees.stream()
                .map(Employee::getName)
                .forEach(System.out::println);
    }

 lambda表达式的基本使用规则:

/**
     * lambda表达式
     * 左侧:Lambda表达式的参数列表
     * 右侧:Lambda表达式所执行的功能,即lambda体
     * 接口中只能有一个实现类
     */
    @Test
    public void test8() {
        //Consumer接口中只有一个抽象方法,和一个接口默认方法
        Consumer<String> con = (x) -> System.out.println("Yan:" + x);
        con.accept("我是YanYan啊");
    }

    @Test
    public void test9() {
        //lambda体中有多条语句,必须使用大括号
        Comparator<Integer> com = (x, y) -> {
            System.out.println("Comparator接口");
            return x.compareTo(y);
        };
        com.compare(1, 2);

    }
//原来匿名内部类
    @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);
    }

    //现在的 Lambda 表达式
    @Test
    public void test2() {
        //比较器
        Comparator<Integer> com = (x, y) -> Integer.compare(x, y);

        TreeSet<Integer> ts = new TreeSet<>(com);
    }
//Demo1
@FunctionalInterface
interface MyFun { Integer getValue(Integer num); } public Integer operation(Integer num, MyFun mf) { return mf.getValue(num); } @Test public void test10() { System.out.println(operation(10, (x) -> x * x)); System.out.println(operation(1, x -> x + x)); }

 

//Demo2
@FunctionalInterface
interface HandleStr { String handle(String str); } public String strHandle(String str, HandleStr hs) { return hs.handle(str); } @Test public void test2() { String str = "zhangyan"; System.out.println( strHandle(str, x -> { //转换成大写 return x.toUpperCase().substring(1, 3); })); }
//Demo3
@FunctionalInterface
interface MyFun3<T, R> { R getValue(T t1, T t2); } public void op(Long l1, Long l2, MyFun3<Long, Long> mf) { System.out.println(mf.getValue(l1, l2)); } @Test public void test3() { op(100l,200l,(x,y)-> x+y); op(10l,15l,(x,y)->{ return x*y; }); }

 

 

 

 

二.JAVA内置四大核心函数式接口

之前我们在使用Lamda表达式中每次都需要自己写一个接口,然后再去自定义接口的实现类

然而,JKD1.8已经为我们定义了四大函数式接口,配合Lambda表达式使用起来非常方便

/**
 * java内置四大核心函数式接口
 * <p>
 * 1.Consumer<T>消费型接口 无返回值  void accept(T t)
 * 2.Supplier<T>供给型接口 T get();
 * 3.Function<T>函数型接口 R apply(T t)
 * 4.Predicate<T>断言型接口 用于做判断操作 boolean test(T t)
 */
public class TestLambda3 {

    //Consumer<T>
    @Test
    public void test1() {
        happy(10.15, (x) -> System.out.println(x));

    }

    //happy
    public void happy(double money, Consumer<Double> con) {
        con.accept(money);
    }


    //Supplier<T> 产生指定个数的随机数,存入集合
    @Test
    public void test2() {
        this.getNumber(10, () -> (int) Math.random() * 100);
    }

    public List<Integer> getNumber(int num, Supplier<Integer> sup) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            list.add(sup.get());
        }
        return list;
    }


    //Predicate<T>

    @Test
    public void test3() {
        List<String> strList = Arrays.asList("Mike", "Lee", "Yan");
        //使用时设置条件
        List<String> list = this.filterStr(strList, (x) -> x.length() > 3);
        list.forEach(System.out::print);
    }

    //将满足条件的字符串 存入集合中
    public List<String> filterStr(List<String> str, Predicate<String> pre) {
        List<String> list = new ArrayList<>();

        for (String s : str) {
            if (pre.test(s)) {
                list.add(s);
            }
        }
        return list;
    }

 

 

 

 

三.方法引用和构造器引用

本质上是lambda表达式的另一种表现形式

* 三种语法格式
* 1.对象 :: 实例方法名
*
* 2.:: 静态方法名
*
* 3.:: 实例方法名
*/
public class TestMethodRef {

    @Test
    public void test1() {

        Consumer<String> consumer = (x)-> System.out.println(x);

        PrintStream ps = System.out;
        Consumer<String> son =  ps::println;

    }
 @Test
    public void test2() {
        Employee emp = new Employee("Yan", 24, ‘男‘, 14000);
        Supplier<String> sup = emp::getName;
       /* Supplier<String> sup2 = new Supplier<String>() {
            @Override
            public String get() {
               return emp.getName();
            }
        };*/

//     与上面语句功能相同    Supplier sup2 = ()->emp.getName();
        String s = sup.get();
        System.out.println(s);
    }


    //类 :: 静态方法
    @Test
    public void test3() {
        Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);

        Comparator<Integer> com2 = Integer::compare;
    }


    //类 :: 实例方法名

    @Test
    public void test4() {
        BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);

        //限制条件:只有当(x, y) -> x.equals(y) 第一个参数x作为参数的调用者,第二个参数y为方法参数时,才可以使用这种方式
        //ClassName::method
        BiPredicate<String, String> bp2 = String::equals;
    }


    //构造器引用 ClassName::new
    @Test
    public void test5() {
        Supplier<Employee> sup1 = () -> new Employee();
        Employee employee = sup1.get();//接口sup1 调用方法 get()  get方法被() -> new Employee() 重写

        //调用无参构造器  因为 需要和Supplier get方法中的入参和返回值类型保持一致
        Supplier<Employee> sup2 = Employee::new;


        //如需使用其他构造器则
        BiFunction<String, Integer, Employee> bg1 = (x, y) -> new Employee(x, y);
        System.out.println(bg1.apply("Yan", 23));

        //调用有参构造器,取决于BiFunction中的apply方法的入参
        BiFunction<String, Integer, Employee> bg2 = Employee::new;


    }


    //数组引用 type[] :: new
    @Test
    public void test6() {
        Function<Integer, String[]> fun1 = (x) -> new String[x];
        String[] apply = fun1.apply(10);
        System.out.println(apply);

        Function<Integer, String[]> fun2 = String[]::new;

    }

 



 

















以上是关于Jdk1.8新特性之Lambda表达式的主要内容,如果未能解决你的问题,请参考以下文章

JDK1.8新特性

jdk1.8新特性之lambda表达式及在Android Studio中的使用举例

JDK1.8新特性之--方法引用

jdk1.8新特性Lambda表达式方法引用

JDK1.8新特性之--函数式接口

jdk1.8新特性总结