* 不可变
* 惰性求值
* 闭包
* 高阶函数
* 柯里化
* 部分应用
* 结合律
- 参数类型可推导
- 单行可省略单括号
- 单参数可以省略小括号
(int a, int b) -> {return a + b;}
(a, b) -> a + b;
a -> a * a;
() -> return true;
@FunctionalInterface // 非必需,加上该注解编译器会进行校验
public interface Runnable {
// SAM 只能是单个的非默认方法,这是由于 Java 8 的 interface 允许在接口内定义默认的方法体和静态方法
public abstract void run();
}
常用函数式接口对象:
Function<T, R>
:一个输入参数与返回值,将 T 转换为 R。SAM 为 R applay(T t)
Predicate<T>
:一个输入参数,返回一个 boolean
值。SAM 为 boolean test(T t)
Consumer<T>
:一个输入参数 ,执行对应的行为。SAM 为 void accept(T t)
Supplier<T>
: 无输入参数,返回一个对应的泛型 T
对象,类似于一个工厂方法。SAM 为 T get()
UnaryOperator<T>
:一个一元操作,将 输入的 T
转变为 T
,该接口继承自 Funtion<T, R>
, 因此 SAM 也为 R apply(T t)
BinaryOperator<T, U, R>
:一个二元操作函数,输入第一个参数T
和 第二个参数U
,得到处理结果 R
。该接口继承自 BiFunction<T, U, R>
,SAM 为 R apply(T t, U u)
。
方法引用:
- 类的静态方法:
ClassX::methodName
- 类的构造方法:
ClassX::new
- 类的实例方法:
instance::methodName
- 对于类的实例方法,当实例方法所需参数小于 Lambda 要求的参数时,将会把当前的实例对象作为一个参数放入 Lambda 中作为参数。。。。。(具体细节未知)
函数式接口转换:
- 忽略输入:Supplier -> Function
- 忽略返回:Function -> Consumer
- 忽略输入和返回:Supplier -> Runnable
void-compatibility 规则:如果 Lambda 是一个语句表达式,那么即时该 Lambda 有返回值也可以赋值给返回值为 void 的函数
相比较于一般的 List
容器,Stream
存在以下这些优点:
Stream
可以是无限的Stream
可以对数据进行并行处理Stream
可以延迟执行
filter(Predicate<? super T> predicate)
通过传入的 Predicate
函数对数据进行过滤。该方法是一个中间操作方法。
map(Function<? super T, ? extends R> mapper)
通过传入的 mapper
映射函数对数据元素进行转换。该方法也是一个中间操作方法。
reduce(T identity, BinaryOperator<T> accumulator)
通过传入的二元函数对初始数据元素为 identity
的数据进行 reduction 操作。该方法是一个终止操作方法。
reduce()
方法的示例:
-
数据求和
public static int sum(List<Integer> list) { // 从流中每次计算得到两个数据的总和,直到所有数据都被处理 return list.stream().reduce(0, Integer::sum); }
-
求最大值与最小值
public static int max(List<Integer> list) { return list.stream().reduce(Integer.MIN_VALUE, Math::max); } public static int min(List<Integer> list) { return list.stream().reduce(Integer.MAX_VALUE, Math::min); }
-
组合成字符串
public static String join(List<Integer> list) { return list.stream().map(String::valueOf) .reduce((String s1, String s2) -> String.join(", ", s1, s2)) .orElse(" "); }
-
将数据存放到容器中
public static <T> List<T> toList(Stream<T> stream) { List<T> tmp = new ArrayList<>(); // 最终保存结果的列表对象 return stream.reduce(tmp, (List<T> t1, T obj) -> { t1.add(obj); return t1; }, (List<T> t1, List<T> t2) -> { t1.addAll(t2); return t2; }// 整合规则); }
-
使用
reduce
实现map
public static <T, R> List<R> toMap(List<T> list, Function<T, R> transfer) { List<R> rList = new ArrayList<>(); // 存放结果的容器对象 return list.stream().reduce(rList, (List<R> r1, T obj) -> { R r = transfer.apply(obj); r1.add(r); return r1; // 传入得到数据元素使用转换函数进行转换,添加到当前处理的容器对象中 }, (List<R> r1, List<R> r2) -> { r1.addAll(r2); return r1; // 容器元素的整合规则 }); }
-
使用
reduce
实现filter
public static <T> List<T> toFilter(List<T> list, Predicate<T> filter) { List<T> tmp = new ArrayList<>(); // 存储结果的容器对象 return list.stream().reduce(tmp, (List<T> t1, T obj) -> { if (filter.test(obj)) t1.add(obj); // 元素过滤规则 return t1; }, (List<T> t1, List<T> t2) -> { t1.addAll(t2); return t1; }); // 容器的整合规则 }
Stream.collect()
相比较于 Stream.reduce()
, collect()
操作可变数据,reduce()
操作不可变数据
-
<R> R collect(Supplier<R> supplier, // 一个创建新的可变结果容器的函数,对于并行的执行,该函数可能会被多次调用,每次返回更新后的值 BiConsumer<R, ? super T> accumulator, // 将第二个参数对象折叠到第一个容器中的二元函数 BiConsumer<R, R> combiner); // 将第二个容器的所有元素折叠到第一个容器中的二元函数
-
<R, A> R collect(Collector<? super T, A, R> collector); // Collector 聚集了上文第一个方法需要的函数
其中,Collector
包含了所需的函数,包括:
Supplier<A> supplier()
:一个创建可返回易变结果容器的函数。BiConsumer<A, T> accumulator()
:一个将元素折叠到易变结果容器的函数。累积函数BinaryOperator<A> combiner()
:接收两个局部结果,将它们归并到一起的整合函数。Function<A, R> finisher()
:将中间类型A
转化为最终结果类型B
。也就是对累积数据进行队中的转换。Set<Characteristics> characteristics()
:返回一个Collector.Characteristics
集合指示该Collector
的特征,这个集合应当是不可变的。集合中的元素为:CONCURRENT
意味着支持来自多个线程的对同一结果容器并发地调用累积函数;UNORDERED
指示该集合操作不致力于保留输入元素地顺序;IDENTITY_FINISH
如果设置该属性,那么必须保证finisher()
函数在未经检查的情况下进行对象的转化是成功的。
Collector
需要满足:
-
同一律
Combiner.apply(acc, []) === acc;
-
结合律
acc.apply(t1); acc.apply(t2) === acc.apply(t2);acc.apply(t1); finisher.apply(acc) === finisher.apply(combiner.apply(t1, t2))
groupingBy(Function)
// 单纯分 key 存放成 Map<key, List>; 默认使用 HashMap
public static <T, K> Collector<T, ?, Map<K, List<T>>>
groupingBy(Function<? super T, ? extends K> classifier) // classifier 为分类的映射函数,将输入参数转变为对应的 key
-
roupingBy(Function, Collector)
// 对输入的元素进行 group by 操作,该分类按照 classifier 转换函数将传入的元素进行转换为对应的 key,然后按照 downstrem 继续进行 reduction 操作。 public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, // 分类转换函数 classifier Collector<? super T, A, D> downstream) { // 完成分类之后继续进行的下一步 reduction 操作 return groupingBy(classifier, HashMap::new, downstream); }
-
groupingBy(Function, Suppiler, Collector)
// 与上文 groupingBy 一致,通过 mapFactory 提供的 Map 存储结果。 public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier, Supplier<M> mapFactory, Collector<? super T, A, D> downstream)
f3 = f1.andThen(f2)
—>f3 = f2(f1)
f3 = f1.compose(f2)
—>f3 = f1(f2)
一个容器对象可能包含或者不包含值,如果这个容器对象包含有值,那么isPresent()
方法将会返回 true
并且 get()
方法将会返回这个值。
一些额外的方法依赖于容器中的值是否存在,如 orElse()
方法在容器中不存在值的情况下返回一个默认值,ifPresent()
执行一个代码块如果值存在的话。
这是一个基于值的类,一些 identity-sensitive 操作,如 ==
、synchronization
等在 Optional
实例上 将会导致不可预期的结果,应当避免使用它。
-
orElse(T other)
:如果ifPresent()
为true
,返回容器内的结果,否则返回other
。 -
orElseGet(Supplier<? extends T> other)
: 如果ifPresent()
为true
,返回容器内的结果,否则返回other
提供函数的提供对象。 -
ifPresent(Consumer<? super T> consumer)
:如果isPresent()
为true
,调用预期的consumer
消费函数使用value
作为参数,否则什么都不做。 -
map()
(核心)处理工程中为元素不存在时依旧会继续处理,而不会抛出异常 -
flatMap(Function<? super T, Optional<U>> mapper)
不会包装转换过程中存在的Optional
包装。