美文网首页
java-stream

java-stream

作者: wyc0859 | 来源:发表于2021-02-01 15:35 被阅读0次

Stream(流):以一种声明的方式处理数据。

是一个来自数据源的元素队列并支持聚合操作,比如filter, map, reduce, find, match, sorted等。
特点:
1 . 不是数据结构,不会保存数据。
2. 不会修改原来的数据源,它会将操作后的数据保存到另外一个对象中。(保留意见:毕竟peek方法可以修改流中元素)
3. 惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算。

IntStream、LongStream 和 DoubleStream 分别表示原始 int 流、 原始 long 流 和 原始 double 流。
这三个原始流类提供了大量的方法用于操作流中的数据,同时提供了相应的静态方法来初始化它们自己。
这三个原始流类都在 java.util.stream 命名空间下。

Stream中的静态方法:of()、iterate()、generate()

iterate()
使用Stream.iterate的最主要作用是抽象迭代逻辑,替代Iterator。Iterator的实现太重,不但需要新建一个class,而且迭代逻辑被分离成了hasNext和next两部分
相对来说,用Stream.iterate来抽象迭代逻辑就方便得多,而且写好之后可以随便扩展,使用filter,map,flatMap,takeWhile,dropWhile等方法得到新的Stream返回给客户代码

 Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 2).limit(6);
 stream2.forEach(System.out::println); // 0 2 4 6 8 10       

generate()

 Stream<Double> stream3 = Stream.generate(Math::random).limit(2);
 stream3.forEach(System.out::println);   //0.13511523827758753   0.9366387392872296

reduce

Stream API提供了一些预定义的reduce操作,比如count(), max(), min(), sum()等。
如果我们需要自己写reduce的逻辑,则可以使用reduce方法。
Stream类中有三种reduce,分别接受1个参数,2个参数,和3个参数
1个参数:

List<Integer> num = Arrays.asList(1, 2, 4, 5, 6, 7);
        Integer result = num.stream().reduce((x, y) -> {
            System.out.println("x:"+x);
            return x + y;
        }).get();
System.out.println("resutl:"+result);

2个参数:

 List<Integer> num = Arrays.asList(1, 2, 3, 4, 5, 6);
        Integer result = num.stream().reduce(0,(x, y) -> {
            System.out.println("x:" + x);
            return x + y;
        });
System.out.println("resutl:" + result);

Stream 基础示例

  @Test
    public void map_map(){
        Map<String,String> map1 = new HashMap<>();
        map1.put("dan", "good");
        map1.put("Jess", "Good");
        map1.put("Jaxon", "Bad");
        map1.put("Maggie", "Great");
        map1.put("Allie", "Bad");
        System.out.println("MAP:" + toJsonString(map1.entrySet())); //HashSet集合
        //MAP:[{"dan":"good"},{"Jaxon":"Bad"},{"Jess":"Good"},{"Allie":"Bad"},{"Maggie":"Great"}]
        Map<String,String> map2 = map1.entrySet().stream().filter(x ->
                !x.getKey().equals("dan") && !x.getKey().equals("Allie"))
                .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
        System.out.println(toJsonString(map2)); //{"Jaxon":"Bad","Jess":"Good","Maggie":"Great"}
    }

    @Test
    public void list_map(){
        ArrayList<String> alist = new ArrayList<>();
        alist.add("a");
        alist.add("b");
        alist.add("c");
        alist.add("a");
        System.out.println("1:  " + alist);
        Map<String, String> collect = alist.stream().collect(
                Collectors.toMap(x -> x, x -> {
                    return x+"!";
                },(n1, n2) -> {
                    System.out.println("只会执行一次" + n1 + ":" + n2);
                    return n2+"x";
                }));
        System.out.println(toJsonString(collect));  //{"a":"a!x","b":"b!","c":"c!"}
    }

    @Test
    public void stream_map(){
        Map<String, String> collect = Stream.of("a","b","c","d").collect(
                Collectors.toMap(x -> x, x -> x+x,(n1, n2) -> n2,TreeMap::new));
        System.out.println(toJsonString(collect));  //{"a":"aa","b":"bb","c":"cc","d":"dd"}
    }

