Java8使用流操作集合

Java8集合操作正確方式

  • 流Api是Java8提供的新的api,用來聲明式地處理數據集合。

1 一個Demo案例:

  • 需要將List集合中的重量大於0.3kg的水果篩選出來進行排序後拿出它的名字最後放到另一個List中去。
      
        List<Fruit> 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<Fruit> tempList = new ArrayList<>();
//        for(Fruit fruit : fruits){
//            if(fruit.getWeight()>0.3){
//                tempList.add(fruit);
//            }
//        }
//
//        List<String> fruitNames = new ArrayList<>();
//        tempList.sort(new Comparator<Fruit>() {
//            @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<String> 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<Menu> factory() {


        Menu meatMenu = new Menu("meat", 8.88);
        List<Menu> 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<Menu> list = factory();

        //filter (過濾不符合條件的元素)
        List<Menu> newMenu = list.stream().filter(w -> w.getWeight() > 0.88).collect(Collectors.toList());
        System.out.println(newMenu);

        //distinct (過濾調一樣的元素基於hashcode和equals)
        List<Menu> newMenu2 = list.stream().distinct().collect(Collectors.toList());
        System.out.println(newMenu2);


        //limit (限制選取前幾個元素)
        List<Menu> newMenu3 = list.stream().limit(2).collect(Collectors.toList());
        System.out.println(newMenu3);

        //skip (限制跳過前幾個元素)
        List<Menu> 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<String> newMenu5 = list.stream().map(Menu::getName).collect(Collectors.toList());
    System.out.println(newMenu5);


    //flatMap 可以將生成的流扁平化爲單個流
    List<String> 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<Menu> anyMenu = list.stream().findAny();
        System.out.println(anyMenu.toString());

        //返回當前流中第一個元素
        Optional<Menu> 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<Integer> integers = Lists.newArrayList(1, 2, 3, 4, 5, 6);
        //0代表初始值
        int sum = integers.stream().reduce(0, Integer::sum);
        //可以不指定初始值,返回值變爲Optional<Integer>以防止可能爲空的情況
        Optional<Integer> sum2 = integers.stream().reduce(Integer::sum);
        System.out.println(sum);
        System.out.println(sum2);

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

        System.out.println("max==="+max+"  min==="+min);
        //求menu中fruit的數量
        Optional<Integer> 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<Double> 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<int[]> 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<String> 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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章