I want to fly higher
          programming Explorer
          posts - 114,comments - 263,trackbacks - 0
              本篇用代碼示例結合JDk源碼講了Java8引入的工具接口Stream以及新Map接口提供的常用默認方法.
              參考:http://winterbe.com/posts/2014/03/16/java-8-tutorial/

              1.Stream示例

          package com.mavsplus.java8.turtorial.streams;

          import java.util.ArrayList;
          import java.util.List;
          import java.util.Optional;
          import java.util.UUID;

          /**
           * java.util.Stream使用例子
           * 
           * <pre>
           * java.util.Stream表示了某一種元素的序列,在這些元素上可以進行各種操作。Stream操作可以是中間操作,也可以是完結操作。
           * 完結操作會返回一個某種類型的值,而中間操作會返回流對象本身,并且你可以通過多次調用同一個流操作方法來將操作結果串起來。
           * Stream是在一個源的基礎上創建出來的,例如java.util.Collection中的list或者set(map不能作為Stream的源)。
           * Stream操作往往可以通過順序或者并行兩種方式來執行。
           * </pre>
           * 
           * public interface Stream<T> extends BaseStream<T, Stream<T>> {
           * <p>
           * 可以看到Stream是一個接口,其是1.8引入
           * 
           * <p>
           * Java 8中的Collections類的功能已經有所增強,你可以之直接通過調用Collections.stream()或者Collection.
           * parallelStream()方法來創建一個流對象
           * 
           * @author landon
           * @since 1.8.0_25
           
          */
          public class StreamUtilExample {

              private List<String> stringList = new ArrayList<>();

              public StreamUtilExample() {
                  init();
              }

              private void init() {
                  initStringList();
              }

              /**
               * 初始化字符串列表
               
          */
              private void initStringList() {
                  stringList.add("zzz1");
                  stringList.add("aaa2");
                  stringList.add("bbb2");
                  stringList.add("fff1");
                  stringList.add("fff2");
                  stringList.add("aaa1");
                  stringList.add("bbb1");
                  stringList.add("zzz2");
              }

              /**
               * Filter接受一個predicate接口類型的變量,并將所有流對象中的元素進行過濾。該操作是一個中間操作,
               * 因此它允許我們在返回結果的基礎上再進行其他的流操作
               * (forEach)。ForEach接受一個function接口類型的變量,用來執行對每一個元素的操作
               * 。ForEach是一個中止操作。它不返回流,所以我們不能再調用其他的流操作
               
          */
              public void useStreamFilter() {
                  // stream()方法是Collection接口的一個默認方法
                  
          // Stream<T> filter(Predicate<? super T>
                  
          // predicate);filter方法參數是一個Predicate函數式接口并繼續返回Stream接口
                  
          // void forEach(Consumer<? super T> action);foreach方法參數是一個Consumer函數式接口

                  
          // 解釋:從字符串序列中過濾出以字符a開頭的字符串并迭代打印輸出
                  stringList.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);
              }

              /**
               * Sorted是一個中間操作,能夠返回一個排過序的流對象的視圖。流對象中的元素會默認按照自然順序進行排序,
               * 除非你自己指定一個Comparator接口來改變排序規則.
               * 
               * <p>
               * 一定要記住,sorted只是創建一個流對象排序的視圖,而不會改變原來集合中元素的順序。原來string集合中的元素順序是沒有改變的
               
          */
              public void useStreamSort() {
                  // Stream<T> sorted();返回Stream接口
                  
          // 另外還有一個 Stream<T> sorted(Comparator<? super T>
                  
          // comparator);帶Comparator接口的參數
                  stringList.stream().sorted().filter((s) -> s.startsWith("a")).forEach(System.out::println);

                  // 輸出原始集合元素,sorted只是創建排序視圖,不影響原來集合順序
                  stringList.stream().forEach(System.out::println);
              }

              /**
               * map是一個對于流對象的中間操作,通過給定的方法,它能夠把流對象中的每一個元素對應到另外一個對象上。
               * 下面的例子就演示了如何把每個string都轉換成大寫的string.
               * 不但如此,你還可以把每一種對象映射成為其他類型。對于帶泛型結果的流對象,具體的類型還要由傳遞給map的泛型方法來決定。
               
          */
              public void useStreamMap() {
                  // <R> Stream<R> map(Function<? super T, ? extends R> mapper);
                  
          // map方法參數為Function函數式接口(R_String,T_String).

                  
          // 解釋:將集合元素轉為大寫(每個元素映射到大寫)->降序排序->迭代輸出
                  
          // 不影響原來集合
                  stringList.stream().map(String::toUpperCase).sorted((a, b) -> b.compareTo(a)).forEach(System.out::println);
              }

              /**
               * 匹配操作有多種不同的類型,都是用來判斷某一種規則是否與流對象相互吻合的。所有的匹配操作都是終結操作,只返回一個boolean類型的結果
               
          */
              public void useStreamMatch() {
                  // boolean anyMatch(Predicate<? super T> predicate);參數為Predicate函數式接口
                  
          // 解釋:集合中是否有任一元素匹配以'a'開頭
                  boolean anyStartsWithA = stringList.stream().anyMatch((s) -> s.startsWith("a"));
                  System.out.println(anyStartsWithA);

                  // boolean allMatch(Predicate<? super T> predicate);
                  
          // 解釋:集合中是否所有元素匹配以'a'開頭
                  boolean allStartsWithA = stringList.stream().allMatch((s) -> s.startsWith("a"));
                  System.out.println(allStartsWithA);

                  // boolean noneMatch(Predicate<? super T> predicate);
                  
          // 解釋:集合中是否沒有元素匹配以'd'開頭
                  boolean nonStartsWithD = stringList.stream().noneMatch((s) -> s.startsWith("d"));
                  System.out.println(nonStartsWithD);
              }

              /**
               * Count是一個終結操作,它的作用是返回一個數值,用來標識當前流對象中包含的元素數量
               
          */
              public void useStreamCount() {
                  // long count();
                  
          // 解釋:返回集合中以'a'開頭元素的數目
                  long startsWithACount = stringList.stream().filter((s) -> s.startsWith("a")).count();
                  System.out.println(startsWithACount);

                  System.out.println(stringList.stream().count());
              }

              /**
               * 該操作是一個終結操作,它能夠通過某一個方法,對元素進行削減操作。該操作的結果會放在一個Optional變量里返回。
               
          */
              public void useStreamReduce() {
                  // Optional<T> reduce(BinaryOperator<T> accumulator);
                  
          // @FunctionalInterface public interface BinaryOperator<T> extends
                  
          // BiFunction<T,T,T> {

                  
          // @FunctionalInterface public interface BiFunction<T, U, R> { R apply(T
                  
          // t, U u);
                  Optional<String> reduced = stringList.stream().sorted().reduce((s1, s2) -> s1 + "#" + s2);

                  // 解釋:集合元素排序后->reduce(削減 )->將元素以#連接->生成Optional對象(其get方法返回#拼接后的值)
                  reduced.ifPresent(System.out::println);
                  System.out.println(reduced.get());
              }

              /**
               * 使用并行流
               * <p>
               * 流操作可以是順序的,也可以是并行的。順序操作通過單線程執行,而并行操作則通過多線程執行. 可使用并行流進行操作來提高運行效率
               
          */
              public void useParallelStreams() {
                  // 初始化一個字符串集合
                  int max = 1000000;
                  List<String> values = new ArrayList<>();

                  for (int i = 0; i < max; i++) {
                      UUID uuid = UUID.randomUUID();
                      values.add(uuid.toString());
                  }

                  // 使用順序流排序

                  long sequenceT0 = System.nanoTime();
                  values.stream().sorted();
                  long sequenceT1 = System.nanoTime();

                  // 輸出:sequential sort took: 51921 ms.
                  System.out.format("sequential sort took: %d ms.", sequenceT1 - sequenceT0).println();

                  // 使用并行流排序
                  long parallelT0 = System.nanoTime();
                  // default Stream<E> parallelStream() {
                  
          // parallelStream為Collection接口的一個默認方法
                  values.parallelStream().sorted();
                  long parallelT1 = System.nanoTime();

                  // 輸出:parallel sort took: 21432 ms.
                  System.out.format("parallel sort took: %d ms.", parallelT1 - parallelT0).println();

                  // 從輸出可以看出:并行排序快了一倍多
              }

              public static void main(String[] args) {
                  StreamUtilExample example = new StreamUtilExample();

                  example.useStreamFilter();
                  example.useStreamMap();
                  example.useStreamMatch();
                  example.useStreamCount();
                  example.useStreamReduce();
                  example.useParallelStreams();
              }
          }


              2.Map接口中新的默認方法示例

          package com.mavsplus.java8.turtorial.streams;

          import java.util.HashMap;
          import java.util.Map;

          /**
           * map是不支持流操作的。而更新后的map現在則支持多種實用的新方法,來完成常規的任務
           * 
           * @author landon
           * @since 1.8.0_25
           
          */
          public class MapUtilExample {

              private Map<Integer, String> map = new HashMap<>();

              public MapUtilExample() {
                  initPut();
              }

              /**
               * 使用更新后的map進行putIfAbsent
               
          */
              private void initPut() {
                  // putIfAbsent為Map接口中新增的一個默認方法
                  /**
                   * <code>
                            default V putIfAbsent(K key, V value) {
                              V v = get(key);
                              if (v == null) {
                                  v = put(key, value);
                              }

                              return v;
                            }
                            </code>
                   
          */
                  // 如果map中有對應K映射的V且不為null則直接返回;否則執行put
                  for (int i = 0; i < 10; i++) {
                      map.putIfAbsent(i, "value" + i);
                  }

                  // 放入了一個null元素
                  map.putIfAbsent(10null);
                  // 替換null
                  map.putIfAbsent(10"value10");
                  // 因為K-10有映射且不為null則忽略V-value11
                  map.putIfAbsent(10"value11");
              }

              /**
               * 使用更新后的map進行for-each
               
          */
              public void forEach() {
                  // default void forEach(BiConsumer<? super K, ? super V> action)
                  
          // Map接口中新增的默認方法

                  
          // @FunctionalInterface public interface BiConsumer<T, U> {void accept(T
                  
          // t, U u);
                  map.forEach((id, val) -> System.out.println(val));
              }

              /**
               * 使用更新后的map進行compute——->重映射
               
          */
              public void compute() {
                  // default V computeIfPresent(K key,BiFunction<? super K, ? super V, ?
                  
          // extends V> remappingFunction)

                  
          // Map接口中新增的默認方法

                  
          // @FunctionalInterface public interface BiFunction<T, U, R> {R apply(T
                  
          // t, U u);
                  
          // --> V apply(K k,V v)

                  
          // ifPresent會判斷key對應的v是否是null,不會null才會compute->否則直接返回null

                  
          // 解釋:將K-3映射的value->compute->"value3" + 3 = value33
                  map.computeIfPresent(3, (key, val) -> val + key);
                  System.out.println(map.get(3));

                  // 解釋:這里將K-3映射的value進行重映射->null
                  
          // 該方法源碼實現會判斷如果newValue為null則會執行remove(key)方法,將移除key
                  map.computeIfPresent(9, (key, val) -> null);
                  // 從上面的解釋中得到,輸出為false,因為已經被移除了
                  System.out.println(map.containsKey(9));

                  // default V computeIfAbsent(K key,Function<? super K, ? extends V>
                  
          // mappingFunction)
                  
          // 解釋:代碼實現上看,如果K-15映射的值為null,即不存在或者為null,則執行映射->所以本例來看(沒有15的key),該方法相當于插入一個新值
                  map.computeIfAbsent(15, (key) -> "val" + key);
                  System.out.println(map.containsKey(15));

                  // 因為K-4映射的值存在,所以直接返回,即不會重映射,所以輸出依然會是value4
                  map.computeIfAbsent(4, key -> "bam");
                  System.out.println(map.get(4));
              }

              /**
               * 使用更新后的map進行remove
               
          */
              public void remove() {
                  // default boolean remove(Object key, Object value) {
                  
          // Map接口中新增的默認方法

                  
          // 其源碼實現是
                  
          // 1.當前key對應的值和傳入的參數不一致時則直接返回,移除失敗(用的是Objects.equals方法)
                  
          // 2.當前key對應的值為null且!containsKey(key),移除失敗(即當前map中根本不存在這個key_【因為有一種情況是有這個key但是key映射的值為null】)
                  
          // ->否則執行移除

                  /**
                   * <code>
                   *  default boolean remove(Object key, Object value) {
                          Object curValue = get(key);
                          if (!Objects.equals(curValue, value) ||
                              (curValue == null && !containsKey(key))) {
                              return false;
                          }
                          remove(key);
                          return true;
                      }
                   * </code>
                   
          */
                  map.remove(3"value4");
                  System.out.println(map.get(3));

                  // key和v匹配時則移除成功
                  map.remove(3"value33");
                  System.out.println(map.get(3));
              }

              /**
               * getOrDefault是一個有用的方法
               
          */
              public void getOrDefault() {
                  // default V getOrDefault(Object key, V defaultValue) {
                  
          // Map接口中新增的默認方法

                  /**
                   * <code>
                   * default V getOrDefault(Object key, V defaultValue) {
                      V v;
                      return (((v = get(key)) != null) || containsKey(key))
                          ? v
                          : defaultValue;
                      }
                   * </code>
                   
          */

                  // 源碼實現:
                  
          // 1.如果對應的key有value且不為null,則直接返回value;如果為null且包含該key,則返回null(總之即必須要有該key)
                  
          // 2.如果沒有該key,則用默認值
                  String retV = map.getOrDefault("20""not found");
                  System.out.println(retV);

                  // 加入一個null
                  map.putIfAbsent(30null);
                  // 輸出null
                  System.out.println(map.get(30));
                  // 輸出null
                  System.out.println(map.getOrDefault(30"value30"));
              }

              /**
               * 合并
               
          */
              public void merge() {
                  // default V merge(K key, V value,BiFunction<? super V, ? super V, ?
                  
          // extends V> remappingFunction)

                  
          // @FunctionalInterface public interface BiFunction<T, U, R> { R apply(T
                  
          // t, U u);

                  
          // merge為Map接口新增的默認方法

                  /**
                   * <code>
                   default V merge(K key, V value,
                      BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
                          Objects.requireNonNull(remappingFunction);
                          Objects.requireNonNull(value);
                          V oldValue = get(key);
                          V newValue = (oldValue == null) ? value :
                                     remappingFunction.apply(oldValue, value);
                          if(newValue == null) {
                              remove(key);
                          } else {
                              put(key, newValue);
                          }
                      return newValue;
                   }
                   * </code>
                   
          */

                  // 其源碼實現:
                  
          // 1.分別檢查參數remappingFunction和value是否為null(調用Objects.requireNonNull).->為null則拋出空指針
                  
          // 2.判斷oldValue是否為null,如果為null則將傳入的newValue賦值;如果oldValue不為null則執行merge函數
                  
          // --->apply(oldValue, value)
                  
          // 3.判斷newValue->如果為null則執行移除;否則執行插入

                  
          // k-9的值在執行compute方法的時候已經被移除了->所以oldValue為null->所以newValue為傳入的參數value9->執行插入
                  
          // 所以這里輸出為value9
                  String newValue1 = map.merge(9"value9", (value, newValue) -> value.concat(newValue));
                  System.out.println(newValue1);
                  System.out.println(map.get(9));

                  // k-9的值現在已經為value9了,所以執行merge函數->"value9".concat("concat")->newValue為"value9concat"
                  
          // 執行插入,所以這里輸出為value9concat
                  String newValue2 = map.merge(9"concat", (value, newValue) -> value.concat(newValue));
                  System.out.println(newValue2);
                  System.out.println(map.get(9));

                  // k-8值存在為value8->執行merge函數->直接返回"NewMerge8"->newValue為"NewMerge8"
                  
          // 執行put->所以這里輸出"NewMerge8"
                  map.merge(8"merge", (value, newValue) -> "NewMerge8");
                  System.out.println(map.get(8));
              }

              public static void main(String[] args) {
                  MapUtilExample example = new MapUtilExample();

                  example.forEach();
                  example.compute();
                  example.remove();
                  example.getOrDefault();
                  example.merge();
              }
          }


          posted on 2014-11-18 20:31 landon 閱讀(24528) 評論(1)  編輯  收藏 所屬分類: Program

          FeedBack:
          # re: Java8之Stream/Map[未登錄]
          2016-01-19 02:13 | jay
          總結的很詳細!  回復  更多評論
            
          主站蜘蛛池模板: 定南县| 清远市| 鄂托克旗| 新绛县| 定南县| 鄂托克前旗| 思南县| 盐山县| 阳春市| 舒兰市| 菏泽市| 伊宁市| 襄垣县| 屏南县| 东阿县| 福鼎市| 封丘县| 岳阳市| 宝丰县| 萍乡市| 金坛市| 金湖县| 安国市| 大名县| 革吉县| 台山市| 宁阳县| 依兰县| 荔波县| 内乡县| 西乌珠穆沁旗| 武义县| 大理市| 土默特右旗| 紫云| 铜山县| 达尔| 集贤县| 全州县| 油尖旺区| 德庆县|