Stream 示例

 public class stream {
    String strlist="[{\"颜色\":\"红1\",\"大小\":\"128\",\"price\":\"11\",\"stock_num\":\"22\"},\n" +
            "{\"颜色\":\"红2\",\"大小\":\"258\",\"price\":\"33\",\"stock_num\":\"44\"},\n" +
            "{\"颜色\":\"黄3\",\"大小\":\"128\",\"price\":\"11\",\"stock_num\":\"66\"},\n" +
            "{\"颜色\":\"黄4\",\"大小\":\"258\",\"price\":\"77\",\"stock_num\":\"44\"}]";

    @Test
    public void test1(){
        // Collectors.toList():转换成List集合。/ Collectors.toSet():转换成set集合。
        System.out.println(Stream.of("a", "b", "c","a").collect(Collectors.toSet()));   //[a, b, c]
        System.out.println(Stream.of("a", "b", "c","a").collect(Collectors.toList()));   //[a, b, c, a]

        // Collectors.toCollection(TreeSet::new):转换成特定的set集合。
        TreeSet<String> treeSet = Stream.of("a", "c", "b", "a").collect(Collectors.toCollection(TreeSet::new));
        System.out.println(treeSet); //[a, b, c]

        //Collectors.joining(","):拼接字符串。    //结果: 1,3,3,2
        System.out.println(Stream.of("1", "3", "3", "2").collect(Collectors.joining(",")));

        //Collectors.mapping(...):跟Stream的map操作类似,只是参数有点区别
        System.out.println(Stream.of(1, 3, 5).collect(Collectors.mapping(x -> x + 1, Collectors.toList())));
        //[2, 4, 6]

        // Collectors.toMap(keyMapper, valueMapper, mergeFunction):转换成map。
        Map<String, String> collect = Stream.of("a", "b", "c", "a").collect(
                Collectors.toMap(x -> x, x -> x +"!",(oldVal, newVal) -> newVal));
        System.out.println(toJsonString(collect));  //{"a":"a!","b":"b!","c":"c!"}


        //可以获取最大值、最小值、平均值、总和值、总数。
        //求最小值,相对应的当然也有maxBy方法。
        Optional<Integer> int2 = Stream.of(1, 3, 4).collect(Collectors.minBy(Integer::compare));
        System.out.println(int2.orElseThrow(null)); //1

        Map<Integer, List<Integer>> map = Stream.of(1, 3, 3, 2, 1).collect(Collectors.groupingBy(Function.identity()));
        System.out.println(map);    //{1=[1, 1], 2=[2], 3=[3, 3]}

        //summingInt 求和
        Map<Integer, Integer> map1 = Stream.of(1, 3, 3, 2, 1).collect(Collectors.groupingBy(Function.identity(),
                Collectors.summingInt(x -> x)
        ));
        System.out.println(map1);  //{1=2, 2=2, 3=6}

        HashMap<Integer, List<Integer>> hashMap = Stream.of(1, 3, 3, 2, 1).collect(Collectors.groupingBy(Function.identity(),
                HashMap::new, Collectors.mapping(x -> x + 1, Collectors.toList())));
        System.out.println(hashMap); //{1=[2, 2], 2=[3], 3=[4, 4]}

        //Collectors.partitioningBy(x -> x > 2),把数据分成两部分,key为ture/false。第一个方法也是调用第二个方法,
        // 第二个参数默认为Collectors.toList()
        Map<Boolean, List<Integer>> map2 = Stream.of(1, 3, 3, 2).collect(Collectors.partitioningBy(x -> x > 2));
        Map<Boolean, Long> longMap = Stream.of(1, 3, 3, 2).collect(Collectors.partitioningBy(x -> x > 1, Collectors.counting()));
        System.out.println(toJsonString(map2)); //{false:[1,2],true:[3,3]}
        System.out.println(toJsonString(longMap)); //{false:1,true:3}
    }

    /**
     * 1、Stream中of方法传入可变参数
     * 2、Stream中map元素类型转化方法
     * 3、Function匿名接口,people匿名对象的使用
     * 4、String中split切割方法
     * 5、Lambda表达式
     * 匿名对象也可以使用Lambda替换,达到精简的效果,因为了便于理解只在forEach遍历下使用了Lambda表达式)。
     */
    @Test
    public void test3(){
        Stream.of("小王:18","小杨:20").map(new Function<String, People>() {
            @Override
            public People apply(String s) {
                String[] str = s.split(":");
                People people = new People(str[0],Integer.valueOf(str[1]));
                return people;
            }
        }).forEach(people-> System.out.println( people));
        //打印:{name='小王', age=18}
        //打印:{name='小杨', age=20}
    }

    @Test
    public void test4(){

//         List<Map<String,String>> skuList = toList(strlist, JSONObject.class);
//        this.merge(skuList,"stock_num");

        List<Map<String,Object>> skuList = toList(strlist, JSONObject.class);
        this.order(skuList);
    }


    //从集合中过滤出来符合条件的元素:
    @Test
    public void  filter(){
        List<Map<String,Object>> skuList = toList(strlist, JSONObject.class);
        //原本是一个list,stream后也是需要一个返回类型的,所以.collect(Collectors.toList())不能少
        List<Map<String,Object>> filterList = skuList.stream().filter(a -> a.get("price").equals("55")).collect(Collectors.toList());
        System.err.println("filterList:"+filterList);   //filterList:[{"大小":"128","颜色":"黄","price":"55","stock_num":"66"}]
    }

    /**
     * 合并两个具有相同key的map为list
     * @param m1 要合并的list
     * @param mergeKey 以哪个key为基准合并
     * @return
     */
    public static List<Map<String, String>> merge(List<Map<String, String>> m1, String mergeKey){
        Set<String> set = new HashSet<>();
        List<Map<String, String>> reslist=m1.stream()
                .filter(map->map.get(mergeKey)!=null)
                .collect(Collectors.groupingBy(o->{
                    set.addAll(o.keySet());//暂存所有key
                    return o.get(mergeKey).toString(); //按mergeKey分组
                }))
                .entrySet().stream().map(o->{
                    Map<String, String> map = o.getValue().stream().flatMap(m->{ //合并
                        return m.entrySet().stream();
                    }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a,b)->b));
                    set.stream().forEach(k->{//为没有的key赋值0
                        if(!map.containsKey(k)) map.put(k, "0");
                    });
                    return map;
                }).collect(Collectors.toList());
        System.out.println(toJsonString(reslist));
        //[{"大小":"128","颜色":"黄3","price":"11","stock_num":"66"},{"大小":"258","颜色":"黄4","price":"77","stock_num":"44"},
        // {"大小":"128","颜色":"红1","price":"11","stock_num":"22"}]
        return reslist;
    }


    public void order(List<Map<String, Object>> list){
        List<Map<String, Object>> list2 = new ArrayList<>();
        list2.addAll(list);
        List<Map<String, Object>> collect = list.stream().filter(x->{
            long count = list2.stream().filter(x2->x2.get("stock_num").equals(x.get("stock_num"))).count();
            if(count>1) {  //过滤订单数小于2的 ,这种需求很少
                return true;
            }
            return false;
        }).collect(Collectors.groupingBy(x->x.get("stock_num"))).entrySet().stream().map(x->{
            Map<String, Object> tmp = new HashMap<>();
            tmp.put("v", x.getValue());
            tmp.put("k", x.getKey());
            return tmp;  //分组展示重复的订单数据
        }).collect(Collectors.toList());

        System.out.println("collect:    "+toJsonString(collect));   //没有分组C,因为C只有一单 count>1
    }

    @Test
    public void common(){
        List<Apple> appleList = new ArrayList<>();//存放apple对象集合

        Apple apple1 =  new Apple(1,"苹果1",new BigDecimal("3.25"),10);
        Apple apple2 = new Apple(1,"苹果2",new BigDecimal("1.35"),20);
        Apple apple3 =  new Apple(2,"香蕉",new BigDecimal("2.89"),30);
        Apple apple4 =  new Apple(3,"荔枝",new BigDecimal("9.99"),40);

        appleList.add(apple1);
        appleList.add(apple2);
        appleList.add(apple3);
        appleList.add(apple4);

        //List 以ID分组 Map<Integer,List<Apple>>
        Map<Integer, List<Apple>> groupBy = appleList.stream().collect(Collectors.groupingBy(Apple::getId));
        System.out.println("以ID分组:" + toJsonString(groupBy));

        //id为key,apple对象为value
        Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));
        System.out.println("id为key:" + toJsonString(appleMap));

        //从集合中过滤出来符合条件的元素:
        List<Apple> filterList = appleList.stream().filter(a -> a.getName().equals("香蕉")).collect(Collectors.toList());
        System.out.println("筛选符合条件的数据:" + toJsonString(filterList));

        //将集合中的数据按照某个属性求和:
        BigDecimal totalMoney = appleList.stream().map(Apple::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        System.out.println("求和:" + toJsonString(totalMoney));

        // 根据id去重
        List<Object> unique = appleList.stream().collect(collectingAndThen(
                toCollection(() -> new TreeSet<>(comparingLong(Apple::getId))), ArrayList::new)
        );
        System.out.println("根据id去重:" + toJsonString(unique));
    }

    @Test
    public void users(){
        List<User> userList = Lists.newArrayList(
                new User().setId("A").setName("1张三"),
                new User().setId("A").setName("2李四"),    //new User().setId("B").setName("李四"),
                new User().setId("C").setName("3王五"),
                new User().setId("D").setName("4赵六"),
                new User().setId("A").setName("5杨七")
        );
        System.out.println("userList:" + toJsonString(userList));

        //过去的做法(循环):
        Map<String, String> map = new HashMap<>();
        for (User user : userList) {
            map.put(user.getId(), user.getName());
        }
        System.out.println("map:" + toJsonString(map)); //{"A":"杨七","C":"王五","D":"赵六"}


//        Map<String, String> map2 = userList.stream().collect(Collectors.toMap(User::getId, User::getName));
//        System.out.println("map2:" + toJsonString(map2));
        //如果存在重复元素,如setId("B")改为setId("A"),如上就会报错,但如下才是正确

/*        Map<String, String> map3 = userList.stream().collect(Collectors.toMap(User::getId, User::getName, (n1, n2) -> n1 + n2));
        System.out.println("map3:" + toJsonString(map3));   //{"A":"张三李四杨七","C":"王五","D":"赵六"}

       Map<String, String> map3 = userList.stream().collect(Collectors.toMap(User::getId, User::getName, (n1, n2) -> {
            String str=n1 + n2;
            return str;
        }));
        System.out.println("map3:" + toJsonString(map3));  //{"A":"张三李四杨七","C":"王五","D":"赵六"}*/

        //第四参数用于自定义返回 Map 类型,比如希望返回Map是根据Key排序的,可如下:
        Map<String, String> map3 = userList.stream().collect(
                Collectors.toMap(User::getId, User::getName, (n1, n2) -> n1,TreeMap::new)
        );
        System.out.println("map3:" + toJsonString(map3));   //{"A":"1张三","C":"3王五","D":"4赵六"}
    }
}

