Java 8 函数接口详细教程

ay = new byte[array.length];
for (int i = 0; i < array.length; i++) {
transformedArray[i] = function.applyAsByte(array[i]);
}
return transformedArray;
}
1
2
3
4
5
6
7
这里测试如何实现short数组至byte数组乘以2的转换:

short[] array = {(short) 1, (short) 2, (short) 3};
byte[] transformedArray = transformArray(array, s -> (byte) (s * 2));

byte[] expectedArray = {(byte) 2, (byte) 4, (byte) 6};
assertArrayEquals(expectedArray, transformedArray);
1
2
3
4
5
二元函数接口
带两个参数的lambda表达式,我们需要使用名称包含Bi关键字的函数接口:BiFunction, ToDoubleBiFunction, ToIntBiFunction, and ToLongBiFunction。

BiFunction 两个参数和返回值都是泛型,而ToDoubleBiFunction和其他类似函数接口可以返回基本类型。

使用二元lambda表示的典型示例是jdk中Map.replaceAll 方法,其使用计算值替换map中所有值。下面使用BiFunction实现接收key和被替换的值取计算新值并返回:

Map<String, Integer> salaries = new HashMap<>();
salaries.put("John", 40000);
salaries.put("Freddy", 30000);
salaries.put("Samuel", 50000);

salaries.replaceAll((name, oldValue) ->
name.equals("Freddy") ? oldValue : oldValue + 10000);
1
2
3
4
5
6
7
Supplier函数接口
Supplier接口是另一个不带任何参数的特殊形式。典型用于延迟生成值。举例,定义double值得平方函数。其不接收一个值,而是Supperlier作为值:

public double squareLazy(Supplier<Double> lazyValue) {
return Math.pow(lazyValue.get(), 2);
}
1
2
3
该函数可以通过使用Supplier实现来延迟生成值。这对于生成值需要花费很多时间情况非常有用。下面使用Guava 的sleepUninterruptibly 的方法进行模拟:

Supplier<Double> lazyValue = () -> {
Uninterruptibles.sleepUninterruptibly(1000, TimeUnit.MILLISECONDS);
return 9d;
};

Double valueSquared = squareLazy(lazyValue);
1
2
3
4
5
6
另一个Supplier的使用场景是定义流的生成序列逻辑。为了演示,我们使用静态Stream.genernate方法创建斐波那契数值流:

int[] fibs = {0, 1};
Stream<Integer> fibonacci = Stream.generate(() -> {
int result = fibs[1];
int fib3 = fibs[0] + fibs[1];
fibs[0] = fibs[1];
fibs[1] = fib3;
return result;
});
1
2
3
4
5
6
7
8
Stream.generate方法传入函数作为Supplier函数接口的实现。注意,要成为有用的生成器,Supplier函数接口通常需要某种外部状态。在本例中,它的状态由最后两个斐波那契数列数字组成。
为了实现该状态,我们使用一个数组而不是一组变量,因为所有在lambda表达式里面使用的外部变量必须是final。

其他特殊的Supplier 函数接口包括 BooleanSupplier, DoubleSupplier, LongSupplier 和 IntSupplier, 它们的返回类型都是相应的基本类型。

Consumer 函数接口
与Supplier相反,Consumer接口接收一个泛型参数但没有返回值。该函数是有副作用的代表(因为修改了参数,lambda表达式不能修改参数)。

举例,对list中每个名称以输出至控制台的方式进行问候。lambda表达式传入 List.forEach方法实现Consumer函数接口:

List<String> names = Arrays.asList("John", "Freddy", "Samuel");
names.forEach(name -> System.out.println("Hello, " + name));
1
2
也有特定版本的Consumer — DoubleConsumer, IntConsumer and LongConsumer,接收基本类型值作为参数。更有趣的是BiConsumer接口,其中一个应用场景是迭代map的entry:

Map<String, Integer> ages = new HashMap<>();
ages.put("John", 25);
ages.put("Freddy", 24);
ages.put("Samuel", 30);

