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表达的不同函数式接口,并通过示例说明其应用场景。
---------------------
Java 8 函数接口详细教程的更多相关文章
- 《手把手教你》系列技巧篇(二十五)-java+ selenium自动化测试-FluentWait(详细教程)
1.简介 其实今天介绍也讲解的也是一种等待的方法,有些童鞋或者小伙伴们会问宏哥,这也是一种等待方法,为什么不在上一篇文章中竹筒倒豆子一股脑的全部说完,反而又在这里单独写了一篇.那是因为这个比较重要,所 ...
- VSCode Java 开发环境配置 详细教程
VSCode Java 开发环境配置 详细教程 配置java 下载 用于现在大多数使用者用的是java 8,小白的我先安装java 8好了,^ w ^. 下载地址:Java 8 | Java SE 打 ...
- JNI的又一替代者—使用JNR访问Java外部函数接口(jnr-ffi)
1. JNR简单介绍 继上文“JNI的替代者—使用JNA访问Java外部函数接口”,我们知道JNI越来越不受欢迎,JNI是编写Java本地方法以及将Java虚拟机嵌入本地应用程序的标准编程接口.它管理 ...
- 阿里巴巴Java开发规约插件p3c详细教程及使用感受
阿里巴巴Java开发手册 在进入正题介绍这款插件之前,首先来谈一下<阿里巴巴Java开发手册>,2017年年初,首次公开的阿里官方Java代码规范标准手册可以说是引起了全民(IT界)代码规 ...
- 最新的Windows环境搭建zeroMQ并使用java代码运行zeromq详细教程
最近项目要用zeromq,linux上很好配置使用,但是windows上配置与使用没有找到合适的解决方案,看的很头疼,这里自己总结下供大家参考 准备工作: 1.libzmq下载地址:https://g ...
- Java程序生成exe可执行文件详细教程(图文说明)
ava程序打包成exe可执行文件,分为两大步骤. 第一步:将Java程序通过Eclipse或者Myeclipse导成Jar包 第二步:通过exe4j讲Jar包程序生成exe可执行文件 第一步详解: 将 ...
- Java连接MySQL数据库详细教程(附网盘下载地址)
准备工具 Eclipse-oxygen-64位 http://pan.baidu.com/s/1gf48FIj MySQL-5.7.17 http://pan.baidu.com/s/1skD14Cl ...
- 阿里巴巴Java开发规约插件p3c详细教程及使用感受 - 转
http://www.cnblogs.com/han-1034683568/p/7682594.html
- 转载:python + requests实现的接口自动化框架详细教程
转自https://my.oschina.net/u/3041656/blog/820023 摘要: python + requests实现的接口自动化框架详细教程 前段时间由于公司测试方向的转型,由 ...
随机推荐
- F2BPM作流引擎系列索引
索引如下 F2工作流引擎遵循参考WFCM标准规范,符合中国国情特色,更轻量级的工作流引擎,支持多种数据库(mmsqlserver,mysql,oracle),有强大智能的组织模型接口可快速应用到任何基 ...
- 一个效果非常华丽的仿桌面APP,却胜似Launcher
开发Android APP的同学是否对于Launcher实现的绚丽效果而痴迷呢?什么.连Android Launcher是什么都不知道.好吧,拿起侬的手机.在解锁后的首页界面上左右滑动滑动,体验体验, ...
- 新手对ASP.NET MVC的疑惑
习惯了多年的WEB FORM开发方式,突然转向MVC,一下子懵了,晕头转向,好多不习惯,好多不明白,直到现在也没弄明白,只好先记下来,在应用中一一求解. 主要集中在视图(View)这里. 1.@Htm ...
- mongodb 对内存的占用监控 ——mongostat,linux系统可用的内存是free + buffers + cached
刚开始使用mongodb的时候,不太注意mongodb的内存使用,但通过查资料发现mongodb对内存的占用是巨大的,在本地测试服务器中,8G的内存居然被占用了45%.汗呀. 本文就来剖析一下mong ...
- CodeForces - 743D Chloe and pleasant prizes
Chloe and pleasant prizes time limit per test 2 seconds memory limit per test 256 megabytes input st ...
- codeforces 898F Hash
F. Restoring the Expression time limit per test 2 seconds memory limit per test 256 megabytes input ...
- B4321 queue2 dp
这个题的dp真的恶心.首先,一开始我以为是一道数论题,但是组合数和这个题没啥关系.dp方程巨麻烦,状态是dp[i][j][0/1],代表i位连了j个,上一位是否连着.然后开始转移,证明如下: 我们先来 ...
- Network Saboteur(dfs)
http://poj.org/problem?id=2531 不太理解这个代码... #include <stdio.h> #include <string.h> ][],v[ ...
- Python 35 线程(1)线程理论、开启线程的两种方式
一:线程理论 1 什么是线程 进程其实一个资源单位,而进程内的线程才是cpu上的执行单位 线程其实指的就是代码的执行过程2 为何要用线程 线程vs进程 1. 同一进程下的多个线程共享该进程 ...
- POI合并单元边框问题解决方法
http://blog.csdn.net/hardworking0323/article/details/51105430