Java8使用流操作集合

Java8集合操作正确方式

  • 流Api是Java8提供的新的api,用来声明式地处理数据集合。

1 一个Demo案例:

  • 需要将List集合中的重量大于0.3kg的水果筛选出来进行排序后拿出它的名字最后放到另一个List中去。
      
        List fruits = new ArrayList<>();
        fruits.add(new Fruit("Apple", 0.8));
        fruits.add(new Fruit("orange", 0.3));
        fruits.add(new Fruit("watermelon", 1.2));
        fruits.add(new Fruit("banana", 0.6));

        //java8之前的做法
//        List tempList = new ArrayList<>();
//        for(Fruit fruit : fruits){
//            if(fruit.getWeight()>0.3){
//                tempList.add(fruit);
//            }
//        }
//
//        List fruitNames = new ArrayList<>();
//        tempList.sort(new Comparator() {
//            @Override
//            public int compare(Fruit o1, Fruit o2) {
//                return  o1.getWeight().compareTo(o2.getWeight());
//            }
//        });
//
//        for(Fruit fruit :tempList){
//            fruitNames.add(fruit.getName());
//        }
//
//        System.out.println(fruitNames);

        //java8的做法
        List fruitName = fruits.stream().filter(f -> f.getWeight()>0.3).sorted(Comparator.comparing(Fruit::getWeight)).map((Fruit::getName)).collect(Collectors.toList());
        System.out.println(fruitName);

    结果:[banana, Apple, watermelon]
   

通过这个demo,可以很清楚地看到java8对集合的操作非常的简单并且支持对集合的链式操作,而java8之前则需要大量的迭代集合的操作代码重复很多。

2 Java 8中流对集合的处理:

需要一个数据源(如集合),一个中间操作链(过滤、排序、limit等操作),一个终端操作执行流水线并生成结果