ages.forEach((name, age) -> System.out.println(name + " is " + age + " years old"));
1
2
3
4
5
6
另外一组特殊BiConsumer 接口是 ObjDoubleConsumer, ObjIntConsumer, ObjLongConsumer ,分别接收两个参数,其中之一是泛型,另一个是基本类型。

Predicate 函数接口
在数学逻辑中,谓词是一个函数,它接收一个值并返回一个布尔值。Predicate函数接口是一个特殊函数接口,其接收一个泛型类型值,返回一个boolean。典型的应用场景是过滤集合的值:

List<String> names = Arrays.asList("Angela", "Aaron", "Bob", "Claire", "David");

List<String> namesWithA = names.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
1
2
3
4
5
在上面的代码中,我们使用流API过滤list的值名称以A开头的,Predicate实现即过滤逻辑代码。和前面示例一样,IntPredicate, DoublePredicate 和 LongPredicate 几个接口接收基础类型。

Operator 函数接口
Operator 接口是Function接口的特殊情况,接收和返回类型相同。UnaryOperator接口接收单个参数,其中一个应用是Collection Api的替换list中所有值,使用相同类型的计算值:

List<String> names = Arrays.asList("bob", "josh", "megan");
names.replaceAll(name -> name.toUpperCase());
1
2
List.replaceAll函数返回void类型,因为其替换一定位置的值。为了实现该目的,用于转换list值的lambda必须返回与其入参类型相同的结果。这就是为什么UnaryOperator在这里很有用。当然也可以使用方法引用代替lambda:

names.replaceAll(String::toUpperCase);
1
BinaryOperator接口一个最有趣的用例是reduce操作。如计算整型集合值之和。使用stream api可以实现,但更通用的方式是使用reduce方法:

List<Integer> values = Arrays.asList(3, 5, 8, 9, 12);

int sum = values.stream().reduce(0, (i1, i2) -> i1 + i2);
1
2
3
reduce方法接收一个初始累加值和BinaryOperator函数接口。该接口参数是相同类型的一对值,函数包括逻辑实现连接两者称为一个相同类型的值。传入函数必须具有结合性,即与值得计算顺序无关,如应满足下面条件:

op.apply(a, op.apply(b, c)) == op.apply(op.apply(a, b), c)
1
BinaryOperator 函数的结合性使得并行计算很容易。当然也针对基本类型的UnaryOperator 和 BinaryOperator,依次命名为 DoubleUnaryOperator, IntUnaryOperator, LongUnaryOperator, DoubleBinaryOperator, IntBinaryOperator 和 LongBinaryOperator。

传统的函数接口
不是所有的函数接口都来自Java 8 。很多之前版本的接口满足函数接口的条件则可以用作lambda表达式。典型的例子是并行API的 Runnable 和 Callable 接口。在Java 8 中这些接口使用@FunctionalInterface进行标记,这使得并发代码大大得到简化:

Thread thread = new Thread(() -> System.out.println("Hello From Another Thread"));
thread.start();
1
2
总结
本文我们描述Java Api提供可以作为lambda表达的不同函数式接口,并通过示例说明其应用场景。
---------------------

原文地址:https://www.cnblogs.com/ly570/p/10954610.html

时间: 2024-08-29 19:18:06

Java 8 函数接口详细教程的相关文章

函数接口

了解如何创建自定义函数接口,以及为什么应尽量使用内置接口 https://www.ibm.com/developerworks/cn/java/j-java8idioms7/index.html 系列内容: 此内容是该系列的一部分:Java 8 习惯用语 lambda 表达式的类型是什么?一些语言使用函数值或函数对象来表示 lambda 表达式,但 Java? 语言没有这么做.Java 使用函数接口来表示 lambda 表达式类型.乍一看似乎有点奇怪,但事实上这是一种确保对 Java 语言旧版本

java调用matlab函数接口的两种方案

Java 调用matlab 函数接口 Java调用matlab函数接口有两种方式: l 一种是通过matlab把函数打成jar包: l 一种是把matlab编译成dll后,用C++再封装成java能支持的数据类型的dll. 注意:不论用这两种方式中的哪一种,最终部署时都需要matlab环境(MCR,在matlab安装路径下有). 1. 方式一:matlab直接打jar包 1.1. 利用matlab自带工具打jar包 1.1.1. 建立jar包 在matlab的Commond Window中输入d

