Java8之将普通方法写一个装逼的函数式代码

首先看代码

下面的方法很简单就是从数据中找一个值,找到返回。

@Test
public void test2() {
Integer [] c = new Integer[20];
for(int i = 0;i< c.length; i++) {
c[i]=i;
}
//从上面这个数组中找一个值
int findValue = find(c, 2);
System.err.println(findValue);
}
private Integer find(Integer[] x, int y) {
for (int i = 0; i < x.length; i++) {
if (x[i].intValue() == y)
return x[i];
}
return null;
}

Java8修改成函数式,变成以一下这个样子

@Test
public void test1() {
int size = 20;
Integer [] c = Stream.iterate(size - 1, x -> x-1).limit(size).toArray(Integer[]::new);
Integer result =find1(c, 2, (x,y)->{
return Arrays.stream(x).filter(n->n.intValue()==y).findFirst().orElse(null);
});
System.err.println(result);
}
public static Integer find1(Integer[] x,Integer y,BiFunction t) {
return t.apply(x, y);
}

或者变成这个样子

@Test
public void test1() {
int size = 20;
Integer [] c = Stream.iterate(size - 1, x -> x-1).limit(size).toArray(Integer[]::new);
Integer result = find13(c, 2);
System.err.println(result);
}
public Integer find13(Integer[] x, Integer y) {
BiFunction f = (m, n) -> {
return Arrays.stream(m).filter(i -> i.intValue() == n).findFirst().orElse(null);
};
return f.apply(x, y);
}

这里BiFunction是Java8已定义的一个函数接口

Interface BiFunction 其中 参数类型如下

T - 函数的第一个参数的类型

U - 函数的第二个参数的类型

R - 函数结果的类型

如果觉得看不明白,也可以自定义一个自己的函数接口

这时上面的方法就变成下面这样:

@Test
public void test1() {
int size = 20;
Integer [] c = Stream.iterate(size - 1, x -> x-1).limit(size).toArray(Integer[]::new);
Integer result = find13(c, 2);
System.err.println(result);
}
public Integer find13(Integer[] x, Integer y) {
F1 f1 = (m, n) -> {
return Arrays.stream(m).filter(i -> i.intValue() == n).findFirst().orElse(null);
};
return f1.find(x, y);
}
@FunctionalInterface
interface F1{
Integer find(Integer [] r,Integer u);
}

其中F1为自定义的函数接口,只包含一个抽象方法。可以看java8 总结 之lambda表达式来了解什么时函数接口。

如果你有一定的函数式编程经验,是不是感觉怪怪的。这是因为在Java中lambda表达式,其实还是一个接口。要想写一个灵活的函数表达式,首先要定义一个只包含一个抽象方法的接口,还好,Java8已经自定义好了绝大部分你能用到的接口:

常用函数式接口

函数式接口

参数类型

返回类型

抽象方法名

描述

其它方法

Runnable

void

run

执行一个没有参数和返回值的操作

Supplier

T

get

提供一个T返回值

Consumer

T

void

accept

处理一个T类型的值

chain

BiConsumer

T,U

void

accept

处理T类型和U类型的值

chain

Function

T

R

apply

表示接受一个参数T处理并产生结果R

compose,andThen,compose,identity

BiFunction

T,U

R

apply

表示接受两个参数(T,U)并产生结果R

andThen

UnaryOperator

T

T

apply

对类型T进行的一元操作,并返回T类型

andThen, apply, compose

BinaryOperator

T

T

apply

对类型T进行的二元操作

andThen

Predicate

T

boolean

test

一个计算Boolean值的函数

And,or,negate,isEqual

BiPredicate

T,U

boolean

test

一个含有两个参数,计算Boolean的函数

And,or,negate

以上是比较常用的几个,上面的例子中用至的就是BiFunction函数接口。

如果要了解更多可以查看JDK1.8下java.util.function或者查看在线API

写装X函数式代码的方式

写出箭头函数

如上,定义或者使用已有的函数式接口,如上面的F1接口或者 BiFunction接口都是这类的接口,定义好后,在调用至该接口的抽象方法时,就要知道,这些接口可以将函数做为参数来传递。要有这个思想转变。

消除for/while循环

原则上,函数式编程不应该有循环的,对于循环Java8对集合类的几乎都可以转为Stream,Stream丰富操作完全可以满足日常常用操作。

只要记住函数式编程的“函数式”特性:不可变数据,第一类对象以及尾调用优化。

要想了解的话可以至左耳朵耗子的博客看一下价绍。

结束 end.

下一篇我们来说说Java8系列最后一篇对并发的增强以及新日期的API。