Java 方法引用与ambda表达式的联系

目录
  • 方法引用是什么
  • 冗余的Lambda场景
  • 使用方法引用改进
  • 使用方法
    • 通过对象名引用成员方法
    • 通过类名称引用静态方法
    • 通过super引用成员方法
    • 通过this引用成员方法
    • 类的构造器引用
    • 数组的构造器引用

方法引用是什么

方法引用通过方法的名字来指向一个方法。方法引用可以使语言的构造更紧凑简洁,减少冗余代码。 方法引用同样是Java 8 引入的新特性,而且和Lambda表达式有着不小的联系,它同样可以根据上下文进行推导,进而可以简化代码,可以说是Lambda的孪生兄弟。

下面我会通过最简单的一个例子来展开方法引用:

冗余的Lambda场景

@FunctionalInterface
public interface Printable {
	void print(String str);
}

先定义一个函数式接口,在 Printable 接口当中唯一的抽象方法 print 接收一个字符串参数,目的就是为了打印显示它。

那么通过Lambda来使用它的代码很简单:

public class Demo01PrintSimple {
	private static void printString(Printable data) {
		data.print("Hello, World!");
	}
public static void main(String[] args) {
	printString(s ‐> System.out.println(s));
	}
}

其中 printString 方法只管调用 Printable 接口的 print 方法,而并不管 print 方法的具体实现逻辑会将字符串打印到什么地方去。而 main 方法通过Lambda表达式指定了函数式接口 Printable 的具体操作方案为:拿到String(类型可推导,所以可省略)数据后,在控制台中输出它。

注:Lambda 中 传递的参数 一定是方法引用中 的那个方法可以接收的类型,否则会抛出异常

使用方法引用改进

public class Demo02PrintRef {
	private static void printString(Printable data) {
		data.print("Hello, World!");
	}
	public static void main(String[] args) {
		printString(System.out::println);
	}
}

这里的双冒号 :: 写法,这被称为“方法引用”,而双冒号是一种新的语法。如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者。

使用方法

下面会引出六种不同的方法引用

通过对象名引用成员方法

这个是最常见的一种用法,与上例相同(System.out 实际上是一个对象,out是System类中的一个静态打印流对象,详细内容参考API文档),如果一个类中已经存在了一个成员方法:

public class MethodRefObject {
	public void printUpperCase(String str) {
		System.out.println(str.toUpperCase());
	}
}

函数式接口仍然定义为:

@FunctionalInterface
public interface Printable {
	void print(String str);
}

那么当需要使用这个 printUpperCase 成员方法来替代 Printable 接口的Lambda的时候,已经具有了 MethodRefObject 类的对象实例,则可以通过对象名引用成员方法,

代码为:

public class Demo04MethodRef {
	private static void printString(Printable lambda) {
		lambda.print("Hello");
	}
	public static void main(String[] args) {
		MethodRefObject obj = new MethodRefObject();
		printString(obj::printUpperCase);
	}
}

通过类名称引用静态方法

由于在 java.lang.Math 类中已经存在了静态方法 abs ,所以当我们需要通过Lambda来调用该方法时,有两种写法。首先是函数式接口:

@FunctionalInterface
public interface Calcable {
	int calc(int num);
}

第一种写法是使用Lambda表达式:

public class Demo05Lambda {
	private static void method(int num, Calcable lambda) {
		System.out.println(lambda.calc(num));
	}
	public static void main(String[] args) {
		method(‐10, n ‐> Math.abs(n));
	}
}

但是使用方法引用的更好写法是:

public class Demo06MethodRef {
	private static void method(int num, Calcable lambda) {
		System.out.println(lambda.calc(num));
	}
	public static void main(String[] args) {
		method(‐10, Math::abs);
	}
}

在这个例子中,下面两种写法是等效的:

  • Lambda表达式: n -> Math.abs(n)
  • 方法引用: Math::abs

通过super引用成员方法

如果存在继承关系,当Lambda中需要出现super调用时,也可以使用方法引用进行替代。首先是函数式接口:

@FunctionalInterface
public interface Greetable {
	void greet();
	}

然后是父类 Human 的内容:

public class Human {
	public void sayHello() {
		System.out.println("Hello!");
	}
}

最后是子类 Man 的内容,其中使用了Lambda的写法:

public class Man extends Human {
	@Override
	public void sayHello() {
		System.out.println("大家好,我是Man!");
	}
//定义方法method,参数传递Greetable接口
	public void method(Greetable g){
		g.greet();
	}
	public void show(){
//使用super关键字代替父类对象
		method(()‐>super.sayHello());
	}
}

但是如果使用方法引用来调用父类中的 sayHello 方法会更好,将show方法中的方法体改为:

method(super::sayHello);

通过this引用成员方法

使用和上一种大同小异,这里就不赘述了。

类的构造器引用

由于构造器的名称与类名完全一样,并不固定。所以构造器引用使用 类名称::new 的格式表示。首先是一个简单的 Person 类:

public class Person {
	private String name;
	public Person(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

然后是用来创建 Person 对象的函数式接口:

public interface PersonBuilder {
	Person buildPerson(String name);
}

要使用这个函数式接口,可以通过Lambda表达式:

public class Demo09Lambda {
	public static void printName(String name, PersonBuilder builder) {
		System.out.println(builder.buildPerson(name).getName());
	}
	public static void main(String[] args) {
		printName("阿尔玟", name ‐> new Person(name));
	}
}

方法引用优化写法:

public class Demo10ConstructorRef {
	public static void printName(String name, PersonBuilder builder) {
		System.out.println(builder.buildPerson(name).getName());
	}
	public static void main(String[] args) {
		printName("赵丽颖", Person::new);
	}
}

在这个例子中,下面两种写法是等效的:

  • Lambda表达式: name -> new Person(name)
  • 方法引用: Person::new

数组的构造器引用

数组也是 Object 的子类对象,所以同样具有构造器,只是语法稍有不同。所以这个案例和上一个其实本质上是一样的只不过上一个是自定义类的构造函数引用,而这个则是数组类的构造函数引用。如果对应到Lambda的使用场景中时,需要一个函数式接口:

@FunctionalInterface
public interface ArrayBuilder {
	int[] buildArray(int length);
}

在应用该接口的时候,可以通过Lambda表达式:

public class Demo11ArrayInitRef {
	private static int[] initArray(int length, ArrayBuilder builder) {
		return builder.buildArray(length);
	}
	public static void main(String[] args) {
		int[] array = initArray(10, length ‐> new int[length]);
	}
}

但是更好的写法是使用数组的构造器引用:

public class Demo12ArrayInitRef {
	private static int[] initArray(int length, ArrayBuilder builder) {
		return builder.buildArray(length);
	}
	public static void main(String[] args) {
		int[] array = initArray(10, int[]::new);
	}
}

在这个例子中,下面两种写法是等效的:

  • Lambda表达式: length -> new int[length]
  • 方法引用: int[]::new

到此这篇关于Java 方法引用与ambda表达式的联系的文章就介绍到这了,更多相关Java 方法引用 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java8新特性:Lambda表达式之方法引用详解

    1.方法引用简述 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法.方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文.计算时,方法引用会创建函数式接口的一个实例. 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些.方法引用是一种更简洁易懂的Lambda表达式. Lambda表达式全文详情地址:http://blog.csdn.net/sun_promise/article/details/

  • Java Lambda表达式的方法引用和构造器引用实例分析

    本文实例讲述了Java Lambda表达式的方法引用和构造器引用.分享给大家供大家参考,具体如下: 一 点睛 如果Lambda表达式的代码块只有一条代码,还可以在代码块中使用方法引用和构造器引用,以使得Lambda表达式更加简洁. 种类 示例 说明 对应的Lambda表达式 引用类方法 类名::类方法 函数式接口中被实现方法的全部参数传给该类方法作为参数. (a,b,...) -> 类名.类方法(a,b, ...) 引用特定对象的实例方法 特定对象::实例方法 函数式接口中被实现方法的全部参数传

  • 一文带你掌握Java8中Lambda表达式 函数式接口及方法构造器数组的引用

    目录 函数式接口概述 函数式接口示例 1.Runnable接口 2.自定义函数式接口 3.作为参数传递 Lambda 表达式 内置函数式接口 Lambda简述 Lambda语法 方法引用 构造器引用 数组引用 函数式接口概述 只包含一个抽象方法的接口,称为函数式接口. 可以通过 Lambda 表达式来创建该接口的对象. 可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口.同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口.

  • Java 方法引用与ambda表达式的联系

    目录 方法引用是什么 冗余的Lambda场景 使用方法引用改进 使用方法 通过对象名引用成员方法 通过类名称引用静态方法 通过super引用成员方法 通过this引用成员方法 类的构造器引用 数组的构造器引用 方法引用是什么 方法引用通过方法的名字来指向一个方法.方法引用可以使语言的构造更紧凑简洁,减少冗余代码. 方法引用同样是Java 8 引入的新特性,而且和Lambda表达式有着不小的联系,它同样可以根据上下文进行推导,进而可以简化代码,可以说是Lambda的孪生兄弟. 下面我会通过最简单的

  • Java方法引用原理实例解析

    目录 冗余的Lambda场景 问题分析 用方法引用改进代码 方法引用符 通过对象名引用成员方法 通过类名称引用静态方法 通过super引用成员方法 通过this引用成员方法 类的构造器引用 数组的构造器引用 总结 在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿什么参数做什么操作.那么考虑 一种情况:如果我们在Lambda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再写重复逻辑? 冗余的Lambda场景 在 Printable 接口当中唯一的抽象方法 p

  • 你真的会使用Java的方法引用吗

    目录 前言 方法引用是什么? 方法引用与Lambda表达式 方法引用的使用 静态方法引用 实例方法引用 对象方法引用 构建方法引用 总结 前言 Java 8由Oracle公司于2014年3月18日发布,至今已过去数年之久.然而,直到今日仍有许多软件开发者对其相关特性不了解,这可能主要是Java基础教材更新缓慢的原因.Java 8 方法引用是Java 8的新特性,Java 8出来已经很久了,相信很多伙伴都已经在使用了,也有少部分不知道方法引用是怎么使用的,那么本文将带领大家一起初始Java的方法引

  • 使用Java 8中的Lambda表达式实现工厂模式

    前言 工厂模式是面向对象设计模式中大家最为熟知的设计模式之一.传统的实现方式大家都在熟悉不过了,今天将向大家介绍使用Java8 Lambda 表达式更加优雅的实现工厂模式. 封面 工厂模式在java中最常用的设计模式之一,它提供了一种很好的实例化对象的方法,是替代new操作的一种模式常用的方式.工厂设计模式可以让你实例化对象的逻辑不用暴露给客户端. 在下面的文章中我将给出使用传统的代码实现工厂模式的一个例子,然后再使用 Java8 Lambada 方式重新实现 一个例子 首先我将创建一个 Sha

  • java8新特性之方法引用示例代码

    简介 方法引用是java8的新特性之一, 可以直接引用已有Java类或对象的方法或构造器.方法引用与lambda表达式结合使用,可以进一步简化代码. 方法引用的使用场景 我们用Lambda表达式来实现匿名方法.但有些情况下,我们用Lambda表达式仅仅是调用一些已经存在的方法,除了调用动作外,没有其他任何多余的动作,在这种情况下,我们倾向于通过方法名来调用它,而Lambda表达式可以帮助我们实现这一要求,它使得Lambda在调用那些已经拥有方法名的方法的代码更简洁.更容易理解.方法引用可以理解为

  • Java8新特性之方法引用的实践指南

    一 前言 日常开发中,经常使用到Lambda表达式,例如: public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 5, 10, 4, 2); // 打印列表中的每一个数字 list.forEach((x) -> System.out.println(x)); } 其中(x) -> System.out.println(x)就是使用的Lambda表达式.Lambda表达式可以分为三

