zoukankan      html  css  js  c++  java
  • java8 lambda表达式

    【前言】 java8新特性

    java8 函数接口

    java8 Optional使用总结

    Java 8 时间日期使用

    java8中一个非常重要的特性就是lambda表达式,我们可以把它看成是一种闭包,它允许把函数当做参数来使用,是面向函数式编程的思想,一定程度上可以使代码看起来更加简洁。例如以前我们使用匿名内部类来实现代码:

         //匿名内部类写法
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("内部类写法");
                }
            }).start();

    使用lambda则更加简洁:

            //lambda 写法
            new Thread(() -> System.out.println("lambda写法")).start();    

    1、lambda表达式语法

        (paramters) -> expression;

    或者

        (paramters) -> {statements;}  
        展开如:
        (Type1 param1, Type2 param2, Type2 param2, ...) -> {
            statement1;
            statement2;
            statement3;
            ...
            return statementX;
        }   

    2、lambda表达式特征

    •  可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
    •  可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
    •  可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
    •  可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

    示例:

            //入参为空
            TestDemo no_param = () -> "hi, no param";
            TestDemo no_param2 = () -> { return "hi, no param"; };
            System.out.println(no_param.hi());
    
            //单个参数
            TestDemo2 param = name -> name;
            TestDemo2 param2 = name -> { return name;};
            System.out.println(param.hei("hei, grils"));
    
            //多个参数
            TestDemo3 multiple = (String hello, String name) -> hello + " " + name;
            //一条返回语句,可以省略大括号和return
            TestDemo3 multiple2 = (hello, name) -> hello + name;
            //多条处理语句,需要大括号和return
            TestDemo3 multiple3 = (hello, name) -> {
                System.out.println("进入内部");
                return hello + name;
            };
            System.out.println(multiple.greet("hello", "lambda"));

    3、方法引用

    有以下几种类型

    3.1 对象::实例方法,将lambda的参数当做方法的参数使用

    objectName::instanceMethod

    示例:

            Consumer<String> sc = System.out::println;
            //等效
            Consumer<String> sc2 = (x) -> System.out.println(x);
            sc.accept("618, 狂欢happy");

    3.2 类::静态方法,将lambda的参数当做方法的参数使用

    ClassName::staticMethod

    示例:

            //ClassName::staticMethod  类的静态方法:把表达式的参数值作为staticMethod方法的参数
            Function<Integer, String> sf = String::valueOf;
            //等效
            Function<Integer, String> sf2 = (x) -> String.valueOf(x);
            String apply1 = sf.apply(61888);

    3.3 类::实例方法,将lambda的第一个参数当做方法的调用者,其他的参数作为方法的参数。开发中尽量少些此类写法,减少后续维护成本。

    ClassName::instanceMethod

    示例:

            //ClassName::instanceMethod  类的实例方法:把表达式的第一个参数当成instanceMethod的调用者,其他参数作为该方法的参数
            BiPredicate<String, String> sbp = String::equals;
            //等效
            BiPredicate<String, String> sbp2 = (x, y) -> x.equals(y);
            boolean test = sbp.test("a", "A");

    4、构造函数

    无参的构造方法就是类::实例方法模型,如:

            Supplier<User> us = User::new;
            //等效
            Supplier<User> us2 = () -> new User();
            //获取对象
            User user = us.get();

    当有参数时

            //一个参数,参数类型不同则会编译出错
            Function<Integer, User> uf = id -> new User(id);
            //或加括号
            Function<Integer, User> uf2 = (id) -> new User(id);
            //等效
            Function<Integer, User> uf3 = (Integer id) -> new User(id);
            User apply = uf.apply(61888);
    
            //两个参数
            BiFunction<Integer, String, User> ubf = (id, name) -> new User(id, name);
            User 狂欢happy = ubf.apply(618, "狂欢happy");

    5、继承及实现具有相同默认方法的父类或接口问题

    接口A:

    public interface A {
    
        String hi();
    
        String greet();
    
        default void hello() {
            System.out.println("A.hello");
        }
    
    }

    接口B:

    public interface B {
    
        String hi();
    
        String hh();
    
        default void hello() {
            System.out.println("B.hello");
        }
    
    }

    类C实现A,B:

    public class C implements A, B{
    
        @Override
        public String hi() {
            return "C.hi";
        }
    
        @Override
        public String greet() {
            return "C.greet";
        }
    
        @Override
        public String hh() {
            return "C.hh";
        }
    
        /**
         * 子类优先继承父类的方法, 如果父类没有相同签名的方法,才继承接口的默认方法。
         * 编译报错解决1:覆盖法
         */
        @Override
        public void hello() {
            System.out.println("C.hello");
        }
    
        /**
         * 编译报错解决2:指定实现的父接口
         */
    //    @Override
    //    public void hello() {
    //        A.super.hello();
    ////        B.super.hello();
    //    }
    
    }

    此时若不处理hello方法时,类C将编译出错,解决方式要么覆盖,要么指定实现父接口的该方法。

    进一步测试继承具有相同方法的父类:

    类D:

    public class D {
    
        public void hello() {
            System.out.println("D.hello");
        }
    }

    类C继承类D:

    public class C extends D implements A, B{
    
        @Override
        public String hi() {
            return "C.hi";
        }
    
        @Override
        public String greet() {
            return "C.greet";
        }
    
        @Override
        public String hh() {
            return "C.hh";
        }
    
        /**
         * 子类优先继承父类的方法, 如果父类没有相同签名的方法,才继承接口的默认方法。
         * 编译报错解决1:覆盖法
         */
    //    @Override
    //    public void hello() {
    //        System.out.println("C.hello");
    //    }
    
        /**
         * 编译报错解决2:指定实现的父接口
         */
    //    @Override
    //    public void hello() {
    //        A.super.hello();
    ////        B.super.hello();
    //    }
    
    }

    此时若不覆盖或指定父接口的方法时,类C将继承类D的hello方法。

    6、总结

    java8引入lambda表达式是接收了函数式编程语言的思想,例如scala之类的,它将函数视为一等公民,可以使用高阶函数等。

    和指令式编程相比,函数式编程强调函数的计算比指令的执行重要。

    和过程化编程相比,函数式编程里函数的计算可随时调用。
    写在最后,lambda表达式可以使代码看起来简洁,但一定程度上增加了代码的可读性以及调试的复杂性,所以在使用时应尽量是团队都熟悉使用,要么干脆就别用,不然维护起来是件较痛苦的事。
     

    源码参照Github

  • 相关阅读:
    Windows下python3安装pip管理包(转贴)
    AnyConnect removes "Connections" tab from IE Settings solution
    split陷阱
    java不足前面补0
    linux定时任务cron配置说明
    maven常用的plugin
    linux部署两个tomcat
    spring定时任务配置,以及不执行的解决办法
    windows10 自带笔记本键盘禁止和开启
    spring task的定时任务突然断了
  • 原文地址:https://www.cnblogs.com/kingsonfu/p/11047116.html
Copyright © 2011-2022 走看看