JDK8的lambda表达式、方法引用

(部分转自:https://www.cnblogs.com/xiaoxi/p/7099667.html)

1. lambda表达式

  以前定义一个Thread:

1 final int i = 0;
2 new Thread(new Runnable() {
3     @Override
4     public void run() {
5         System.out.println("i = " + i);
6     }
7 }).start();

  lambda表达式定义:

1 int i = 0;
2 new Thread(() -> System.out.println("i = " + i));

  概述:lambda表达式除了使代码简洁外,还为了消除单方法接口实现的匿名内部类。

  结构:

  注意:  

  •   lambda要求实现的接口中只有一个方法(该接口称为函数式接口),可以知道如果要得到一个接口的对象,则需要创建一个类并实现接口再实例化对象,而lambda则可以直接提供对象。
  •   参数体内如果只有一个参数则可以省略小括号,方法体内如果只有一条语句则可以省略花括号。
  •   参数体内可以省略数据类型,编译器可以推导出参数类型,例如:(first, second)-> {first.length() - second.length()}。
  •   方法体内必须有return含义,即可以显式地return或隐式地return(编译器会根据上下文推导得出return返回的数据类型),例如上。
  • lambda内部引用外部的变量,该变量必须是最终变量,即初始化后不再为它赋新值。

2. 方法引用

  方法引用是直接访问类或者实例的方法、类方法、静态方法;提供了一种引用而不执行方法的方式;计算时,方法引用会创建函数式接口的一个实例。

  方法引用等价于lambda表达式,只是lambda表达式更为简洁的写法,当lambda表达式只是执行一个方法调用时则不用lambda。lambda中如果参数和方法内使用的参数一致即可在方法引用中忽略参数。

// lambda写法:
Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2));
// 方法引用写法
Arrays.sort(stringsArray, String::compareToIgnoreCase);

  详细的例子,首先定义一个Person类,如下:

package com.demo.model;

import java.time.LocalDate;

public class Person {

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

    String name;
    LocalDate birthday;

    public LocalDate getBirthday() {
        return birthday;
    }

    public static int compareByAge(Person a, Person b) {
        return a.birthday.compareTo(b.birthday);
    }

    @Override
    public String toString() {
        return this.name;
    }
}

  假设我们有一个Person数组,并且想对它进行排序,这时候,我们可能会这样写:

  其中,Arrays类的sort方法定义如下:

public static <T> void sort(T[] a, Comparator<? super T> c)

  这里,我们首先要注意Comparator接口是一个函数式接口,因此我们可以使用Lambda表达式,而不需要定义一个实现Comparator接口的类,并创建它的实例对象,传给sort方法。

  使用Lambda表达式,未调用已存在的方法

public void test1() {
    Person[] pArr = new Person[]{
            new Person("003", LocalDate.of(2016,9,1)),
            new Person("001", LocalDate.of(2016,2,1)),
            new Person("002", LocalDate.of(2016,3,1)),
            new Person("004", LocalDate.of(2016,12,1))};

    //使用lambda表达式
    Arrays.sort(pArr, (Person a, Person b) -> {
        return a.getBirthday().compareTo(b.getBirthday());
    });

    System.out.println(Arrays.asList(pArr));
}

  然而,在以上代码中,关于两个人生日的比较方法在Person类中已经定义了,因此,我们可以直接使用已存在的Person.compareByAge方法。

  使用Lambda表达式,调用已存在的方法

public void test2() {
    Person[] pArr = new Person[]{
            new Person("003", LocalDate.of(2016,9,1)),
            new Person("001", LocalDate.of(2016,2,1)),
            new Person("002", LocalDate.of(2016,3,1)),
            new Person("004", LocalDate.of(2016,12,1))};

    //使用lambda表达式和类的静态方法
    Arrays.sort(pArr, (a ,b) -> Person.compareByAge(a, b));

    System.out.println(Arrays.asList(pArr));
}

  因为这个Lambda表达式调用了一个已存在的方法,因此,我们可以直接使用方法引用来替代这个Lambda表达式。

  使用方法引用