  • Java8中方法引用的使用详解

    1. 引言 Java8中最受广大开发中喜欢的变化之一是因为引入了 lambda 表达式,因为这些表达式允许我们放弃匿名类,从而大大减少了样板代码,并提高了可读性. 方法引用是lambda表达式的一种特殊类型.它们通常通过引用现有方法来创建简单的lambda表达式. 方法引用包括以下四种类型: 静态方法 特定对象的实例方法 特定类型的任意对象的实例方法 构造方法 在本篇文章中,我们将探讨Java中的方法引用. 2. 引用静态方法 We'll begin with a very simple exa

  • Java函数式编程(八):字符串及方法引用

    第三章 字符串,比较器和过滤器 JDK引入的一些方法对写出函数式风格的代码很有帮助.JDK库里的一些的类和接口我们已经用得非常熟悉了,比如说String,为了摆脱以前习惯的那种老的风格,我们得主动寻找机会来使用这些新的方法.同样,当我们需要用到只有一个方法的匿名内部类时,我们现在可以用lambda表达式来替换它了,不用再像原来那样写的那么繁琐了. 本章我们会使用lambda表达式和方法引用来遍历字符串,实现Comparator接口,查看目录中的文件,监视文件及目录的变更.上一章中介绍的一些方法还

  • 深入理解Java中的构造函数引用和方法引用

    JDK 8 见证了一个特殊特性的出现:构造函数引用和方法引用.在本文中, Adrian D. Finlay 探讨了开发人员如何释放构造函数引用的真正潜力. 方法引用的一些背景 如果你还不知道 Java 构造函数本身就是特殊的方法,那么阅读方法引用的基本示例将对读者有所帮助,通过了解这些内容,可以了解构造函数引用是什么. 「方法引用为已经有名称的方法提供易读的 lambda 表达式.」 「它们提供了一种无需执行就可以引用方法的简单方式.」 以上引自<Java 8 编程参考官方教程(第 9 版)>

随机推荐