@Getter
@Setter
class Apple {
    private Integer id;
    private String name;
    private BigDecimal money;
    private Integer num;

    public Apple(Integer id, String name, BigDecimal money, Integer num) {
        this.id = id;
        this.name = name;
        this.money = money;
        this.num = num;
    }
}

@Accessors(chain = true) // 链式方法   new User().setId("A").setName("张三"),
@lombok.Data    // User::getId
class User {
    private String id;
    private String name;
}



@Setter
@Getter
class People {
    private String name;
    private int age;

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "打印:{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

相关文章

  • java-stream

    Stream(流):以一种声明的方式处理数据。 是一个来自数据源的元素队列并支持聚合操作,比如filter, ma...

  • java-stream(下)

    转载文章 上一篇文章我讲解 Stream 流的基本原理,以及它的基本方法使用,本篇文章我们继续讲解流的其他操作没有...

  • java-stream(上)

    转载文章 Java 8 发布至今也已经好几年过去,如今 Java 也已经向 11 迈去,但是 Java 8 作出的...

  • java-stream(一)

    吾尝终日而思矣,不如须臾之所学以。 这个流是干啥的? 流可以简单理解为,把我们业务中数据过滤,分页,求和,分类汇总...

  • java-stream(二)

    源码是如何实现的 我们随便其中一个方法,比如filter,然后在ReferencePipeline类中找到方法的实...

  • Java-Stream实现生成质数的无限流

    思路:使用Strream.generate方法 代码实现IntSupplier,而不是用Lambda表达式,是为了...

网友评论

      本文标题:java-stream

      本文链接:https://www.haomeiwen.com/subject/uaurtltx.html