public void test3() {
    Person[] pArr = new Person[]{
            new Person("003", LocalDate.of(2016,9,1)),
            new Person("001", LocalDate.of(2016,2,1)),
            new Person("002", LocalDate.of(2016,3,1)),
            new Person("004", LocalDate.of(2016,12,1))};

    //使用方法引用,引用的是类的静态方法
    Arrays.sort(pArr, Person::compareByAge);

    System.out.println(Arrays.asList(pArr));
}

3. 方法引用几种类型:

  

  (1) 静态方法引用

  组成语法格式:ClassName::staticMethodName

  我们前面举的例子Person::compareByAge就是一个静态方法引用。

  例子:

  String::valueOf   等价于lambda表达式 (s) -> String.valueOf(s)

  Math::pow       等价于lambda表达式  (x, y) -> Math.pow(x, y);

  (2) 对象方法引用

  a.实例上的实例方法引用

  组成语法格式:instanceReference::methodName

  如下示例,引用的方法是myComparisonProvider 对象的compareByName方法。

class ComparisonProvider{

    public int compareByName(Person a, Person b){
        return a.getName().compareTo(b.getName());
    }

    public int compareByAge(Person a, Person b){
        return a.getBirthday().compareTo(b.getBirthday());
    }
}

ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName); 

  b.超类上的实例方法引用

  组成语法格式:super::methodName

  方法的名称由methodName指定,通过使用super,可以引用方法的超类版本。

  例子:

  还可以捕获this 指针,this :: equals  等价于lambda表达式  x -> this.equals(x);

  c.类型上的实例方法引用

  组成语法格式:ClassName::methodName

  注意:

  若类型的实例方法是泛型的,就需要在::分隔符前提供类型参数,或者(多数情况下)利用目标类型推导出其类型。

  静态方法引用和类型上的实例方法引用拥有一样的语法。编译器会根据实际情况做出决定。一般我们不需要指定方法引用中的参数类型,因为编译器往往可以推导出结果,但如果需要我们也可以显式在::分隔符之前提供参数类型信息。

  例子:

  String::toString 等价于lambda表达式 (s) -> s.toString()

  这里不太容易理解,实例方法要通过对象来调用,方法引用对应Lambda,Lambda的第一个参数会成为调用实例方法的对象。

  (3) 任意对象(属于同一个类)的实例方法引用

  如下示例,这里引用的是字符串数组中任意一个对象的compareToIgnoreCase方法。

String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

  (4) 构造方法引用

构造方法引用又分构造方法引用和数组构造方法引用。

  a. 构造方法引用(也可以称作构造器引用)

  组成语法格式:Class::new

  构造函数本质上是静态方法,只是方法名字比较特殊,使用的是new 关键字

  例子:

  String::new, 等价于lambda表达式 () -> new String()

package com.demo;

public interface MyFunc1 {

    MyClass func(int n);

}
package com.demo;

public class MyClass {

    private int val;

    MyClass(int v) {
        val = v;
    }

    MyClass(){
        val = 0;
    }

    public int getValue() {
        return val;
    }

}
package com.demo;

public class ConstructorRefDemo {

    public static void main(String[] args) {
        MyFunc1 myClassCons = MyClass :: new;
        MyClass mc = myClassCons.func(100);
        System.out.println("val in mc is: " + mc.getValue());
    }
}

  输出结果:

val in mc is: 100

  b.数组构造方法引用

  组成语法格式:TypeName[]::new

  例子:

  int[]::new 是一个含有一个参数的构造器引用,这个参数就是数组的长度。等价于lambda表达式  x -> new int[x]。

  假想存在一个接收int参数的数组构造方法

IntFunction<int[]> arrayMaker = int[]::new;
int[] array = arrayMaker.apply(10) // 创建数组 int[10]

  

原文地址:https://www.cnblogs.com/chenloveslife/p/9313305.html

时间: 2024-11-05 21:43:55

JDK8的lambda表达式、方法引用的相关文章

jdk1.8新特性Lambda表达式方法引用