3 Stream API支持的操作

    /**
     * 预定义的菜单类
     */
    public class Menu {

        private String name;
        private double weight;
    
        public Menu(String name, double weight) {
            this.name = name;
            this.weight = weight;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public double getWeight() {
            return weight;
        }
    
        public void setWeight(double weight) {
            this.weight = weight;
        }
    
        @Override
        public String toString() {
            return "Menu{" +
                    "name='" + name + '\'' +
                    ", weight=" + weight +
                    '}';
        }
    }
3.1 筛选和切片(filter、distinc、limit、skip)
   public class UsefulOperator {

    public static List factory() {


        Menu meatMenu = new Menu("meat", 8.88);
        List list = Lists.newArrayList();
        list.add(new Menu("fish", 1.98));
        list.add(new Menu("apple", 0.88));
        list.add(new Menu("beaf", 2.18));
        list.add(meatMenu);
        list.add(meatMenu);
        list.add(new Menu("chop", 0.08));

        return list;
    }

    public static void main(String[] args) {
        List list = factory();

        //filter (过滤不符合条件的元素)
        List newMenu = list.stream().filter(w -> w.getWeight() > 0.88).collect(Collectors.toList());
        System.out.println(newMenu);

        //distinct (过滤调一样的元素基于hashcode和equals)
        List newMenu2 = list.stream().distinct().collect(Collectors.toList());
        System.out.println(newMenu2);


        //limit (限制选取前几个元素)
        List newMenu3 = list.stream().limit(2).collect(Collectors.toList());
        System.out.println(newMenu3);

        //skip (限制跳过前几个元素)
        List newMenu4 = list.stream().skip(2).collect(Collectors.toList());
        System.out.println(newMenu4);

    }
}

结果:
[Menu{name=‘fish’, weight=1.98}, Menu{name=‘beaf’, weight=2.18}, Menu{name=‘meat’, weight=8.88}, Menu{name=‘meat’, weight=8.88}]

[Menu{name=‘fish’, weight=1.98}, Menu{name=‘apple’, weight=0.88}, Menu{name=‘beaf’, weight=2.18}, Menu{name=‘meat’, weight=8.88}, Menu{name=‘chop’, weight=0.08}]

[Menu{name=‘fish’, weight=1.98}, Menu{name=‘apple’, weight=0.88}]

[Menu{name=‘beaf’, weight=2.18}, Menu{name=‘meat’, weight=8.88}, Menu{name=‘meat’, weight=8.88}, Menu{name=‘chop’, weight=0.08}]

3.2 映射(map、flatMap)
    //映射

    //map(接受一个函数并且将其映射成一个新的元素)
    List newMenu5 = list.stream().map(Menu::getName).collect(Collectors.toList());
    System.out.println(newMenu5);


    //flatMap 可以将生成的流扁平化为单个流
    List words = Lists.newArrayList("hello", "World");

    //将数组words中不同单词保存下来
    System.out.println(words.stream().map(word -> word.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList()));
    

结果
[fish, apple, beaf, meat, meat, chop]

[h, e, l, o, W, r, d]

3.3 查找和匹配(allMatch、 anyMatch、 noneMatch、 findFirst和findAny)
  
        //判断集合中是否有任何符合条件的元素 终端操作返回boolean
        if (list.stream().anyMatch(m -> m.getWeight() > 1.8)) {
            System.out.println("have right fruit");
        }

        //判断集合的所有元素是否符合条件 终端操作返回boolean
        if (list.stream().allMatch(m -> m.getWeight() > 1.8)) {
            System.out.println("have  all right fruit");
        }


        //集合中是否所有元素都不匹配指定的条件 终端操作返回boolean
        if (list.stream().noneMatch(m -> m.getWeight() > 10)) {
            System.out.println("have none right fruit");
        }


        //返回当前流中的任意元素
        //  //你可能会想,为什么会同时有findFirst和findAny呢?答案是并行。找到第一个元素
        //        //在并行上限制更多。如果你不关心返回的元素是哪个,请使用findAny,因为它在使用并行流
        //        //时限制较少。
        Optional anyMenu = list.stream().findAny();
        System.out.println(anyMenu.toString());

        //返回当前流中第一个元素
        Optional firstMenu = list.stream().findFirst();
        System.out.println(firstMenu.toString());

结果:

have right fruit

have none right fruit

Optional[Menu{name=‘fish’, weight=1.98}]

Optional[Menu{name=‘fish’, weight=1.98}]

3.4 规约(reduce)
    //规约
        //元素求和
        List integers = Lists.newArrayList(1, 2, 3, 4, 5, 6);
        //0代表初始值
        int sum = integers.stream().reduce(0, Integer::sum);
        //可以不指定初始值,返回值变为Optional以防止可能为空的情况
        Optional sum2 = integers.stream().reduce(Integer::sum);
        System.out.println(sum);
        System.out.println(sum2);

        //最大值和最小值
        Optional max = integers.stream().reduce(Integer::max);
//      Optional min = integers.stream().reduce((a,b)->a min = integers.stream().reduce(Integer::min);

        System.out.println("max==="+max+"  min==="+min);
        //求menu中fruit的数量
        Optional fruitCount = list.stream().map(c -> 1).reduce(Integer::sum);
        System.out.println("fruit's count is "+ fruitCount);

结果:

21

Optional[21]

max=Optional[6] min=Optional[1]

fruit’s count is Optional[6]

操作总结

3.4 数值流(IntStream、 DoubleStream和LongStream)
   //数值流


        //映射到数值流
        double totalWeight = list.stream().mapToDouble(Menu::getWeight).sum();
        System.out.println(totalWeight);

        //转换回对象流
        Stream boxed = list.stream().mapToDouble(Menu::getWeight).boxed();

        //默认值OptionalDouble
        OptionalDouble optionalDouble = list.stream().mapToDouble(Menu::getWeight).max();
        System.out.println(optionalDouble);
        System.out.println(optionalDouble.orElse(99.99));

        //数值范围
        System.out.println(IntStream.rangeClosed(100,200).boxed().limit(10).collect(Collectors.toList()));

        //生成勾股数
        Stream pythagoreanTriples =
                IntStream.rangeClosed(1, 100).boxed()
                        .flatMap(a ->
                                IntStream.rangeClosed(a, 100)
                                        .filter(b -> Math.sqrt(a*a + b*b) % 1 == 0)
                                        .mapToObj(b ->
                                                new int[]{a, b, (int)Math.sqrt(a * a + b * b)})
                        );

        pythagoreanTriples.limit(5)
                .forEach(t ->
                        System.out.println(t[0] + ", " + t[1] + ", " + t[2]));

结果:

22.88

OptionalDouble[8.88]

8.88

[100, 101, 102, 103, 104, 105, 106, 107, 108, 109]

3, 4, 5

5, 12, 13

6, 8, 10

7, 24, 25

8, 15, 17

3.4 构建流

//由值创建流
Stream stream = Stream.of(“a”, “b”, “c”, “d”, “e”);
stream.map(String::toUpperCase).forEach(System.out::println);
//获取一个空的流
Stream empty = Stream.empty();

    //由数组创建流
    int[] numbers = {1, 2, 3, 4, 5};
    IntStream numberStream = Arrays.stream(numbers);
    Long countNumber = numberStream.count();
    System.out.println(countNumber);

    //由文件生成流
    long uniqueWords = 0;
    try (Stream lines =
                 Files.lines(Paths.get("G:\\IdeaProject\\javase\\src\\main\\java\\Java8\\chapter3_stream\\operate\\data.txt"), Charset.defaultCharset())) {
        uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
                .distinct()
                .count();

        System.out.println("==diff words==" + uniqueWords);
    } catch (IOException e) {
    }

    //由函数生成流:创建无限流
    //根据初始值进行操作
    Stream.iterate(100, n -> 100 + new Random().nextInt(100)).limit(10).forEach(System.out::println);
    Stream.iterate(new int[]{0, 1}, t->new int[]{t[1],t[0]+t[1]}).limit(20).map(t->t[0]).forEach(t -> System.out.print(t+" "));

    //不需要根据生成值进行后续操作
    Stream.generate(()->new Random().nextInt(100)+100).limit(20).forEach(System.out::println);

你可能感兴趣的:(基础,Java8)