Java函数式编程-2.Lambda表达式

1.什么是lambda表达式?

首先看一段比较熟悉的代码片断,目的是为按钮注册一个事件监听器,当按钮被点击时输出一个提示信息"button clicked",java

Button button = new Button();
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("button clicked");
    }
});

这段自己没有什么问题,可是代码量相对有点多并且语义表达上也不够清新。那么什么样的表达才是清晰的呢?Jdk8给我带来了一种全新的思路,可让咱们更加优雅的实现上述功能,咱们看下述Lambda代码。express

Button button = new Button();
 button.addActionListener(e-> System.out.println("button clicked"));

2.lambda 表达式3种表现形式

  无参数表达式: () -> System.out.println(“hello world!”)
  单个参数表达式 :  (String  sayHello) -> System.out.println(sayHello)
  多个参数表达式:   (int x, int y) -> x + y

  须要注意的是以上三种基本形式能够根据“是否有显示声明参数类型”、“是否有返回值”、“是否省略()”等又会衍生出若干变化。数组

3.lambda表达式值引用

   lambda表达式操做的是对象的引用值而不是对象自己,怎么理解呢?匿名内部类若是引用所在方法中变量那么该变量必须声明为final类型,也就是对象只能对赋值一次。相似的lambda表达式引用所在方法中的变量也必须是final类型,表现形式上能够显示声明final 也能够不显示声明,可是该变量必须是一个既成事实上的final变量。ide

public static void sayHello(String name) {
        if (Objects.isNull(name)) {
            name = "kity";
        }
        ActionListener act = event -> System.out.println("hello " + name);
        ....
    }

上述代码变异会提示 Variable used in lambda expression should be final or effectively final。函数

4.lambda表达式方法引用

之前咱们关注更多的是对象引用,jdk8以后新增了方法引用,须要使用关键字 “::”,这是jdk8咱们须要重点关注的。一下咱们详细列举6种方法引用的详细格式。this

  • 静态方法引用

格式   类名::静态方法名spa

    注意事项:
    被引用方法参数列表和函数式接口中方法的参数一致
    接口的抽象方法没有返回值,引用的方法能够有返回值也能够没有
    接口的抽象方法有返回值,引用方法必须有同类型的返回值code

interface Transfer {
        int run(String string);
    }

    public static void main(String[] args) {
        printStr("1", Integer::valueOf);
    }

    public static void printStr(String str, Transfer t) {
        int num = t.run(str);
        System.out.println(num);
    }
  • 对象方法引用

格式   对象::方法名orm

@FunctionalInterface
    interface Action {
        String run(Integer num);
    }

    public static void main(String[] args) {
        Action t2 = new Person()::walking;
        System.out.println(t2.run(5));
    }
    class Person {
        public String walking(Integer num) {
            return "go ".concat(String.valueOf(num)).concat(" step ...");
        }
    }
  • 构造方法引用

格式   类名::new对象

interface Action {
        Person init(String string);
    }

    class Person {
        String name;

        public Person(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }

    public static void main(String[] args) {
        Action t2 = Person::new;
        Person p2 = t2.init("李四");
        System.out.println(p2);
    }
  • 数组构造方法引用

格式   数据类型[]::new

interface Action {
        String[] run(int len);
    }

    public static void main(String[] args) {
        Action action = String[]::new;
        String[] arr = action.run(5);
        System.out.println(arr.length);
    }
  • 特定类型的方法引用

格式   类名::非静态方法

ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list, "a", "C", "B", "d");
    Collections.sort(list, String::compareToIgnoreCase);
    System.out.println(list);
  • 类中方法调用父类或本类方法引用

格式   this::方法名
          super::方法名

interface Action {
    void init();
}

class Father {
    public void buy() {
        System.out.println("买东西");
    }
}

class Son extends Father {
    public void buy() {
        System.out.println("买糖");
    }

    public void run() {
        Action action1 = this::buy;
        action1.init();
        Action action2 = super::buy;
        action2.init();
    }
}

public static void main(String[] args) {
        Son s = new Son();
        s.run();
    }

5.lambda函数接口

函数式接口是 Java8 引入的一个新特性,是一种特殊的接口:SAM类型的接口(Single Abstract Method),但本质上仍是接口。相比较于其余接口,函数式接口有且只能有一个抽象方法。只要接口中出现多个抽象方法,那么就不能称之为函数式接口,运行的时候就会报错。为此 Java8 提供了一个新的注解@FunctionalInterface,若是接口被这个注解标注,就说明该接口是函数式接口,若是有多于一个的抽象方法,在编译的时候就会报错。可是这个注解不是必需的,只要接口符合函数式接口的定义,那么这个接口就是函数式接。

Java中主要的函数接口

               接口                              参数                                     返回类型                                         描述                      
Predicate<T>                 T               boolean 断言型接口
Consumer<T>                 T                void 消费型接口
Function<T,R>                 T                  R 功能型接口
Supplier<T>              None                 T 供给型接口
UnaryOperator<T>               T                 T 一元运算
BinaryOperator<T>           (T,T)                 T 二元运算

6.lambda函数类型推断

Lamda表达式是函数式接口的一个实例,然而咱们并无从Lambda表达式中看到有关函数式接口的任何信息,于是有必要弄清楚Lambda的类型是什么?它实现了哪一个函数式接口?其实Lambda表达式的类型是从上下文推断出来的,这里的上下文包括以下3种: 赋值上下文 方法调用上下文(参数与返回值) 类型转换上下文 经过这3种上下文就能够推断出Lambda表达式的目标类型(与之对应的函数式接口)。

相关文章
相关标签/搜索