前言 在之前我们接触了JDK1.8引入的新特新lambda表达式没在某种程度上,它可以简化我们的代码,帮助我们快速的编写代码,但在这其中我们之前的编写方式并不是lambda表达式最简洁的方式,而在头屑情况下我们可以使用lambda表达式的方法引用是代码进一步简洁化. 一.方法引用: 在java中方法引用主要是用来替代lambda表达式进一步简化代码,方法引用符号的写法是两个冒号“::”,其中方法引用的用法有一下几种. 1.对象名称::成员方法 如果一个对象中有一个成员方法,就好就是lambda表

深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)

最近看了一下java 8的一些新特性,其中最重要的莫过于Lambda表达式了,通过一阵子的学习,原本准备自己写一篇博客的,后来阅读了一位学长翻译过来的博客(原文是Brain Goetz的State of Lambda,下面会给出原文链接),觉得写的十分完美,把我想要写的和我没想到的都罗列了出来,就把这个分享给大家了. 注:原译文见  http://lucida.me/blog/java-8-lambdas-insideout-language-features/ 英语原版见:http://cr.

[转]深入理解Java 8 Lambda(语言篇——lambda,方法引用,目标类型和默认方法)

以下内容转自: 作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-language-features 本文谢绝转载,如需转载需征得作者本人同意,谢谢. -------------------------------------内容分割线--------------------------------------------------------- 关于 本文是深入

JDK8新特性04 方法引用与构造器引用

import java.io.PrintStream; import java.util.Comparator; import java.util.function.*; /** * 一.方法引用 * lambda方法体之 --> 方法引用:若Lambda 体中的内容有方法已经实现了,我们可以使用"方法引用" * (可以理解为方法引用是Lambda 表达式的另外一种表现形式) * * * 主要有三种语法格式: * * 对象::实例方法名 * * 类::静态方法名 * * 类::实

通过字节码分析JDK8中Lambda表达式编译及执行机制

关于Lambda字节码相关的文章,很早之前就想写了,[蜂潮运动]APP 产品的后端技术,能快速迭代,除了得益于整体微服架构之外,语言层面上,也是通过Java8的lambda表达式的运用以及rxJava响应式编程框架,使代码更加简洁易维护,调用方式更加便捷.本文将介绍JVM中的方法调用相关的字节码指令,重点解析JDK7(JSR-292)之后新增的invokedynamic指令给lambda表达式的动态调用特性提供的实现机制,最后再探讨一下lambda性能方面的话题. 方法调用的字节码指令 在介绍i

JDK8 的 Lambda 表达式原理

JDK8 使用一行 Lambda 表达式可以代替先前用匿名类五六行代码所做的事情,那么它是怎么实现的呢?从所周知,匿名类会在编译的时候生成与宿主类带上 $1, $2 的类文件,如写在 TestLambda 中的匿名类产生成类文件是 TestLambda$1.class, TestLambda$2.class 等. 我试验了一下,如果使用的是 Lambda 表达式并不会生成额外的类文件,那么字节码里是什么样子的?来看下用  javap -c 反编译出下面文件产生的 TestLambda.class

jdk8系列二、方法引用

一.方法引用 方法引用使得开发者可以直接引用现存的方法.Java类的构造方法或者实例对象.方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码. 例子中,Car类是不同方法引用的例子,可以帮助读者区分四种类型的方法引用. package com.study.demo.TestRefernce; import java.util.Arrays; import java.util.List; import java.util.function.Sup

Jdk8新特性之方法引用

方法引用的格式 符号表示 : :: 符号说明 : 双冒号为方法引用运算符,而它所在的表达式被称为方法引用.应用场景 : 如果Lambda所要实现的方案 , 已经有其他方法存在相同方案,那么则可以使用方法引用.方法引用在JDK 8中使用方式相当灵活,有以下几种形式: 1. instanceName::methodName 对象::方法名2. ClassName::staticMethodName 类名::静态方法3. ClassName::methodName 类名::普通方法4. ClassNa

[二] java8 函数式接口详解 函数接口详解 lambda表达式 匿名函数 方法引用使用含义 函数式接口实例 如何定义函数式接口

函数式接口详细定义 package java.lang; import java.lang.annotation.*; /** * An informative annotation type used to indicate that an interface * type declaration is intended to be a <i>functional interface</i> as * defined by the Java Language Specificat