一、什么是Stream
Stream(流)是一个来自数据源的元素队列并支持聚合操作
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
Stream流中几种经常使用的API:
1.1Filter
public class TestLambda {
public static void main(String[] args) {
List<String> strings = Arrays.asList("abc","","bc","efg","abd","");
List<String> filtered = strings.stream().filter(string->!string.isEmpty()).collect(Collectors.toList());
System.out.println("集合的大小"+filtered.size());
for (String s : filtered) {
System.out.print(s+" ");
}
}
}
由上边的输出结果可以看到,filter的作用就是能够通过filter设置过滤条件去除掉List中的null值或者空值。
1.2Map
public class TestMap {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3,2,2,3,7,9,5);
//获取对应的平方数
List<Integer> squaresList = numbers.stream().map(i->i*i).collect(Collectors.toList());
for (Integer integer : squaresList) {
System.out.println("平方后integer = " + integer);
}
}
}
map 方法用于映射每个元素到对应的结果,并按照相对应的顺序保存在新的集合中。
1.3limit
public class TestLimit {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3,2,2,3,7,9,5);
List<Integer> limitList = numbers.stream().limit(3).collect(Collectors.toList());
System.out.println("使用过limit后的集合大小"+limitList.size());
}
}
1.4Sorted
public class TestLimit {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3,2,2,3,7,9,5);
List<Integer> sortList = numbers.stream().sorted().collect(Collectors.toList());
System.out.println("排序后的集合"+sortList);
//在对象list集合中排序的时候,可以通过某一个属性排序
List<Transaction> collect = transactions.stream().filter(s -> s.getYear() == 2011).sorted(Comparator.comparing(Transaction::getMount)).collect(Collectors.toList());
//得到的结果是升序排列
Collections.reverse(collect);//将结果进行倒序排列
System.out.println("collect = " + collect);
}
}
1.5Foreach
public class TestLimit {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3,2,2,3,7,9,5);
//遍历集合
numbers.stream().forEach(System.out::println);
}
}
代码中的System.out::println,可以这样理解,::前边的是你定义的某个实体类,::后边的是你实体类的某个方法的名字。
1.6skip
public class SkipTest {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(3,2,2,3,7,9,5);
List <Integer> list1 = numbers.stream().skip(2).collect(Collectors.toList());//跳过集合元素原本的前两个
System.out.println("list1 = " + list1);
}
}
1.7将集合合并
public class ConcatTest {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("集合1");
List<String> list2 = new ArrayList<>();
list2.add("集合2");
list2.add("集合2");
//distinct()这个是为了去重
List<String> collect = Stream.of(list1,list2).flatMap(Collection::stream).distinct().collect(Collectors.toList());
System.out.println("两个相同类型的集合合并后collect = " + collect);
//Stream流中的map就是简单的将数据映射,flatmap是将传入的所有流(这里的所有流在这里因为使
//用的字符串类型的,所以就是字符串中每一个字符都会变成一个单独的流),最终这些流汇集到一起
//再合并为一个流
//Function.identity()这个是为了保证输入和输出流类型保持一致
String[] arr = {"数组1"};
List<String> collect2 = Stream.of(list1.stream(), Arrays.stream(arr)).flatMap(Function.identity()).collect(Collectors.toList());
System.out.println("两种不同类型的集合合并后collect2 = " + collect2);
}
}
1.8针对double数据的处理计算平均值
list.stream().mapToDouble(User::getAge).sum()//和
list.stream().mapToDouble(User::getAge).max()//最大
list.stream().mapToDouble(User::getAge).min()//最小
list.stream().mapToDouble(User::getAge).average()//平均值
在项目中使用的情景
Stream<Double> doubleStream = worksheetDOS.stream().map(s -> Double.valueOf(s.getHandingTimes()));
//获取到workSheetDOS这个list集合对应的Double数据的stream流
OptionalDouble average = doubleStream.mapToDouble(Double::doubleValue).average();//Double::doubleValue拿到流中的Double数据
二.项目中用到的Stream流
TyTaskDO tyTaskDO = tyTaskDOS.stream().filter(t -> StringUtil.equals(t.getTaskStatus(), status)).findFirst().orElse(null);
2.1 findFirst
这个Api是说找到符合条件的集合中第一个元素并返回,如果没有就会使用orelse这个api来返回null
2.2 GroupBy
public class CollectorTest {
public static void main(String[] args) {
Product product3 = new Product("啤酒", "a");
Product product2 = new Product("啤酒", "b");
Product product = new Product("零食", "c");
Product product1 = new Product("零食", "d");
List<Product> productList = new ArrayList<Product>();
productList.add(product);
productList.add(product1);
productList.add(product2);
productList.add(product3);
Map<String,List<Product>> proMap = productList.stream().collect(Collectors.groupingBy(Product::getId));
System.out.println("按照id进行商品的分类");
for (String s : proMap.keySet()) {
System.out.println(proMap.get(s));
}
}
}
这个APi中的groupby就是按照id对集合中的数据进行分组,得到的一个以id为key的map集合,适用于电商项目中的分类
三.高级用法
根据关键字去除集合中重复的元素
ArrayList<User> collect1 = users.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(a -> a.getName()))), ArrayList::new));
根据对象中某个最大值查询对应的对象
User user = users.stream().collect(Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(User::getNum)), (Optional<User> us11) -> us11.orElse(null)));
根据对象中某个最大值查询对应对象的某个属性
String name = users.stream().collect(Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(User::getNum)), (Optional<User> user6) -> user6.map(User::getName).orElse(null)));
计算集合中的平均值
users.stream().collect(Collectors.collectingAndThen(Collectors.averagingDouble(User::getNum),Double::doubleValue));
将集合对象的某个属性值以","隔开拼接成字符串
String name = users.stream().map(User::getName).collect(Collectors.joining(","));
判断两个list集合中不同元素有哪些
public static Collection getSameListByMap(Collection collmax, Collection collmin) {
//使用LinkedList防止差异过大时,元素拷贝
Collection csReturn = new LinkedList();
Collection max = collmax;
Collection min = collmin;
//先比较大小,这样会减少后续map的if判断次数
if (collmax.size() < collmin.size()) {
max = collmin;
min = collmax;
}
//直接指定大小,防止再散列
Map<Object, Integer> map = new HashMap<Object, Integer>(max.size());
for (Object object : max) {
map.put(object, 1);
}
for (Object object : min) {
if (map.get(object) != null) {
csReturn.add(object);
}
}
return csReturn;
}