接口 | 参数 | 返回类型 | 描述 |
---|---|---|---|
predicate<t> | t | boolean | 用来比较操作 |
consumer<t> | t | void | 没有返回值的函数 |
function<t, r> | t | r | 有返回值的函数 |
supplier<t> | none | t | 工厂方法-返回一个对象 |
unaryoperator<t> | t | t | 入参和出参都是相同对象的函数 |
binaryoperator<t> | (t,t) | t | 求两个对象的操作结果 |
为什么要先从函数接口说起呢?因为我觉得这是 java8 函数式编程的入口呀!每个函数接口都带有 @functionalinterface 注释,有且仅有一个未实现的方法,表示接收 lambda 表达式,它们存在的意义在于将代码块作为数据打包起来。
没有必要过分解读这几个函数接口,完全可以把它们看成普通的接口,不过他们有且仅有一个抽象方法(因为要接收 lambda 表达式啊)。
@functionalinterface 该注释会强制 javac 检查一个接口是否符合函数接口的标准。 如果该注释添加给一个枚举类型、 类或另一个注释, 或者接口包含不止一个抽象方法, javac 就会报错。
先来复习一下匿名内部类的知识:
new thread(new runnable() { @override public void run() { system.out.println(123); } }).start();
new thread(()-> system.out.println(123)).start();
如上,和传入一个实现某接口的对象不同, 我们传入了一段代码块 —— 一个没有名字的函数。() 是参数列表, 和上面匿名内部类示例中的是一样的。 -> 将参数和 lambda 表达式的主体分开, 而主体是之后操作会运行的一些代码。
lambda 表达式简化了匿名内部类的写法,省略了函数名和参数类型。即参数列表 () 中可以仅指定参数名而不指定参数类型。
java 是强类型语言,为什么可以不指定参数类型呢?这得益于 javac 的类型推断机制,编译器能够根据上下文信息推断出参数的类型,当然也有推断失败的时候,这时就需要手动指明参数类型了。javac 的类型推断机制如下:
java8 在 java.util 包中引入了一个新的类 —— stream.java。java8 之前我们迭代集合,都只能依赖外部迭代器 iterator 对集合进行串行化处理。而 stream 支持对集合顺序和并行聚合操作,将更多的控制权交给集合类,是一种内部迭代方式。这有利于方便用户写出更简单的代码,明确要达到什么转化,而不是如何转化。
stream 的操作有两种,一种是描述 stream ,如 filter、map 等最终不产生结果的行为称为"惰性求值";另外一种像 foreach、collect 等是从 stream 中产生结果的行为称为"及早求值"。
接下来让我们瞧瞧 stream 如何结合 lambda 表达式优雅的处理集合...
list.foreach(e -> system.out.println(e)); map.foreach((k, v) -> { system.out.println(k); system.out.println(v); });
list<string> list = stream.of("java", "c++", "python").collect(collectors.tolist());
等价于:
list<string> aslist = arrays.aslist("java", "c++", "python");
long count = list.stream().filter(x -> "java".equals(x)).count();
list<string> maplist = list.stream().map(str -> str.touppercase()).collect(collectors.tolist()); list<string> list = stream.of("java", "javascript", "python").collect(collectors.tolist()); intsummarystatistics intsummarystatistics = list.stream().maptoint(e -> e.length()).summarystatistics(); system.out.println("最大值:" + intsummarystatistics.getmax()); system.out.println("最小值:" + intsummarystatistics.getmin()); system.out.println("平均值:" + intsummarystatistics.getaverage()); system.out.println("总数:" + intsummarystatistics.getsum());
maptoint、maptolong、maptodouble 和 map 操作类似,只是把函数接口的返回值改为 int、long、double 而已。
list<string> streamlist = stream.of(list, aslist).flatmap(x -> x.stream()).collect(collectors.tolist());
flatmap 方法的相关函数接口和 map 方法的一样, 都是 function 接口, 只是方法的返回值限定为 stream 类型罢了。
string maxstr = list.stream().max(comparator.comparing(e -> e.length())).get(); string minstr = list.stream().min(comparator.comparing(e -> e.length())).get();
integer sum1 = stream.of(1, 2, 3).reduce(0, (acc, e) -> acc + e);
上述执行求和操作,有两个参数: 传入 stream 中初始值和 acc。 将两个参数相加,acc 是累加器,保存着当前的累加结果。
java8 中新增了 stream 操作,那么第三方类库中的自定义集合 mylist 要怎么做到兼容呢?总不能升级完 java8,第三方类库中的集合实现全都不能用了吧?
为此,java8 在接口中引入了"默认方法"的概念!默认方法是指接口中定义的包含方法体的方法,方法名有 default 关键字做前缀。默认方法的出现是为了 java8 能够向后兼容。
public interface iterable<t> { /** * performs the given action for each element of the {@code iterable} * until all elements have been processed or the action throws an * exception. unless otherwise specified by the implementing class, * actions are performed in the order of iteration (if an iteration order * is specified). exceptions thrown by the action are relayed to the * caller. * * @implspec * <p>the default implementation behaves as if: * <pre>{@code * for (t t : this) * action.accept(t); * }</pre> * * @param action the action to be performed for each element * @throws nullpointerexception if the specified action is null * @since 1.8 */ default void foreach(consumer<? super t> action) { objects.requirenonnull(action); for (t t : this) { action.accept(t); } } }
看 java8 中的这个 iterable.java 中的默认方法 foreach(consumer<? super t> action),表示“如果你们没有实现 foreach 方法,就使用我的吧”。
默认方法除了添加了一个新的关键字 default,在继承规则上和普通方法也略有差别:
public static list<assistantvo> getassistant(long tenantid) { // ofnullable 如果 value 为null,会构建一个空对象。 optional<list<assistantvo>> assistantvo = optional.ofnullable(assistant_map.get(tenantid)); // orelse 如果 value 为null,选择默认对象。 assistantvo.orelse(assistant_map.get(default_tenant)); return assistantvo.get(); }
如对本文有疑问, 点击进行留言回复!!
android sdk源码 andoid-21 下的TextUtils.java文本工具类 源码赏析
地理坐标(WGS84),投影坐标下(Mercator)切片系统的计算Java类
荐 JavaWeb~简单认识以太网、MAC地址、MTU机制、ARP协议、DNS协议
HUAWEI MH5000-31 LGA Module Hardware Guide draft
网友评论