java8 lambda表达式 java8 函数接口 java8 Optional使用总结 Java 8 时间日期使用

【前言】 java8新特性html

java8 函数接口

java8 Optional使用总结

Java 8 时间日期使用

 

java8中一个很是重要的特性就是lambda表达式,咱们能够把它当作是一种闭包,它容许把函数当作参数来使用,是面向函数式编程的思想,必定程度上可使代码看起来更加简洁。例如之前咱们使用匿名内部类来实现代码:java

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

使用lambda则更加简洁:git

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

一、lambda表达式语法

    (paramters) -> expression;

或者github

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

二、lambda表达式特征

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

示例:express

        //入参为空
        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.1 对象::实例方法,将lambda的参数当作方法的参数使用闭包

objectName::instanceMethod

示例:app

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

3.2 类::静态方法,将lambda的参数当作方法的参数使用编程语言

ClassName::staticMethod

示例:ide

        //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");

四、构造函数

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

        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");

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

接口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方法。

六、总结

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

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

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

源码参照Github

相关文章
相关标签/搜索