java8函数式编程实例
什么是函数式编程
函数式编程是java8的一大特色,也就是将函数作为一个参数传递给指定方法。别人传的要么是基本数据类型,要么就是地址引用 ,我们要穿一个“动作”。
Stream
说到函数式编程,就不得不提及Stream,Stream跟我们熟知的io流可不是同一个东西,泛指可以顺序执行或者并行执行的元素序列,主要是针对集合,可以将多个函数通过“.”串起来执行,其特点如下:
- stream不会存储数据,只是将集合流化,比如说 声明一个stream之后,往集合里面扔东西,stream可以取到新扔到集合里面的数据,你可以理解为操作时stream会实时从堆中的集合对象提取数据。
- stream不会改变原集合,我的理解是stream 是一堆元素顺序或者并行执行我们串起来的函数,改变后并不会对集合中的元素造成影响。
- steam是延迟执行的,也就是说在聚合操作之前 的其他操作,都会阻塞,直到执行聚合函数,其他的函数才开始一并执行。
解析相关接口
我们看看跟函数式编程相关的接口
java.long.FunctionalInterface是一个注解接口,函数接口都会实现它,看看它有什么特别的
从这里我们可以看出来一个函数接口只有一个抽象方法,但是如果要加一切其他的功能怎么办呢?接口中添加功能的话相当麻烦,接口相关实现类都需要修改,接下来“default”就登场了
default方法只能在接口出现,它不是抽象方法,可以通过methodInstance.isDefault()辨认,咦,弄啥勒,接口还能有普通方法?是的你没看错,添加default方法是为了方便修改接口,不至于每次修改过后都要将他的“儿子,孙子”等实现一一修改;如果在接口中default修饰的方法不加body会怎么样呢? 没错, 会编译失败!贴图:
接口中的default方法不用强制在实现类中 出现,当然业务需要的话,也可以重写来进行多态;
下面是java.util.function中的函数接口描述
序号 | 接口 & 描述 |
---|---|
1 |
BiConsumer<T,U>
代表了一个接受两个输入参数的操作,并且不返回任何结果 |
2 |
BiFunction<T,U,R>
代表了一个接受两个输入参数的方法,并且返回一个结果 |
3 |
BinaryOperator<T>
代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果 |
4 |
BiPredicate<T,U>
代表了一个两个参数的boolean值方法 |
5 |
BooleanSupplier
代表了boolean值结果的提供方 |
6 |
Consumer<T>
代表了接受一个输入参数并且无返回的操作 |
7 |
DoubleBinaryOperator
代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 |
8 |
DoubleConsumer
代表一个接受double值参数的操作,并且不返回结果。 |
9 |
DoubleFunction<R>
代表接受一个double值参数的方法,并且返回结果 |
10 |
DoublePredicate
代表一个拥有double值参数的boolean值方法 |
11 |
DoubleSupplier
代表一个double值结构的提供方 |
12 |
DoubleToIntFunction
接受一个double类型输入,返回一个int类型结果。 |
13 |
DoubleToLongFunction
接受一个double类型输入,返回一个long类型结果 |
14 |
DoubleUnaryOperator
接受一个参数同为类型double,返回值类型也为double 。 |
15 |
Function<T,R>
接受一个输入参数,返回一个结果。 |
16 |
IntBinaryOperator
接受两个参数同为类型int,返回值类型也为int 。 |
17 |
IntConsumer
接受一个int类型的输入参数,无返回值 。 |
18 |
IntFunction<R>
接受一个int类型输入参数,返回一个结果 。 |
19 |
IntPredicate
:接受一个int输入参数,返回一个布尔值的结果。 |
20 |
IntSupplier
无参数,返回一个int类型结果。 |
21 |
IntToDoubleFunction
接受一个int类型输入,返回一个double类型结果 。 |
22 |
IntToLongFunction
接受一个int类型输入,返回一个long类型结果。 |
23 |
IntUnaryOperator
接受一个参数同为类型int,返回值类型也为int 。 |
24 |
LongBinaryOperator
接受两个参数同为类型long,返回值类型也为long。 |
25 |
LongConsumer
接受一个long类型的输入参数,无返回值。 |
26 |
LongFunction<R>
接受一个long类型输入参数,返回一个结果。 |
27 |
LongPredicate
R接受一个long输入参数,返回一个布尔值类型结果。 |
28 |
LongSupplier
无参数,返回一个结果long类型的值。 |
29 |
LongToDoubleFunction
接受一个long类型输入,返回一个double类型结果。 |
30 |
LongToIntFunction
接受一个long类型输入,返回一个int类型结果。 |
31 |
LongUnaryOperator
接受一个参数同为类型long,返回值类型也为long。 |
32 |
ObjDoubleConsumer<T>
接受一个object类型和一个double类型的输入参数,无返回值。 |
33 |
ObjIntConsumer<T>
接受一个object类型和一个int类型的输入参数,无返回值。 |
34 |
ObjLongConsumer<T>
接受一个object类型和一个long类型的输入参数,无返回值。 |
35 |
Predicate<T>
接受一个输入参数,返回一个布尔值结果。 |
36 |
Supplier<T>
无参数,返回一个结果。 |
37 |
ToDoubleBiFunction<T,U>
接受两个输入参数,返回一个double类型结果 |
38 |
ToDoubleFunction<T>
接受一个输入参数,返回一个double类型结果 |
39 |
ToIntBiFunction<T,U>
接受两个输入参数,返回一个int类型结果。 |
40 |
ToIntFunction<T>
接受一个输入参数,返回一个int类型结果。 |
41 |
ToLongBiFunction<T,U>
接受两个输入参数,返回一个long类型结果。 |
42 |
ToLongFunction<T>
接受一个输入参数,返回一个long类型结果。 |
43 |
UnaryOperator<T>
接受一个参数为类型T,返回值类型也为T。 |
除了上面列出的,还有个别函数接口没列出来,例如Comparator(), 但总归是个函数接口都会基于FunctionalInterface注解
总结
这些函数主要还是分为几个主要函数,其余都是以其为基础的分化;
- Supplier<T> 无参数,返回一个结果。
- Consumer<T> 代表了接受一个输入参数并且无返回的操作。
- Function<T,R> 接受一个输入参数,返回一个结果,返回的结果跟参数的类型无关。
- Predicate<T> 接受一个输入参数,返回一个布尔值结果。
- BinaryOperator<T> 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果,xxxOperator 函数都是接受类型跟返回值类型相同。
而且,从上面五个主要函数接口命名也可以看出其作用,"Bi"作为前缀的都是属于二元操作,接受两个参数。
T1toT2是从接受T1类型参数,返回T2类型结果,比如IntToLongFunction 接受一个int类型参数,返回long类型结果。
实战1
下面我写了一个功能,拳击手有分组跟体重两个属性,然后给一组拳击手集合,根据小组或者体重级排序,用到的是Comparator(),也是一个函数接口
上码:
/**
* Created by zhanghe
* 拳击手
*/
public class Boxer {
//分组
private String group;
//重量级
private Integer weight;
public Boxer(String group, Integer weight) {
this.group = group;
this.weight = weight;
}
public static <T> List<List<T>> divider(List<T> datas, Comparator<T> c) {
//声明一个列表来接收各个分组
List<List<T>> list = new ArrayList<>();
for (T t : datas) {
//通过isSameGroup 标识来判断分组是否已创建
boolean isSameGroup = false;
for (int i = 0; i < list.size(); i++) {
//compare函数返回值为int,正数说明param1>param2,0说明param1=param2,负数说明param1<param2
//这里用到的原理是将List列表datas中的各项与分组列表list中的元素比较(比较的规则由外面作为参数传递,这就是函数式编程),
// 值为0表示规则相符即为同一组
if (c.compare(t, list.get(i).get(0)) == 0) {
isSameGroup = true;
list.get(i).add(t);
break;
}
}
//比较完了发现没有规则相符的,即自成一系
if (!isSameGroup) {
List<T> e = new ArrayList<>();
e.add(t);
list.add(e);
}
}
return list;
}
public static void main(String[] args) {
List<Boxer> boxers = Arrays.asList(
new Boxer("红队", 120),
new Boxer("绿队", 180),
new Boxer("蓝队", 200),
new Boxer("绿队", 220),
new Boxer("蓝队", 120),
new Boxer("红队", 80),
new Boxer("红队", 90),
new Boxer("绿队", 240)
);
List<List<Boxer>> dividByGroup = divider(boxers, new Comparator<Boxer>() {
@Override
public int compare(Boxer o1, Boxer o2) {
//分组一样 即认为 相同
return o1.group.equals(o2.group) == true ? 0 : 1;
}
});
System.out.println("根据小组区分:");
dividByGroup.stream().forEach(e->{
System.out.println(e);
});
List<List<Boxer>> dividByWeight = divider(boxers, new Comparator<Boxer>() {
@Override
public int compare(Boxer o1, Boxer o2) {
//体重/100 即体重百分位相同 即认为 相同
return (o1.weight / 100 - o2.weight / 100) == 0 ? 0 : 1;
}
});
System.out.println("根据体重区分:");
dividByWeight.stream().forEach(e->{
System.out.println(e);
});
}
@Override
public String toString() {
return "Boxer{" +
"小组='" + group + '\'' +
", 体重=" + weight +
'}';
}
}
这个是结果
实战2
我用Predicate 写了个具有匹配功能的方法,当然 匹配的规则还是作为一个函数参数传递,撸码不是很优雅,只看功能就好~
闲话不多说,上码:
List<Object> list = Arrays.asList(1, 2,"",100,"3", 'c');
List<Object> matchList = match(list, a -> {
return a instanceof Integer && (Integer) a > 10;
});
System.out.println(matchList);//100
Set set = new HashSet<>();
set.add("haha");
set.add(1);
set.add(100);
Set matchSet = match(set, a -> a instanceof Integer);
System.out.println(matchSet);//[1, 100]
String matchString = match("java", a -> {
return a instanceof String && ((String) a).startsWith("j");
});
System.out.println(matchString);//java
Integer noMatch = match(100, a -> {
return a instanceof String && ((String) a).startsWith("j");
});
System.out.println(noMatch);//null
}
/**
*
* @param t 入参 需要匹配规则的参数
* @param p 函数接口 匹配的动作
* @param <T>
* @return 验证成功 是集合 则只留匹配元素,是String,Integer ..匹配成功返回本身,反之返回null
*/
public static <T> T match(T t, Predicate p) {
if (t instanceof Collection) {
if (t instanceof List) {
t = (T) ((List) t).stream().filter(a -> p.test(a)).collect(Collectors.toList());
}
if (t instanceof Set) {
t = (T) ((Set) t).stream().filter(a -> p.test(a)).collect(Collectors.toSet());
}
} else {
if (!p.test(t)) {
return null;
}
}
return t;
java8函数式编程实例相关推荐
- java8 函数式编程_Java 8函数式编程:延迟实例化
java8 函数式编程 单例通常会延迟实例化自己,有时,如果对象足够重,则可以延迟实例化类字段. 通常,在走惰性路线时,getter方法(或accessor )必须具有一段代码,该代码块在返回对象之前 ...
- java8 函数式编程_您必须学习Java 8的函数式编程吗?
java8 函数式编程 我最近一直在研究Java 8,并掌握了Manning出版的" Java 8 In Action" . 让我印象深刻的第一件事是Java 8独特的销售主张是函 ...
- Java8函数式编程详解
Java8 函数式编程详解 Author:Dorae Date:2017年11月1日23:03:26 转载请注明出处 说起Java8,可能很多人都已经知道其最大的改进,就是引入了Lambda表达式与S ...
- Java8函数式编程_8--设计和架构的原则
1,免责声明,本文大部分内容摘自<Java8函数式编程>.在这本书的基础上,根据自己的理解和网上一些博文,精简或者修改.本次分享的内容,只用于技术分享,不作为任何商业用途.当然这本书是非常 ...
- [2017.02.23] Java8 函数式编程
以前学过Haskell,前几天又复习了其中的部分内容. 函数式编程与命令式编程有着不一样的地方,函数式编程中函数是第一等公民,通过使用少量的几个数据结构如list.map.set,以及在这些数据结构上 ...
- java8 函数式编程_如何使用Java 8函数式编程生成字母序列
java8 函数式编程 我偶然发现了用户" mip"一个有趣的堆栈溢出问题 . 问题是: 我正在寻找一种生成字母序列的方法: A, B, C, ..., Z, AA, AB, AC ...
- java8 函数式编程_使用Javaslang进行Java 8中的函数式编程
java8 函数式编程 我们非常高兴地在jOOQ博客上宣布一个客座帖子,该帖子由HSH Nordbank的高级软件工程师Daniel Dietrich (三人的丈夫和父亲)撰写. 他目前作为项目负责人 ...
- 函数式编程实例WordCount(林子雨老师慕课代码) 由于文件引入的问题之前报过Exception in thread “main“ java.lang.NullPointerExcept(已解决)
函数式编程实例WordCount 数据文件目录: 文件内容: 刚开始在写文件的时候以为val dirfile = new File("data")这一行写的是具体文件,于是我写成了 ...
- Java8函数式编程语法入门
Java8函数式编程语法入门 Java8中函数式编程语法能够精简代码. 使用Consumer作为示例,它是一个函数式接口,包含一个抽象方法accept,这个方法只有输入而无输出. 现在我们要定义一个C ...
最新文章
- linux下i2c设备驱动程序,Linux I2C 设备驱动
- 【每日一题】航班预订统计
- 【Android 应用开发】Activity 返回堆栈管理 ( 栈内复用模式 singleTask | 单实例模式 singleInstance )
- scalikejdbc 学习笔记(4)
- VTK:可视化之LabelContours
- (码友推荐)2018-07-12 .NET及相关开发资讯速递
- 崩溃日志记录Landroid/support/v4/animation/AnimatorCompatHelper
- 将Fri May 04 17:25:34 CST 2012形式的日期字符串转换成java.util.Date对象的方法
- C++:02---命名空间
- (19)FPGA乒乓操作
- Java核心类库——内部类那点事儿
- 利用cca进行fmri分析
- visual studio2013 php
- Web 的将来是语义的
- mysql找不到服务_win7系统安装mysql后找不到服务或提示找不到指定文件如何解决...
- 正充电手机自动订了总统套房!公安介入调查:排除被植入后门或被控制可能...
- fastjson list转json
- WPF下CefSharp的使用
- 谷歌浏览器,如何不用翻墙,下载插件?
- Win7、Win10封装系统制作系统镜像,操作流程#gho