Java8的Lambda学习

关于Lambda表示在工作学习中会经常用到,但并没有全面的去了解。在这里做一个较为详细的记录供以后学习查阅。主要参考Java 8 Lambda 表达式

引言


Java8之前,我们在使用Runnale创建线程的时候,经常需要将Runable实例传入new Thread中。一般采用匿名内部类将函数作为参数的形式传入

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Before Java8,There is no Lambda expression!");
    }
}).start();

之后我们可以使用Java8的新特性Lambda这样写:

new Thread( () -> System.out.println("In Java8, There is Lambda expression!") ).start();

这里相当于:

Runable runable = () -> System.out.println("In Java8, There is Lambda expression!");

可见Lambda表达式的强大之处,下面将以详细记录.


1、Java8的Lambda特性

1、Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
2、Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
3、使用 Lambda 表达式可以使代码变的更加简洁紧凑。

2、Lambda表达式的语法

(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }

比如:

(int a, int b) -> {  return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }

3、Lambda表达式的特征

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

这里e的类型就是由编译器推理得到的,不需要声明类型,当然也可以声明类型,比如:

Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
Arrays.asList( "a", "b", "d" ).forEach( e -> {
    System.out.print( e );
    System.out.print( e );
} );
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指明表达式返回了一个数值。并且如果Lambda表达式中的语句块只有一行,则可以不用使用return语句

如下两个是一样的效果

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );
Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
    int result = e1.compareTo( e2 );
    return result;
} );

4、Lambda变量作用域

Lambda表达式只能引用外部被final修饰的局部变量,换句话说在Lambda表达式中我们不能修改定义在外的局部变量。

public class LambdaTest {

    public static void main(String[] args) {
        //final如果不写的话,Lambda表达式会默认该变量为final
        final String string="Hello ";

        HelloWorld test = (String message)->System.out.println(message+"World!");
        test.print(string);
    }
    @FunctionalInterface
    interface HelloWorld {
        void print(String str);
        default void print2() {

        }
    }
}

5、函数式接口

  • 函数式接口(FunctionImplement)是一种只含有一个抽象方法声明的接口。类似于Java中的Marker
    Interface
    标记类型接口,比如java.io.Serializable等都是没有方法声明或属性声明的接口,主要用于通过instanceof就直接能探测一个实例是否是一个特定接口的实例。
  • 那么java.lang.Runable即是一种函数式接口,在接口中只有void run()方法。
  • 简单来说之前我们使用的匿名内部类传入参数,实则是使用匿名内部类来实例化函数式接口的对象。而之后的Lambda表达式可以更进一步简化代码

我们在看引言当中利用Runable创建线程的例子,后面写道:

Runable runable = () -> System.out.println("In Java8, There is Lambda expression!");

其实这里就是利用Lambda表达式实现实例化函数式接口的对象,比如我们自定义一个函数式接口,增加注解@FunctionalInterface,也可以不用注解,只需要符合函数式接口的要求,否则会报错!

@FunctionalInterface
interface HelloWold {
    void print();
}

定义好函数式接口之后,我们可以使用Lambda Expression

public static void main(String[] args) {
    //实现函数式接口的对象
    HelloWold test = ()->System.out.println("HelloWorld!");
    test.print();
}

如果接口不符合要求,则会报错:
这里写图片描述

6、断言(Predicate)函数式接口

Predicate函数式接口的主要作用就是提供一个test方法,接受一个参数返回一个布尔类型,PredicateStream API中进行一些判断的时候经常用到。主要用于过滤一些符合条件的逻辑

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

猜你喜欢

转载自blog.csdn.net/Mynewclass/article/details/80169476