Java 8 中函数接口,陈货翻新了炒,只是为了Lambda表达式

Java开发人员应该对java.lang.Runnable,java.util.Comparator,java.util.concurrent.Callable 等等接口不会感到陌生.他们都只有一个单一的抽象方法.这样的接口,我们通常叫单一抽象方法接口(SAM,Single Abstract Method Interface). 以前大家应该经常使用下面的代码片段 public class InnerAnonymousClassSample { public static void main(S

JAVA – 虚函数、抽象函数、抽象类、接口

1. Java虚函数 虚函数的存在是为了多态. C++中普通成员函数加上virtual关键字就成为虚函数 Java中其实没有虚函数的概念,它的普通函数就相当于C++的虚函数,动态绑定是Java的默认行为.如果Java中不希望某个函数具有虚函数特性,可以加上final关键字变成非虚函数 PS: 其实C++和Java在虚函数的观点大同小异,异曲同工罢了. 2. Java抽象函数(纯虚函数) 抽象函数或者说是纯虚函数的存在是为了定义接口. C++中纯虚函数形式为:virtual void print(

mapxtreme java学习之路(1)——.dwg转.tab再转.gst详细教程

[背景] 因为项目的需要,需要在java web 项目中使用到地图,厂家提供的是dwg格式的地图,而我们采用的是mapxtreme java技术,所以先要把dwg格式的地图转成mapxtreme java可以解析的格式,即gst格式.关于这方面的资料,网上甚少,加上软件难找,中间走了不少弯路.基于mapxtreme java以后可能还要能到,dwg转gst的过程也必不可少,所以在这里整理一下整个转化过程.如果大家有更好的转化方法,欢迎讨论. [环境] windows xp 32 位 的虚拟机.

JAVA 虚函数 抽象函数 抽象类 接口

1. Java虚函数 虚函数的存在是为了多态. C++中普通成员函数加上virtual关键字就成为虚函数 Java中其实没有虚函数的概念,它的普通函数就相当于C++的虚函数,动态绑定是Java的默认行为.如果Java中不希望某个函数具有虚函数特性,可以加上final关键字变成非虚函数 PS: 其实C++和Java在虚函数的观点大同小异,异曲同工罢了. 2. Java抽象函数(纯虚函数) 抽象函数或者说是纯虚函数的存在是为了定义接口. C++中纯虚函数形式为:virtual void print(

【juincen】Java中的接口interface类比js中的回调函数

前几天在左讯飞语音的时候,无意间意识到java中的接口和js中常用的回调函数有点类似,今天在这儿整理一下思路. interface,Java中的接口,为什么会有这个东西. 一,预留声明 比如两个程序员A和B,A要写一段程序,其中需要调用到B写的程序.这时候A可以写一个接口: public interface Demo{ void deal(); } A要调用的方法先“预留声明”在接口里:deal 然后B去完善这个接口,B写了一个实现类实现了这个Demo接口. A在自己的业务逻辑里面只用调用接口的

Java 8 新特性-菜鸟教程 (3) -Java 8 函数式接口

Java 8 函数式接口 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口. 函数式接口可以被隐式转换为lambda表达式. 函数式接口可以现有的函数友好地支持 lambda. JDK 1.8之前已有的函数式接口: java.lang.Runnable java.util.concurrent.Callable java.security.PrivilegedAction java.util.Comparator java.io.

Eclipse 创建 Java 接口---Eclipse教程第11课

打开新建 Java 接口向导 新建 Java 接口向导可以创建新的 Java 接口.打开向导的方式有: 点击 File 菜单并选择 New > Interface 在 Package Explorer 窗口中右击鼠标并选择 New > Interface 在工具条上的下拉框按钮中 () 选择 () 在打开创建 Java 接口向导前,最好选择好Java接口所属的包名,这样在创建 Java 接口时包名字段就会自动填充. 使用新建 Java 接口向导 Java 接口向导的弹窗中你可以进行以下操作: