平时在编写前端代码时,习惯使用lodash来编写‘野生’的JavaScript;
lodash提供来一套完整的API对JS对象(Array,Object,Collection等)进行操作,这其中就包括_.groupBy 和 _.reduce,即分组和'聚合'(reduce不知道该怎么翻译合适)。
使用这些‘野生’的API能够极大的提高我本人编写JS代码的效率。而JAVA8开始支持stream和lambda表达式,这些和lodash的API有很多类似的功能。因此我在熟悉lodash的前提下尝试使用JAVA8的新特性减少冗余代码的编写。
在开发后端某功能接口的过程中,需要对一个从数据库中取出的数据List<T>进行按照ID进行聚合统计
<U> U reduce(U u,BiFunction<U,? super T,U> accumulator,BinaryOperator<U> combiner) #第一个参数返回实例u,传递你要返回的U类型对象的初始化实例u #第二个参数累加器accumulator,可以使用二元ℷ表达式(即二元lambda表达式),声明你在u上累加你的数据来源t的逻辑 #例如(u,t)->u.sum(t),此时lambda表达式的行参列表是返回实例u和遍历的集合元素t,函数体是在u上累加t #第三个参数组合器combiner,同样是二元ℷ表达式,(u,t)->u #lambda表达式行参列表同样是(u,t),函数体返回的类型则要和第一个参数的类型保持一致
#1.声明一个返回结果U #2.对List<T>进行遍历,在U和每个T实例上应用一个累加器进行累加操作 #3.返回最终结果U U result = identity; for (T element : this stream) result = accumulator.apply(result, element) return result;
var source = [ {"name": "A","type": "san","typeValue": 1.0,"count": 2}, {"name": "A","type": "nas","typeValue": 13.0,"count": 1}, {"name": "B","type": "san","typeValue": 112.0,"count": 3}, {"name": "C","type": "san","typeValue": 43.0,"count": 5}, {"name": "B","type": "nas","typeValue": 77.0,"count": 7} ]; var target = [ { "name": "A", "count": 3, "totalTypeValue": 14.0, "bazList": [ { "type": "san", "typeValue": 1.0 }, { "type": "nas" "typeValue": 13.0 } ] }, { "name": "B", "count": 10, "totalTypeValue": 189.0, "bazList": [ { "type": "san", "typeValue": 112.0 }, { "type": "nas" "typeValue": 77.0 } ] }, { "name": "C", "count": 5, "totalTypeValue": 43.0, "bazList": [ { "type": "san", "typeValue": 43.0 } ] } ];
讲了那么多废话,这个才是最直接的
对 List<Foo> 按照name分组统计得到 List<Bar>
import com.google.common.collect.Lists; import Bar; import Foo; import java.util.List; import java.util.stream.Collectors; public class ReduceTest { public static void main(String[] args) throws Exception{ List<Foo> fooList = Lists.newArrayList( new Foo("A","san",1.0,2), new Foo("A","nas",13.0,1), new Foo("B","san",112.0,3), new Foo("C","san",43.0,5), new Foo("B","nas",77.0,7) ); List<Bar> barList = Lists.newArrayList(); fooList .stream() .collect(Collectors.groupingBy(Foo::getName,Collectors.toList())) .forEach((name,fooListByName)->{ Bar bar = new Bar(); bar = fooListByName .stream() .reduce(bar,(u,t)->u.sum(t),(u,t)->u); System.out.println(bar.toString()); barList.add(bar); }); } /* 输出结果 name:A count:3 totalTypeValue:14.0 bazList: type:san typeValue:1.0 type:nas typeValue:13.0 name:B count:10 totalTypeValue:189.0 bazList: type:san typeValue:112.0 type:nas typeValue:77.0 name:C count:5 totalTypeValue:43.0 bazList: type:san typeValue:43.0 */ }
public class Foo{ private String name; private String type; private Double typeValue; private Integer count; public Foo(String name, String type, Double typeValue, Integer count) { this.name = name; this.type = type; this.typeValue = typeValue; this.count = count; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } public Double getTypeValue() { return typeValue; } public void setTypeValue(Double typeValue) { this.typeValue = typeValue; } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } }
import com.google.common.collect.Lists; import java.util.List; public class Bar{ private String name; private Integer count; private Double totalTypeValue; private List<Baz> bazList; public Bar() { this.name = null; this.count = 0; this.totalTypeValue = 0.0; this.bazList = Lists.newArrayList(); } public Bar sum(Foo foo){ if(name == null){ this.name = foo.getName(); } this.count += foo.getCount(); this.totalTypeValue += foo.getTypeValue(); this.bazList.add(new Baz(foo.getType(),foo.getTypeValue())); return this; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("name:").append(this.name).append(System.lineSeparator()); sb.append("count:").append(this.count).append(System.lineSeparator()); sb.append("totalTypeValue:").append(this.totalTypeValue).append(System.lineSeparator()); sb.append("bazList:").append(System.lineSeparator()); this.bazList.forEach(baz->{ sb.append("/t").append("type:").append(baz.getType()).append(System.lineSeparator()); sb.append("/t").append("typeValue:").append(baz.getTypeValue()).append(System.lineSeparator()); }); return sb.toString(); } }
public class Baz{ private String type; private Double typeValue; public Baz(String type, Double typeValue) { this.type = type; this.typeValue = typeValue; } public String getType() { return type; } public void setType(String type) { this.type = type; } public Double getTypeValue() { return typeValue; } public void setTypeValue(Double typeValue) { this.typeValue = typeValue; } }
等下次有空补上不使用stream().reduce 实现同样操作的比较繁琐的代码,啦啦啦啦啦~~~