java8的方法引用详解(让你的代码看起来高大上)

简介: 在上一篇文章中曾经介绍到了java8中的Lambda表达式,这篇文章是基于Lambda表达式来叙述的。主要讲解方法引用

一、什么是方法引用


在Lambda表达式中,将其划分了几块。这一行就是lambda表达式。() -> System.out.println("使用Lambda表达式");下面我们对lambda的格式进行一个介绍:


(1)左边括号:lambda的形参列表,就好比是我们定义一个接口,里面有一个抽象方法,这个抽象方法的形参列表。


(2)箭头:lambda的操作符,所以你看见这个箭头心中知道这是一个lambda表达式就可以了。


(3)右边lambda体:就好比是我们实现了接口中的抽象方法。

在最后一块中,有时候,lambda体可能仅仅调用一个已存在的方法,而不做任何其它事,对于这种情况,通过一个方法名字来引用这个已存在的方法会更加清晰。


所以我们来总结:方法引用是一个更加紧凑,易读的 Lambda 表达式,注意方法引用是一个 Lambda 表达式,其中方法引用的操作符是双冒号 "::"。


二、举例演示


1、我们首先定义一个User类

public class Person {
    String name;
    LocalDate birthday;
    public Person(String name, LocalDate birthday) {
        this.name = name;
        this.birthday = 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进行排序。


2、Lambda表达式写法


public class RefSort {
    public static void main(String[] args) {
        Person[] pArr = new Person[]{
            new Person("1", LocalDate.of(2019, 12, 1)),
            new Person("2", LocalDate.of(2019, 12, 2)),
            new Person("3", LocalDate.of(2019, 12, 3)),
            new Person("4", LocalDate.of(2019, 12, 4))};
        Arrays.sort(pArr, (Person a, Person b) -> {
            return a.getBirthday().compareTo(b.getBirthday());
        });
        System.out.println(Arrays.asList(pArr));
    }
}

我们使用lambda表达式可以直接进行比较。现在我们使用方法引用。

public class RefSort { 
    public static void main(String[] args) {
        Person[] pArr = new Person[]{ 
            new Person("1", LocalDate.of(2019, 12, 1)),
            new Person("2", LocalDate.of(2019, 12, 2)),
            new Person("3", LocalDate.of(2019, 12, 3)),
            new Person("4", LocalDate.of(2019, 12, 4))};
        Arrays.sort(pArr, Person::compareByAge);
        System.out.println(Arrays.asList(pArr));
    }
}

这下子代码是不是更加的简洁了。我们相当于把lambda表达式进行了改变。下面我们就来好好地讲解一下方法引用是如何使用的。


三、方法引用分类


先来说一下方法引用使用到的操作符“::”,这个操作符把方法引用分成两边,左边是类名或者某个对象的引用,右边是方法名。引用方法有下面几种方式:


(1)对象引用::实例方法名

(2)类名::静态方法名

(3)类名::实例方法名

(4)类名::new

(5)类型[]::new

我们对这5种方式分别来叙述。


1、对象引用::实例方法名


public class PersonCompare {
    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());
    }
    @Test
    public void test(){
        Person[] pArr = new Person[]{
                new Person("1", LocalDate.of(2019, 12, 1)),
                new Person("2", LocalDate.of(2019, 12, 2)),
                new Person("3", LocalDate.of(2019, 12, 3)),
                new Person("4", LocalDate.of(2019, 12, 4))};
        PersonCompare personCompare = new PersonCompare();
        Arrays.sort(pArr, personCompare::compareByName);
    }
}

我们创建了一个PersonCompare对象,调用了其内部的compareByName实例方法。


2、类名::静态方法名


举几个例子:


String::valueOf,等价于 Lambda:s -> String.valueOf(s)

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

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

Function<Long, Long> f = Math::abs;
Long result = f.apply(-3L);123

Math是一个类而abs为该类的静态方法。Function中的唯一抽象方法apply方法参数列表与abs方法的参数列表相同,都是接收一个Long类型参数。


3、类名::实例方法名


若Lambda表达式的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,就可以使用这种方法:

BiPredicate<String, String> b = String::equals;
b.test("abc", "abcd");

String是一个类而equals为该类的定义的实例方法。BiPredicate中的唯一抽象方法test方法参数列表与equals方法的参数列表相同,都是接收两个String类型参数。


4、类名::new


在引用构造器的时候,构造器参数列表要与接口中抽象方法的参数列表一致。对应的 Lambda:() -> new String()。

class PersonFactory {
    private Supplier<Person> supplier;
    public PersonFactory(Supplier<Person> supplier) {
        this.supplier = supplier;
    }
    public Person getPerson() {
        return supplier.get();
    }
}
PersonFactory factory = new PersonFactory(Person::new);
Person p1 = factory.getPerson();

上面这段代码的功能就是使用PersonFactory工厂,然后使用Person::new创建一个Person实例。


5、类型[]::new


引用数组和引用构造器很像,格式为 类型[]::new,等价于 lambda 表达式 x -> new int[x]。其中类型可以为基本类型也可以是类。

Function<Integer, int[]> fun = int[]::new;
int[] arr = fun.apply(10);
Function<Integer, Integer[]> fun2 = Integer[]::new;
Integer[] arr2 = fun2.apply(10);

OK。方法引用就是这么简单。

相关文章
|
2月前
|
消息中间件 Java Kafka
在Java中实现分布式事务的常用框架和方法
总之,选择合适的分布式事务框架和方法需要综合考虑业务需求、性能、复杂度等因素。不同的框架和方法都有其特点和适用场景,需要根据具体情况进行评估和选择。同时,随着技术的不断发展,分布式事务的解决方案也在不断更新和完善,以更好地满足业务的需求。你还可以进一步深入研究和了解这些框架和方法,以便在实际应用中更好地实现分布式事务管理。
|
2月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
79 9
|
2月前
|
Java
在Java中实现接口的具体代码示例
可以根据具体的需求,创建更多的类来实现这个接口,以满足不同形状的计算需求。希望这个示例对你理解在 Java 中如何实现接口有所帮助。
91 38
|
11天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
33 3
|
2月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
54 24
|
18天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
54 2
|
1月前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
76 5
|
1月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
55 5
|
2月前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
2月前
|
安全 Java 开发者
Java中WAIT和NOTIFY方法必须在同步块中调用的原因
在Java多线程编程中,`wait()`和`notify()`方法是实现线程间协作的关键。这两个方法必须在同步块或同步方法中调用,这一要求背后有着深刻的原因。本文将深入探讨为什么`wait()`和`notify()`方法必须在同步块中调用,以及这一机制如何确保线程安全和避免死锁。
46 4