首先我们可以创建一个实体类Node,属性有title和value。
public class Node {
private String title;
private int value;
}
然后声明一个Node集合。
List<Node> list = new ArrayList<>();
list.add(new Node("测试一", 1));
list.add(new Node("测试二", 10));
list.add(new Node("测试三", 99));
这两个方法是把集合转化成流,其中parallelStream() 是并行流方法,能够让数据集执行并行操作。
把流转为List类型。
筛选数据,将T中满足条件的元素过滤出来。将上述三个方法组合使用,就可以过滤出一个满足固定条件的新集合,例如执行下面的代码就会得到一个包含value为1的Node的集合。
list = list.stream()
.filter(node -> node.getValue() == 1)
.collect(Collectors.toList());
去除重复数据,需要注意的是该方法是通过equals()方法来判断是否重复的,所以像例子中的Node类去重时需要重写equals()方法。
如果流中的元素的类实现了 Comparable 接口,即有自己的排序规则,那么可以直接调用 sorted() 方法对元素进行排序,反之则需要调用sorted((T, T) -> int)自己定义排序规则。示例如下:
list = list.stream()
.sorted((p1, p2) -> p1.getValue() - p2.getValue())
.collect(Collectors.toList());
两者用法相似,limit为只返回前n个元素,skip为去除前n个元素。同时调用两个方法时,根据两者的顺序不同,会先返回/去除前n个元素,再去除/返回m个元素,示例如下:
list = list.stream()
.limit(2)
.skip(1)
.collect(Collectors.toList());
类型转换,将T元素映射为R元素,如下面的代码就是返回了一个值为原集合的title的新String集合。同时还展示了另一种写法,调用Node类的getTitle()可以写为Node::getTitle。
List<String> newlist = list.stream().map(Node::getTitle).collect(Collectors.toList());
将流中的每一个元素 T 映射为一个流,再把所有流连接成为一个流,如下面的例子就是是把 List 中每个字符串元素以","分割开,变成一个新的 List。
List<String> list = new ArrayList<>();
list.add("aaa,bbb,ccc");
list.add("ddd,eee,fff");
list.add("ggg,hhh,iii");
list = list.stream().map(s -> s.split(","))
.flatMap(Arrays::stream).collect(Collectors.toList());
首先 map 方法分割每个字符串元素,但此时流的类型为 String[],因为 split 方法返回的是 String[] 类型;所以我们需要使用 flatMap 方法,先使用Arrays::stream将每个 String[] 元素变成一个 String 流,然后 flatMap 会将每一个流连接成为一个流,最终返回我们需要的 String集合。
这三个方法相似,都是判断方法,anyMatch是判断流中是否有任一符合条件的元素,allMatch是判断流中是否所有元素都符合条件,noneMatch是判断流中是否没有元素符合条件。示例如下:
boolean b = list.stream()
.anyMatch(Node -> Node.getValue() == 1);
findAny()在使用 stream() 时找到的是第一个元素,使用 parallelStream() 并行时找到的是其中一个元素;findFirst()为找到第一个元素。这两个方法返回的是一个Optional对象,该对象为一个容器类,能代表一个值存在或不存在。
用于组合或处理流中的元素,如求和,求积,求最大值等。示例如下:
//计算value总和:
int sum = list.stream().map(Node::getValue)
.reduce(0, (a, b) -> a + b);
//另一种写法:
int sum = list.stream().map(Node::getValue)
.reduce(0, Integer::sum);
其中第一个参数0代表起始值为0,若不传起始值,则要考虑结果可能不存在的情况,因此返回的是 Optional 类型,示例如下:
Optional<Integer> sum = list.stream().map(Node::getValue)
.reduce(Integer::sum);
该方法会返回流中元素的个数。
该方法无返回结果,可以当作普通的循环使用,例如直接打印每个元素,示例如下:
list.stream().forEach(System.out::println);
该部分主要记录一些个人对于Stream流的应用,不定期更新。
利用Stream流可以很方便的组织出树形结构的数据,示例如下:
首先我们可以先建立一个树形数据的基础实体类BaseTree。
public class BaseTree<T> {
private String id;
private String parentId;
private List<T> children;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public List<T> getChildren() {
return children;
}
public void setChildren(List<T> children) {
this.children = children;
}
}
然后我们创建实际的数据类TestTree,使其继承BaseTree,这样我们只需要添加需要的数据就可以了。
public class TestTree extends BaseTree<TestTree> {
private String title;
private int value;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
最后写组织树形结构的方法,只要调用getTree方法,传入根节点的parentId和整个集合,就可以得到一个树形结构的集合了。
public static <T extends BaseTree<T>> List<T> getTree(String rootId, List<T> all){
return all.stream()
.filter(m -> Objects.equals(m.getParentId(), rootId))
//.peek(m -> m.setChildren(getChildren(m, all)))
.peek(m -> {
List<T> temp = getTree(m.getId(), all);
if(temp.size()>0){
m.setChildren(temp);
}else{
m.setChildren(null);
}
})
.collect(Collectors.toList());
}
一些较为复杂的统计功能也可以通过stream来实现。比如现在我们有一个这样的类:
public static class Test{
private List<String> a;
public List<String> getA() {
return a;
}
public void setA(List<String> a) {
this.a = a;
}
}
如果需要统计List中所有的a的数量,我们可以这样来统计:
List<Test> lists1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<String> list3 = new ArrayList<>();
list2.add("1");
list2.add("2");
list3.add("5");
list3.add("6");
Test test1 = new Test();
test1.setA(list2);
lists1.add(test1);
Test test2 = new Test();
test2.setA(list3);
lists1.add(test2);
//统计
System.out.println(lists1.stream().map(t -> t.getA().size()).collect(Collectors.summarizingInt(Integer::intValue)).getSum());
其中summarizing相关的方法返回的是一个SummaryStatistics对象,其中包含的值有:
{count=2, sum=4, min=2, average=2.000000, max=2}
我们可以通过get方法来获取其中任意的值。
比如我们要给一个类ApplyArchivalParams的集合分组并统计出每组的元素数量,就可以这样写:
Map<String,Long> tsMap = applyArchivalParams.parallelStream().collect(Collectors.groupingBy(
p->{
return p.getQlr().get(0).getQlrmc() +"-"+ p.getQlr().get(0).getZjh();
},ConcurrentHashMap::new,Collectors.counting()));