在JDK8中添加了java.util.function包,该包中是用于一些函数式接口,这些接口被用于改造JDK原有的一些接口添加Lambda调用方式的函数式方法。
List等实现了Iterable接口的类:
package java.lang;
import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
/**
* 拿客
* www.coderknock.com
* QQ群:213732117
* 创建时间:2016年07月23日
* 描述:
*/
public interface Iterable {
Iterator iterator();
/**
* 迭代的每个元素并执行特定动作的代码直到所有的元素都被处理或抛出异常。
* 除非实现类的其他的实现, 否则,
* action中的操作是在迭代的顺序中执行的(如果迭代顺序指定)。
* 异常会传递给action的调用对象。
*
* @implSpec
*
The default implementation behaves as if:
*
{@code
* for (T t : this)
* action.accept(t);
* }
*
* @param action 为每个元素执行的操作
* @throws NullPointerException 如果指定的操作是空的
* @since 1.8
*/
default void forEach(Consumer super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator spliterator() {
//根据迭代器创建一个分片迭代器
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
我们来看下Consumer:
package java.util.function;
import java.util.Objects;
/**
* 拿客
* www.coderknock.com
* QQ群:213732117
* 创建时间:2016年07月23日
* 描述:
*/
/**
* 表示接受一个输入参数,并返回没有结果的操作。不像大多数其他的功能接口,Consumer is expected
* to operate via side-effects.预计通过副作用。
*
* 这是一个函数接口,函数方法为accept(T t)
*
* @param 输入到操作的类型
*
* @since 1.8
*/
@FunctionalInterface
public interface Consumer {
/**
* 在给定的参数上执行此操作。
*
* @param t 输入的参数
*/
void accept(T t);
/**
* 返回一个Consumer对象,其在执行accept之后执行传入的after中的accept,从而可以执行多重操作
*
* @param after 此操作后执行的操作
* @return 返回一个Consumer对象,其操作为自身的accept以及after中的accept
* @throws NullPointerException
*/
default Consumer andThen(Consumer super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
通过forEach的示例来看一下是怎么实现的:
List list = new ArrayList<>();
/**
下面代码时非Lambda的forEach写法
list.forEach(new Consumer() {
@Override
public void accept(String x) {
System.out.println(x);
}
});
**/
list.forEach(x -> System.out.println(x));
上面语句中x -> System.out.println(x)实际上是创建了一个Consumer,该Consumer的泛型在编译器编译时会根据List的泛型进行判断,如果没有声明则默认Object。
Stream的Filter
Stream的filter方法如下:
Stream filter(Predicate super T> predicate);
Predicate其实就是提供了一个boolean类型的返回值方法的函数接口,其源码如下:
package java.util.function;
import java.util.Objects;
/**
* 拿客
* www.coderknock.com
* QQ群:213732117
* 创建时间:2016年07月23日
* 描述:
*/
/**
* 表示对一个参数的断言的结果(布尔值函数)。
*
* 这是一个函数接口,函数方法是test(Object)
*
* @param 输入到断言的类型
*
* @since 1.8
*/
@FunctionalInterface
public interface Predicate {
/**
* 在给定的参数上计算这个断言。
*
* @param t 输入的参数
* @return 如果参数匹配断言返回true,否则返回false
*/
boolean test(T t);
default Predicate and(Predicate super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate negate() {
return (t) -> !test(t);
}
default Predicate or(Predicate super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static Predicate isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
还是使用上面的list变量,其stream写法如下:
/**
//非lambda写法
list.stream().filter(new Predicate() {
@Override
public boolean test(String x) {
return x.equals("test");
}
});
**/
list.stream().filter(x -> x.equals("test"));
上面语句中x -> x.equals("test")实际上是创建了一个Predicate,该Predicate的泛型在编译器编译时会根据List的泛型进行判断,如果没有声明则默认Object。
如果你写成list.stream().filter(x -> x==1);是会编译错误的,编译时编译器通过类型推断可以确定x是String类型,所以使用x==1时会报错:
D:\Work\LearnJavaFX\src>javac -encoding utf-8 LambdaTest.java
LambdaTest.java:20: 错误: 不可比较的类型: String和int
return x==1;
^
1 个错误