<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Java8的Stream API使用

      前言

      這次想介紹一下Java Stream的API使用,最近在做一個(gè)新的項(xiàng)目,然后終于可以從老項(xiàng)目的祖?zhèn)鞔a坑里跳出來了。項(xiàng)目用公司自己的框架搭建完成后,我就想著把JDK版本也升級(jí)一下吧(之前的項(xiàng)目,最高就能用JDK7),但是后來發(fā)現(xiàn)公司的項(xiàng)目部署打包平臺(tái)最高只支持到JDK8。那好吧,既然就支持到JDK8,也能滿足日常需求了(要啥自行車),升級(jí)到JDK8后,在搭建完項(xiàng)目架構(gòu)后,就開始寫一些基礎(chǔ)邏輯。其中就用到了一些JDK8的Stream。但是我的同事在看我的代碼的時(shí)候表示看不懂。確實(shí),這個(gè)我也承認(rèn),Lambda表達(dá)式雖然代碼簡潔,但是不會(huì)用的人會(huì)覺得它的可讀性不是太好。所以這次就結(jié)合自己使用經(jīng)驗(yàn)來介紹一下Java Stream的一些功能。

      從遍歷到Stream操作

      Oracle 公司于 2014 年 3 月 18 日發(fā)布 Java 8,Java8主要是在原來面向?qū)ο蟮幕A(chǔ)上增加了函數(shù)式編程的能力。這樣就出現(xiàn)了在Java中使用Lambda表達(dá)式,將一個(gè)函數(shù)作為方法的參數(shù)來進(jìn)行傳遞。Java8的Stream就是典型的例子,Stream API可以極大提高Java程序員的生產(chǎn)力,讓程序員寫出高效率、干凈、簡潔的代碼。

      例子:

      List<Integer> numbers = new ArrayList<>();
      numbers.add(3);
      numbers.add(4);
      numbers.add(8);
      numbers.add(16);
      numbers.add(19);
      numbers.add(27);
      numbers.add(23);
      numbers.add(99);
      numbers.add(15);
      numbers.add(32);
      numbers.add(5);
      numbers.add(232);
      numbers.add(56);
      int count = 0;
      for(Integer i:numbers){
      if(i>20){
      count++;
      }
      }
      System.out.println("count:"+count);

      如上遍歷的代碼轉(zhuǎn)換成使用Stream的API來實(shí)現(xiàn)如下:

      long count = numbers.stream().filter(i->i>20).count();
      System.out.println("count:"+count);

      正常的遍歷用Stream一行就可以實(shí)現(xiàn)了。

      下面是一個(gè)使用了Stream API實(shí)現(xiàn)的流程圖。

      轉(zhuǎn)換成Java代碼就是

      Integer transactionsIds =
                      roomList.stream()
                              .filter(b -> b.getLength() == 10)
                              .sorted((x,y) -> x.getHigh() - y.getHigh())
                              .mapToInt(Room::getWidth).sum();

      創(chuàng)建Stream

      Arrays.stream()

      當(dāng)在日常編程中面對(duì)的是一個(gè)數(shù)組,也可以使用Arrays.stream()方法來使用Stream

      Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
      long count = Arrays.stream(array).filter(i->i>20).count();

      Stream.of()

      當(dāng)面對(duì)數(shù)組時(shí)除了可以使用Arrays.stream()方法外,還可以使用Stream將需要的數(shù)組轉(zhuǎn)成Stream。這個(gè)方法不但支持傳入數(shù)組,將數(shù)組轉(zhuǎn)成Stream,也支持傳入多個(gè)參數(shù),將參數(shù)最終轉(zhuǎn)成Stream

      Integer[] array = new Integer[]{3,4,8,16,19,27,23,99,76,232,33,96};
      long count = Stream.of(array).filter(i->i>20).count();
      long sum = Stream.of(12,77,59,3,654).filter(i->i>20).mapToInt(Integer::intValue).sum();
      System.out.println("count:"+count+",sum:"+sum);

      其實(shí)Stream.of()也是調(diào)用的Stream.of()方法來實(shí)現(xiàn)的。

      Stream.generate()

      Stream接口有兩個(gè)用來創(chuàng)建無限Stream的靜態(tài)方法。generate()方法接受一個(gè)參數(shù)函數(shù),可以使用類似如下代碼來創(chuàng)建一個(gè)你需要的Stream。

      Stream<String> stream = Stream.generate(() -> "test").limit(10);
      String[] strArr = stream.toArray(String[]::new);
      System.out.println(Arrays.toString(strArr));

      運(yùn)行結(jié)果

      [test, test, test, test, test, test, test, test, test, test]

      Stream.iterate()

      Stream接口的另一用來創(chuàng)建無限Stream的靜態(tài)方法就是iterate()方法。iterate()方法也是接受一個(gè)參數(shù)函數(shù),可以用類似如下代碼來創(chuàng)建一個(gè)你需要的Stream。

      Stream<BigInteger> bigIntStream = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.TEN)).limit(10);
      BigInteger[] bigIntArr = bigIntStream.toArray(BigInteger[]::new);
      System.out.println(Arrays.toString(bigIntArr));

      運(yùn)行結(jié)果

      [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

      Collection.stream()

      這個(gè)就是最常見的Stream了。因?yàn)镃ollection是Java中集合接口的父接口,Java中的集合都繼承或?qū)崿F(xiàn)了此接口。所以Java中的集合都可以使用此方法來創(chuàng)建一個(gè)Stream;

            /**
              * @see     Set
              * @see     List
              * @see     Map
              * @see     SortedSet
              * @see     SortedMap
              * @see     HashSet
              * @see     TreeSet
              * @see     ArrayList
              * @see     LinkedList
              * @see     Vector
              * @see     Collections
              * @see     Arrays
              * @see     AbstractCollection
              * @since 1.2
              */
              public interface Collection<E> extends Iterable<E> {
                  /**
                   * Returns a sequential {@code Stream} with this collection as its source.
                   *
                   * <p>This method should be overridden when the {@link #spliterator()}
                   * method cannot return a spliterator that is {@code IMMUTABLE},
                   * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
                   * for details.)
                   *
                   * @implSpec
                   * The default implementation creates a sequential {@code Stream} from the
                   * collection's {@code Spliterator}.
                   *
                   * @return a sequential {@code Stream} over the elements in this collection
                   * @since 1.8
                   */
                  default Stream<E> stream() {
                      return StreamSupport.stream(spliterator(), false);
                  }
              }

      例子

      List<Integer> numbers = new ArrayList<>();
      numbers.add(3);
      numbers.add(4);
      numbers.add(8);
      numbers.add(16);   
      numbers.stream().forEach(number->{
          System.out.println(number);
      });

      StreamSupport.stream()

      通過查看Collection.stream()的方法,我們可以看出來,Colleciton.stream()其實(shí)是調(diào)用了StreamSupport.stream()來實(shí)現(xiàn)的。所以我們也可以使用StreamSupport.stream()來創(chuàng)建一個(gè)Stream。當(dāng)我們面對(duì)的是一個(gè)迭代器的時(shí)候,使用StreamSupport.stream()就可以創(chuàng)建一個(gè)Stream。第一個(gè)參數(shù)是傳入一個(gè)迭代器,第二個(gè)參數(shù)是true代表使用并行來進(jìn)行處理。false代表串行來處理Stream。

      List<Integer> numbers = new ArrayList<>();
      numbers.add(
      3); numbers.add(4); numbers.add(8); numbers.add(16); numbers.add(19); numbers.add(27); numbers.add(23); Spliterator<Integer> integers = numbers.spliterator(); StreamSupport.stream(integers,false).forEach(number->{   System.out.println(number); });

      流的轉(zhuǎn)換

      filter方法

      從名字上就能看出來,這是一個(gè)Stream的過濾轉(zhuǎn)換,此方法會(huì)生成一個(gè)新的流,其中包含符合某個(gè)特定條件的所有元素。

      List<Integer> integerList = Lists.newArrayList();
      integerList.add(15);
      integerList.add(32);
      integerList.add(5);
      integerList.add(232);
      integerList.add(56);
      List<Integer> after = integerList.stream()
                          .filter(i->i>50)
                          .collect(Collectors.toList());

      System.out.println(after);

      運(yùn)行結(jié)果:

      [232, 56]

      map方法

      map方法指對(duì)一個(gè)流中的值進(jìn)行某種形式的轉(zhuǎn)換。需要傳遞給它一個(gè)轉(zhuǎn)換的函數(shù)作為參數(shù)。

      List<Integer> integerList = Lists.newArrayList();
      integerList.add(15);
      integerList.add(32);
      integerList.add(5);
      integerList.add(232);
      integerList.add(56);
      //將Integer類型轉(zhuǎn)換成String類型
      List<String> afterString = integerList.stream()
                      .map(i->String.valueOf(i)).collect(Collectors.toList());
      System.out.println(afterString);

      flatMap方法

      上面用map方法進(jìn)行流轉(zhuǎn)換的時(shí)候,是對(duì)每個(gè)元素應(yīng)用一個(gè)函數(shù),并將返回的值收集到一個(gè)新的流中。但是如果有一個(gè)函數(shù),它返回的不是一個(gè)值,而是一個(gè)包含多個(gè)值的流。但是你需要的是一個(gè)包含多個(gè)流中的元素的集合。

      例如

      List<Integer> oneList = Lists.newArrayList(),
      twoList = Lists.newArrayList();
      oneList.add(34);
      oneList.add(23);
      oneList.add(87);

      twoList.add(29);
      twoList.add(48);
      twoList.add(92);
      Map<String,List<Integer>> testMap = Maps.newHashMap();
      testMap.put("1",oneList);
      testMap.put("2",twoList);
      //返回的是一個(gè)流的集合,但是我需要的是List<Integer>這樣一個(gè)集合
      List<Stream<Integer>> testList = testMap.values().stream()
                          .map(number->number.stream()).collect(Collectors.toList());

      這個(gè)時(shí)候就應(yīng)該使用flatMap將多個(gè)流進(jìn)行合并,然后再收集到一個(gè)集合中。

      List<Integer> testList = testMap.values().stream()
                      .flatMap(number->number.stream()).collect(Collectors.toList());

      limit方法和skip方法

      limit(n)方法會(huì)返回一個(gè)包含n個(gè)元素的新的流(若總長小于n則返回原始流)。

      List<Integer> myList = Lists.newArrayList();
      myList.add(1);
      myList.add(2);
      myList.add(3);
      myList.add(4);
      myList.add(5);
      myList.add(6);
      List<Integer> afterLimit = myList.stream().limit(4).collect(Collectors.toList());
      System.out.println("afterLimit:"+afterLimit);

      skip(n)方法正好相反,它會(huì)丟棄掉前面的n個(gè)元素。

      List<Integer> afterSkip = myList.stream().skip(4).collect(Collectors.toList());
      System.out.println("afterSkip:"+afterSkip);

      運(yùn)行結(jié)果:

      afterLimit:[1, 2, 3, 4]
      afterSkip:[5, 6]

      用limit和skip方法一起使用就可以實(shí)現(xiàn)日常的分頁功能:

      List<Integer> pageList = myList.stream()
                        .skip(pageNumber*pageSize)
                        .limit(pageSize).collect(Collectors.toList());

      distinct方法和sorted方法

      上面介紹的流的轉(zhuǎn)換方法都是無狀態(tài)的。即從一個(gè)已經(jīng)轉(zhuǎn)換的流中取某個(gè)元素時(shí),結(jié)果并不依賴于之前的元素。除此之外還有兩個(gè)方法在轉(zhuǎn)換流時(shí)是需要依賴于之前流中的元素的。一個(gè)是distinct方法一個(gè)是sorted方法。

      distinct方法會(huì)根據(jù)原始流中的元素返回一個(gè)具有相同順序、去除了重復(fù)元素的流,這個(gè)操作顯然是需要記住之前讀取的元素。

      List<Integer> myTestList = Lists.newArrayList();
      myTestList.add(10);
      myTestList.add(39);
      myTestList.add(10);
      myTestList.add(78);
      myTestList.add(10);
      List<Integer> distinctList = myTestList.stream()
                              .distinct().collect(Collectors.toList());
      System.out.println("distinctList:"+distinctList);

      運(yùn)行結(jié)果:

      distinctList:[10, 39, 78]

      sorted方法是需要遍歷整個(gè)流的,并在產(chǎn)生任何元素之前對(duì)它進(jìn)行排序。因?yàn)橛锌赡芘判蚝蠹系牡谝粋€(gè)元素會(huì)在未排序集合的最后一位。

      List<Integer> myTestList = Lists.newArrayList();
      myTestList.add(39);
      myTestList.add(78);
      myTestList.add(10);
      myTestList.add(22);
      myTestList.add(56);
      List<Integer> sortList = myTestList.stream()
                      .sorted(Integer::compareTo).collect(Collectors.toList()); System.out.println(
      "sortList:"+sortList);

      運(yùn)行結(jié)果:

      sortList:[10, 22, 39, 56, 78]

      聚合操作

      前面已經(jīng)介紹了流的創(chuàng)建和轉(zhuǎn)換,下面介紹流的聚合,聚合是指將流匯聚為一個(gè)值,以便在程序中使用。聚合方法都是終止操作。

      max方法min方法

      在前面的代碼例子中使用的count方法sum方法都屬于流從聚合方法。還有兩個(gè)聚合方法是max方法min方法,分別返回流中最大值和最小值。

      
      
      List<Integer> hearList = Lists.newArrayList();
      hearList.add(15);
      hearList.add(32);
      hearList.add(5);
      hearList.add(232);
      hearList.add(56);
      hearList.add(29);
      hearList.add(94);
      Integer maxItem = hearList.stream().max(Integer::compareTo).get();
      Integer minItem = hearList.stream().min(Integer::compareTo).get();
      System.out.println("max:"+maxItem+",min:"+minItem);

      運(yùn)行結(jié)果:

      max:232,min:5

      findFirst方法

      findFirst方法返回非空集合中的第一個(gè)值,它通常與filter方法結(jié)合起來使用。

      List<Integer> hearList = Lists.newArrayList();
      hearList.add(15);
      hearList.add(32);
      hearList.add(5);
      hearList.add(232);
      hearList.add(56);
      hearList.add(29);
      hearList.add(104);
      Integer first = hearList.stream().filter(i->i>100).findFirst().get();

      findAny方法

      findAny方法可以在集合中只要找到任何一個(gè)所匹配的元素,就返回,此方法在對(duì)流并行執(zhí)行時(shí)十分有效(任何片段中發(fā)現(xiàn)第一個(gè)匹配元素都會(huì)結(jié)束計(jì)算,串行流中和findFirst返回一樣)。

      Integer anyItem = hearList.parallelStream().filter(i->i>100).findAny().get();

      anyMatch方法

      anyMatch方法可以判定集合中是否還有匹配的元素。返回結(jié)果是一個(gè)boolean類型值。

      boolean isHas = hearList.parallelStream().anyMatch(i->i>100);

      allMatch方法noneMatch方法

      allMatch方法noneMatch方法,分別在所有元素匹配和沒有元素匹配時(shí)返回true。

      boolean allHas = hearList.parallelStream().allMatch(i->i>100);
      boolean noHas = hearList.parallelStream().noneMatch(i->i>100);

      雖然這些方法總是會(huì)檢查整個(gè)流,但是仍然可以通過并行執(zhí)行來提高速度。 

      reduce方法

      reduce方法是將流中的元素進(jìn)行進(jìn)一步計(jì)算的方法。

      List<Integer> hearList = Lists.newArrayList();
      hearList.add(15);
      hearList.add(32);
      hearList.add(5);
      hearList.add(232);
      hearList.add(56);
      hearList.add(29);
      hearList.add(104);
      //求和
      Integer sum = hearList.stream().reduce((x,y)->x+y).get();
      System.out.println("sum:"+sum);
      //簡化一下,求和
      sum = hearList.stream().reduce(Integer::sum).get();
      System.out.println("sum:"+sum);
      //含有初始標(biāo)識(shí)的,求和
      sum = hearList.stream().reduce(0,(x,y)->x+y);
      System.out.println("sum:"+sum);
      //對(duì)元素的長度進(jìn)行求和( (total,y)->total+y.toString().length(),類似于一個(gè)累加器,會(huì)被重復(fù)調(diào)用)
      sum = hearList.stream().reduce(0,(total,y)->total+y.toString().length(),(total1,total2)->total1+total2);
      System.out.println("sum:"+sum);
      //簡化一下,對(duì)元素長度進(jìn)行求和。
      sum = hearList.stream().map(Objects::toString).mapToInt(String::length).sum();
      System.out.println("sum:"+sum);

      運(yùn)行結(jié)果

      sum:473
      sum:473
      sum:473
      sum:15
      sum:15

      收集結(jié)果

      當(dāng)處理完流之后,通常是想查看一下結(jié)果,而不是將他們聚合為一個(gè)值。Collectorts類為我們提供了常用的收集類的各個(gè)工廠方法。

      收集到集合

      例如前面的例子用的要將一個(gè)流收集到一個(gè)List中,只需要這樣寫就可以。

      List<Integer> thereList = hereList.stream().collect(Collectors.toList());

      收集到Set中可以這樣用

      Set<Integer> thereSet = hereList.stream().collect(Collectors.toSet());

      收集到Set時(shí),控制Set的類型,可以這樣。

      TreeSet<Integer> treeSet = hereList.stream()
                          .collect(Collectors.toCollection(TreeSet::new));

      拼接

      將字流中的字符串連接并收集起來。

      String resultString = stringList.stream().collect(Collectors.joining());

      在將流中的字符串連接并收集起來時(shí),想在元素中介添加分隔符,傳遞個(gè)joining方法即可。

      String resultString = stringList.stream().collect(Collectors.joining(","));

      當(dāng)流中的元素不是字符串時(shí),需要先將流轉(zhuǎn)成字符串流再進(jìn)行拼接。

      String hereResultString = hereList.stream()
                      .map(String::valueOf).collect(Collectors.joining(","));

      收集聚合

      分別收集流的總和、平均值、最大值或者最小值。

      List<Integer> hereList = Lists.newArrayList();
      hereList.add(15);
      hereList.add(32);
      hereList.add(5);
      hereList.add(232);
      hereList.add(56);
      hereList.add(29);
      hereList.add(104);
      
      //總和、平均值,最大值,最小值
      int sum = hereList.stream().collect(Collectors.summingInt(Integer::intValue));
      Double ave = hereList.stream().collect(Collectors.averagingInt(Integer::intValue));
      Integer max = hereList.stream().collect(Collectors.maxBy(Integer::compare)).get();
      Integer min = hereList.stream().collect(Collectors.minBy(Integer::compare)).get();
      System.out.println("sum:"+sum+",ave:"+ave+",max:"+max+",min:"+min);

      運(yùn)行結(jié)果:

      sum:473,ave:67.57142857142857,max:232,min:5

      一次性收集流中的結(jié)果,聚合為一個(gè)總和,平均值,最大值或最小值的對(duì)象。

      IntSummaryStatistics summaryStatistics = hereList.stream()
                                .collect(Collectors.summarizingInt(Integer::intValue)); System.out.println(summaryStatistics);

      運(yùn)行結(jié)果:

      IntSummaryStatistics{count=7, sum=473, min=5, average=67.571429, max=232}

      將結(jié)果集收集到Map

      當(dāng)我們希望將集合中的元素收集到Map中時(shí),可以使用Collectors.toMap方法。這個(gè)方法有兩個(gè)參數(shù),用來生成Map的key和value。

      例如將一個(gè)Room對(duì)象的high作為鍵width作為值

      Map<Integer,Integer> hwMap = roomList.stream()
                              .collect(Collectors.toMap(Room::getHigh, Room::getWidth));

      但是通常還是以具體元素作為值的情況多,可以使用Function.identity()來獲取實(shí)際元素。

      Map<Integer,Room> roomMap = roomList.stream()
                              .collect(Collectors.toMap(Room::getHigh, Function.identity()));

      如果多個(gè)元素?fù)碛邢嗤逆I,在收集結(jié)果時(shí)會(huì)拋出java.lang.IllegalStateException異常。可以使用第三個(gè)參數(shù)來解決,第三個(gè)參數(shù)用來確定當(dāng)出現(xiàn)鍵沖突時(shí),該如何處理結(jié)果,如果當(dāng)出現(xiàn)鍵沖突時(shí)只保留一個(gè)并且是保留已經(jīng)存在的值時(shí),就是如下方式。

      Map<Integer,Room> rMap = roomList.stream()
                      .collect(Collectors.toMap(Room::getHigh, Function.identity(),(nowValue,newValue)->nowValue));

      如果想指定生成的Map類型,則還需要第三個(gè)參數(shù)。

      TreeMap<Integer,Room> roomTreeMap = roomList.stream()
                      .collect(Collectors.toMap(Room::getHigh, 
                  Function.identity(),(nowValue,newValue)
      ->newValue,TreeMap::new));

      注意:每個(gè)toMap方法,都會(huì)有一個(gè)對(duì)應(yīng)的toConCurrentMap方法,用來生成一個(gè)并發(fā)Map。

      分組分片

      在一個(gè)集合中,對(duì)具有相同特性的值進(jìn)行分組是一個(gè)很常見的功能,在Stream的API中也提供了相應(yīng)的方法。

      分組

      還是上面的例子,將一個(gè)Room對(duì)象集合按照高度分組。

      List<Room> roomList = Lists.newArrayList(
      new Room(11,23,56),
      new Room(11,84,48),
      new Room(22,46,112),
      new Room(22,75,62),
      new Room(22,56,75),
      new Room(33,92,224));
      
      Map<Integer,List<Room>> groupMap = roomList.stream().collect(Collectors.groupingBy(Room::getHigh));
      System.out.println("groupMap:"+groupMap);

      運(yùn)行結(jié)果:

      groupMap:{33=[Room(high=33, width=92, length=224)], 
      22=[Room(high=22, width=46, length=112), Room(high=22, width=75, length=62), Room(high=22, width=56, length=75)],
      11=[Room(high=11, width=23, length=56), Room(high=11, width=84, length=48)]}

      分片 

      當(dāng)分類函數(shù)是一個(gè)返回布爾值的函數(shù)時(shí),流元素會(huì)被分為兩組列表:一組是返回true的元素集合,另一組是返回false的元素集合。這種情況適用partitoningBy方法會(huì)比groupingBy更有效率。

      例如我們將房間集合分為兩組,一組是高度為22的房間,另一組是其他房間。

      Map<Boolean,List<Room>> partitionMap = roomList.stream()
                      .collect(Collectors.partitioningBy(room->room.getHigh()==22));

      運(yùn)行結(jié)果:

      partitionMap:{false=[Room(high=11, width=23, length=56), Room(high=11, width=84, length=48), Room(high=33, width=92, length=224)],
      true=[Room(high=22, width=46, length=112), Room(high=22, width=75, length=62), Room(high=22, width=56, length=75)]}

      擴(kuò)展功能

      下面要介紹的這些方法功能,無論是groupingBy方法還是partitioningBy方法都是支持的。

      counting方法會(huì)返回收集元素的總個(gè)數(shù)。

      Map<Integer,Long> countMap = roomList.stream()
                 .collect(Collectors.groupingBy(Room::getHigh,Collectors.counting()));

      summing(Int|Long|Double)方法接受一個(gè)取值函數(shù)作為參數(shù),來計(jì)算總和。

      Map<Integer,Integer> sumMap = roomList.stream().
                      collect(Collectors.groupingBy(Room::getHigh,Collectors.summingInt(Room::getWidth)));

      maxBy方法和minBy方法接受比較器作為參數(shù)來計(jì)算最大值和最小值。

      取出分組中寬度最大和最小的房間。

      Map<Integer, Optional<Room>> maxMap = roomList.stream().
                      collect(Collectors.groupingBy(Room::getHigh,
                              Collectors.maxBy(Comparator.comparing(Room::getWidth))
                      ));
      Map<Integer, Optional<Room>> minMap = roomList.stream().
                      collect(Collectors.groupingBy(Room::getHigh,
                              Collectors.minBy(Comparator.comparing(Room::getWidth))
                      ));
      
      System.out.println("maxMap:"+ JSON.toJSONString(maxMap));
      System.out.println("minMap:"+JSON.toJSONString(minMap));

      運(yùn)行結(jié)果:

      maxMap:{33:{"high":33,"length":224,"width":92},22:{"high":22,"length":62,"width":75},11:{"high":11,"length":48,"width":84}}
      minMap:{33:{"high":33,"length":224,"width":92},22:{"high":22,"length":112,"width":46},11:{"high":11,"length":56,"width":23}}
      
      

      mapping方法會(huì)將結(jié)果應(yīng)用到另一個(gè)收集器上。

      取出分組中寬度最大的房間的寬度。

      Map<Integer, Optional<Integer>> collect = roomList.stream().collect(Collectors.groupingBy(Room::getHigh,
                      Collectors.mapping(Room::getWidth,
                              Collectors.maxBy(Comparator.comparing(Integer::valueOf)))));
      
      System.out.println("collect:"+JSON.toJSONString(collect));

      運(yùn)行結(jié)果:

      collect:{33:92,22:75,11:84}

      無論groupingBy或是mapping函數(shù),如果返回類型是int、long、double都可以將元素收集到一個(gè)summarystatistics對(duì)象中,然后從每組的summarystatistics對(duì)象中取出函數(shù)值的總和、平均值、總數(shù)、最大值和最小值。

      Map<Integer,IntSummaryStatistics> summaryStatisticsMap = roomList.stream()
                      .collect(Collectors.groupingBy(Room::getHigh,
                      Collectors.summarizingInt(Room::getWidth)));
      
      System.out.println("summaryStatisticsMap:"+summaryStatisticsMap);

      運(yùn)行結(jié)果:

      summaryStatisticsMap:{33=IntSummaryStatistics{count=1, sum=92, min=92, average=92.000000, max=92}, 
      22=IntSummaryStatistics{count=3, sum=177, min=46, average=59.000000, max=75},
      11=IntSummaryStatistics{count=2, sum=107, min=23, average=53.500000, max=84}}

      多級(jí)分組

      上面的例子我們都是按一個(gè)條件進(jìn)行的一級(jí)分組,其實(shí)groupingBy是支持多級(jí)分組的。

      例如第一級(jí)我們將房間按照高度分組,第二級(jí)按照寬度分組。

      Map<Integer,Map<Integer,List<Room>>> multistageMap = roomList.stream().collect(
                Collectors.groupingBy(Room::getHigh,Collectors.groupingBy(Room::getWidth))); System.out.println(
      "multistageMap:"+JSON.toJSONString(multistageMap));

      運(yùn)行結(jié)果:

      {
          "11": {
              "23": [
                  {"high": 11,"length": 56,"width": 23}
              ],
              "84": [
                  {"high": 11,"length": 48,"width": 84}
              ]
          },
          "22": {
              "46": [
                  {"high": 22,"length": 112,"width": 46}
              ],
              "56": [
                  {"high": 22,"length": 75,"width": 56}
              ],
              "75": [
                  {"high": 22,"length": 62,"width": 75}
              ]
          },
          "33": {
              "92": [
                  {"high": 33,"length": 224,"width": 92}
              ]
          }
      }

      并行流

      Stream的建立,使得并行計(jì)算變得容易,但是并行流在使用的時(shí)候也是需要注意的。

      首先,必須是一個(gè)并行流,只要在終止方法執(zhí)行時(shí),流處于并行模式,那么所有的流操作就都會(huì)并行執(zhí)行。

      Stream.of(roomList).parallel();

      parallel方法可以將任意的串行流轉(zhuǎn)換為一個(gè)并行流。

      其次要確保傳遞給并行流操作的函數(shù)是線程安全的。

      int[] words = new int[23];
      Stream.of(roomList).parallel().forEach(s->{
           if(s.size()<10){
                 words[s.size()]++;
           }
      });

      上面這個(gè)例子中的代碼就是錯(cuò)誤的,傳遞給并行流的操作并不是線程安全的。可以改為AtomicInteger的對(duì)象數(shù)組來作為計(jì)數(shù)器。

      我們使在處理集合數(shù)據(jù)量較大的時(shí)候才能體現(xiàn)出并行流的優(yōu)勢(shì),并且目的是為了在保證線程安全的情況下,提升效率,利用多核CPU的資源。

       

      小擴(kuò)展

      使用Stream的API時(shí),在遍歷或處理流的過程中當(dāng)引用外部變量的時(shí)候會(huì)默認(rèn)的將變量當(dāng)成fianl變量來處理。所以有些同學(xué)就會(huì)覺得在遍歷的過程中取不出來集合的索引。其實(shí)可以換一種思想可以只遍歷集合索引,然后在遍歷中取值。

      IntStream.range(0,roomList.size()).forEach(i->{
             System.out.println(roomList.get(i));
      });

       

      posted @ 2019-06-17 00:41  紀(jì)莫  閱讀(23910)  評(píng)論(9)    收藏  舉報(bào)
      主站蜘蛛池模板: 少妇被多人c夜夜爽爽av| 18禁无遮挡啪啪无码网站| 中国大陆高清aⅴ毛片| 欧美 亚洲 另类 丝袜 自拍 动漫| 少妇人妻偷人精品一区二| 亚洲综合无码一区二区| 亚洲人成人网站色www| 综合激情亚洲丁香社区| 宁南县| 国产一区二区三区乱码在线观看 | 免费福利视频一区二区三区高清| 成人免费无码不卡毛片| 国产成人无码一二三区视频| 国产精品三级黄色小视频| 成人性生交大片免费看r链接| 玩两个丰满老熟女久久网| 777天堂麻豆爱综合视频| 精品一区二区三区女性色| 米易县| 中文字幕自拍偷拍福利视频| 97成人碰碰久久人人超级碰oo| 亚洲国产精品一二三区| 国产suv精品一区二区四| 午夜福利国产片在线视频| 小污女小欲女导航| 色噜噜在线视频免费观看| 最新偷拍一区二区三区| 亚洲第一香蕉视频啪啪爽| 国产一区二区波多野结衣| 动漫av网站免费观看| 亚洲欧美日韩愉拍自拍美利坚| 婷婷色香五月综合缴缴情香蕉| 国产在线精品福利91香蕉| japanese丰满奶水| 麻豆精产国品一二三区区| 在线天堂最新版资源| 无码人妻出轨黑人中文字幕| 高清精品视频一区二区三区| 久久亚洲欧美日本精品| 成全我在线观看免费第二季| 久久精品国产亚洲av成人|