前面介绍过很多lamabda表达式的用法,传送门
JAVA8-lambda表达式1
JAVA8-lambda表达式2-集合类api
JAVA8-lambda表达式-并行流,提升效率的利器?
JAVA8-lambda表达式之Optional
现在介绍一种比较通用的编程模式,reduce:reduce 操作可以实现从一组值中生成一个值。比如因为常用而被纳入标准库中
count、 min 和 max 方法
@Test
public void test1() {
// count测试
List list = Stream.of(1,2,3,4,5).collect(Collectors.toList());
// 计算集合中值大于3的个数
long result = list.stream().filter(v -> v> 3).count();
assert result == 2;
// 找出集合中最大值
Integer maxV = list.stream().max(Integer::compareTo).get();
assert maxV == 5;
// 找出集合中最大值
Integer minV = list.stream().min(Integer::compareTo).get();
assert minV == 1;
}
这些方法都是 reduce 操作。
再看一个例子,现在要将上面的数据里面的值进行求和,即1+2+3+4+5=?
如果是传统的写法怎么做呢,用for循环!
@Test
public void test2() {
// 求和
List list = Stream.of(1,2,3,4,5).collect(Collectors.toList());
Integer total = 0;
for (Integer v : list) {
total = total + v;
}
assert total == 15;
}
再看一下reduce的写法,Lambda 表达式就是 reducer, 它执行求和操作, 有两个参数: 传入 Stream 中的当前元素和 acc。 将两个参数相加, acc 是累加器, 保存着当前的累加结果。
total = list.stream().reduce(0, (acc, ele) -> acc + ele).intValue();
assert total == 15;
一个工单审核流程中,把审批人员名字,格式化输出
传统的for循环写法
@Test
public void test4() {
List names = Arrays.asList("张三","李四","王五");
StringBuffer sb = new StringBuffer();
sb.append("[");
for (String name : names) {
if (sb.length() > 1) {
sb.append(", ");
sb.append(name);
}
}
sb.append("]");
System.out.println(sb);
}
输出:[张三, 李四, 王五]
Lambda写法
public void test5() {
List names = Arrays.asList("张三","李四","王五");
StringBuffer sb = new StringBuffer();
sb.append("[");
names.stream().forEach(name -> {
if (sb.length() > 1) {
sb.append(", ");
}
sb.append(name);
});
sb.append("]");
System.out.println(sb);
}
用了lambda的forEach,不过在这里,forEach还是有点重了,没有达到用高级收集器简化代码的目的,再用reduce试试
reduce写法
public void test6() {
List names = Arrays.asList("张三", "李四", "王五");
StringBuffer sb = names.stream().reduce(new StringBuffer(), (builder, name) -> {
if (builder.length() > 1) {
builder.append(", ");
}
builder.append(name);
return builder;
}, (left, right) ->
left.append(right)
);
sb.insert(0, "[");
sb.append("]");
System.out.println(sb);
}
上面3种写法都能实现结果,但是不知道有没有发现,lambda表达式,不管是forEach,reduce并没有使代码易读,反而理难理解了。所以定制一个收集器来实现这个需求
实现 Collector 接口
import java.util.HashSet;
import java.util.Set;
import java.util.StringJoiner;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class StringCollector implements Collector {
private String delimiter;
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public String getDelimiter() {
return delimiter;
}
public String getSuffix() {
return suffix;
}
public StringCollector(String delimiter, String prefix, String suffix) {
this.delimiter = delimiter;
this.prefix = prefix;
this.suffix = suffix;
}
/**
* A function that creates and returns a new mutable result container.
*
* @return a function which returns a new, mutable result container
*/
@Override
public Supplier supplier() {
return () -> new StringJoiner(delimiter, prefix, suffix);
}
/**
* A function that folds a value into a mutable result container.
*
* @return a function which folds a value into a mutable result container
*/
@Override
public BiConsumer accumulator() {
return StringJoiner::add;
}
/**
* A function that accepts two partial results and merges them. The
* combiner function may fold state from one argument into the other and
* return that, or may return a new result container.
*
* @return a function which combines two partial results into a combined
* result
*/
@Override
public BinaryOperator combiner() {
return StringJoiner::merge;
}
/**
* Perform the final transformation from the intermediate accumulation type
* {@code A} to the final result type {@code R}.
*
* If the characteristic {@code IDENTITY_TRANSFORM} is
* set, this function may be presumed to be an identity transform with an
* unchecked cast from {@code A} to {@code R}.
*
* @return a function which transforms the intermediate result to the final
* result
*/
@Override
public Function finisher() {
return StringJoiner::toString;
}
/**
* Returns a {@code Set} of {@code Collector.Characteristics} indicating
* the characteristics of this Collector. This set should be immutable.
*
* @return an immutable set of collector characteristics
*/
@Override
public Set characteristics() {
return new HashSet();
}
}
由于 Collector 接口支持泛型, 因此先得确定一些具
体的类型:
然后来使用它
@Test
public void test7() {
List names = Arrays.asList("张三", "李四", "王五");
String result = names.stream().collect(new StringCollector(",","[", "]"));
System.out.println(result);
}
输出结果与前面一致:[张三,李四,王五]
到此,一个定制化的收集器就开发完成了。
一个收集器由四部分组成
/**
* A function that creates and returns a new mutable result container.
*
* @return a function which returns a new, mutable result container
*/
@Override
public Supplier supplier() {
return () -> new StringJoiner(delimiter, prefix, suffix);
}
所以在StringCollector声明需要传入的参数:分割符-delimiter,前缀prefix,后缀-suffix及对应的构造函数
private String delimiter;
private String prefix;
private String suffix;
public String getPrefix() {
return prefix;
}
public String getDelimiter() {
return delimiter;
}
public String getSuffix() {
return suffix;
}
public StringCollector(String delimiter, String prefix, String suffix) {
this.delimiter = delimiter;
this.prefix = prefix;
this.suffix = suffix;
}
/**
* A function that folds a value into a mutable result container.
*
* @return a function which folds a value into a mutable result container
*/
@Override
public BiConsumer accumulator() {
return StringJoiner::add;
}
/**
* A function that accepts two partial results and merges them. The
* combiner function may fold state from one argument into the other and
* return that, or may return a new result container.
*
* @return a function which combines two partial results into a combined
* result
*/
@Override
public BinaryOperator combiner() {
return StringJoiner::merge;
}
/**
* Perform the final transformation from the intermediate accumulation type
* {@code A} to the final result type {@code R}.
*
* If the characteristic {@code IDENTITY_TRANSFORM} is
* set, this function may be presumed to be an identity transform with an
* unchecked cast from {@code A} to {@code R}.
*
* @return a function which transforms the intermediate result to the final
* result
*/
@Override
public Function finisher() {
return StringJoiner::toString;
}
/**
* Returns a {@code Set} of {@code Collector.Characteristics} indicating
* the characteristics of this Collector. This set should be immutable.
*
* @return an immutable set of collector characteristics
*/
@Override
public Set characteristics() {
return new HashSet();
}