Java8 - lambda 表达式

lambda表达式

为何须要lambda 表达式java

函数对 Java 而言并不重要,在 Java 的世界里,函数没法独立存在。Lambda 表达式为 Java 添加了缺失的函数式编程特色,使咱们能将函数当作一等公民看待。尽管不彻底正确,咱们很快就会见识到 Lambda 与闭包的不一样之处,可是又无限地接近闭包。在支持一类函数的语言中,Lambda 表达式的类型将是函数。可是,在 Java 中,Lambda 表达式是对象,他们必须依附于一类特别的对象类型——函数式接口(functional interface)。express

 

什么是lambda 表达式编程

Java 中的 Lambda 表达式一般使用 (argument) -> (body) 语法书写,例如:闭包

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

如下是一些 Lambda 表达式的例子:ide

(int a, int b) -> { return a + b; }函数式编程

() -> System.out.println("Hello World");函数

(String s) -> { System.out.println(s); }ui

() -> 42this

() -> { return 3.1415 };spa

让咱们了解一下 Lambda 表达式的结构。

  • 一个 Lambda 表达式能够有零个或多个参数

  • 参数的类型既能够明确声明,也能够根据上下文来推断。例如:(int a)与(a)效果相同

  • 全部参数需包含在圆括号内,参数之间用逗号相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)

  • 空圆括号表明参数集为空。例如:() -> 42

  • 当只有一个参数,且其类型可推导时,圆括号()可省略。例如:a -> return a*a

  • Lambda 表达式的主体可包含零条或多条语句

  • 若是 Lambda 表达式的主体只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致

  • 若是 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(造成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空

lambda表达式举例,

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class LambdaTest {


    /**
     * (arg1, arg2...) -> { body }
     * <p>
     * (type1 arg1, type2 arg2...) -> { body }
     *
     * @param args
     */
    public static void main(String[] args) {

        FunctionalWorkInterface.class.getName();

        /**
         * lambda 表达式
         */
        Arrays.asList("a", "b", "d").forEach(e -> {
            System.out.print(e);
        });

        Arrays.asList(1, 2, 8, 4, 5, 7).forEach(e -> System.out.println(e));

        Arrays.asList("a", "b", "d").sort((e1, e2) -> e1.compareTo(e2));


        List<Integer> arr = Arrays.asList(1, 2, 8, 4, 5, 7);

        /**
         * 定义一个lambda 表达式
         * 集中不一样形式的 lambda 表达式定义方式
         */
        Comparator<Integer> comparator = (Integer a, Integer b) -> {
            return a.compareTo(b);
        };


        arr.sort(comparator);

        arr.sort((a, b) -> {
            return a - b;
        });

        // 不须要return
        arr.sort((a, b) -> a - b);

        arr.forEach(e -> System.out.println(e));


        //旧方法:
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello from thread");
            }
        }).start();

        //新方法:
        new Thread(
                () -> System.out.println("Hello from thread")
        ).start();

    }
}

 

函数式接口(Functional interface

@FunctionalInterface是 Java 8 新加入的一种接口,用于指明该接口类型声明是根据 Java 语言规范定义的函数式接口。Java 8 还声明了一些 Lambda 表达式可使用的函数式接口,当你注释的接口不是有效的函数式接口时,会产生@FunctionalInterface 编译层面的错误。

好比 下面这个接口就是函数式接口java.util.Comparator ,

@FunctionalInterface
public interface Comparator<T> {
  
    int compare(T o1, T o2);
 
    boolean equals(Object obj);

    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }

    default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }

    default <U> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        return thenComparing(comparing(keyExtractor, keyComparator));
    }
}

根据定义,函数式接口只能有一个抽象方法,若是你尝试添加第二个抽象方法,将抛出编译时错误。例如:

image.png

Error:(3, 1) java: 意外的 @FunctionalInterface 注释

com.common.FunctionalWorkInterface 不是函数接口

在 接口 com.common.FunctionalWorkInterface 中找到多个非覆盖抽象方法

存在多个抽象方法就会报错。

 

下面是 函数式接口 注解的用法

package com.common;

/**
 * 使用函数式接口 注解标注一个接口 ,该接口只能有一个抽象方法。
 */
@FunctionalInterface
interface FunctionalWorkInterface {

    void doSomeWork();

}

public class TestMain {

    public static void execute(FunctionalWorkInterface worker) {
        worker.doSomeWork();
    }

    public static void main(String[] args) {

        //invoke doSomeWork using Annonymous class
        execute(new FunctionalWorkInterface() {
            @Override
            public void doSomeWork() {
                System.out.println("do some work...");
            }
        });

        //invoke doSomeWork using Lambda expression
        execute(() -> System.out.println("do some work from lambda..."));
    }

}

这上面的例子里,建立了自定义的函数式接口并与 Lambda 表达式一块儿使用。

execute() 方法如今能够将 Lambda 表达式做为参数。

 

Lambda 表达式与匿名类的区别

使用匿名类与 Lambda 表达式的一大区别在于关键词的使用。对于匿名类,关键词 this 解读为匿名类,而对于 Lambda 表达式,关键词 this 解读为写就 Lambda 的外部类。

Lambda 表达式与匿名类的另外一不一样在于二者的编译方法。Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有函数,它使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法。

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class LambdaThisTest {

    public void sort(List<Integer> list) {

        list.sort((a, b) -> {
            System.out.print(this.getClass().getName());
            return a.compareTo(b);
        });
    }

    public void sort02(List<Integer> list) {

        list.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(this.getClass().getName());
                return o1.compareTo(o2);
            }
        });
    }

    public static void main(String[] args) {
        LambdaThisTest lambdaThisTest = new LambdaThisTest();
        lambdaThisTest.sort(Arrays.asList(1, 5, 6));
        lambdaThisTest.sort02(Arrays.asList(1, 5, 6));
    }
}

输出,

com.common.LambdaThisTestcom.common.LambdaThisTestcom.common.LambdaThisTest$1

com.common.LambdaThisTest$1

===========END===========

相关文章
相关标签/搜索