<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文詳解 JDK1.8 的 Lambda、Stream、LocalDateTime

          共 28062字,需瀏覽 57分鐘

           ·

          2024-04-12 03:41

          今天跟小伙伴們聊聊 Java中JDK1.8的一些新語(yǔ)法特性使用,主要是Lambda、Stream和LocalDate日期的一些使用講解。

          Lambda

          Lambda介紹

          Lambda 表達(dá)式(lambda expression)是一個(gè)匿名函數(shù),Lambda表達(dá)式基于數(shù)學(xué)中的λ演算得名,直接對(duì)應(yīng)于其中的lambda抽象(lambda abstraction),是一個(gè)匿名函數(shù),即沒(méi)有函數(shù)名的函數(shù)。

          Lambda表達(dá)式的結(jié)構(gòu)

          • 一個(gè) Lambda 表達(dá)式可以有零個(gè)或多個(gè)參數(shù)
          • 參數(shù)的類型既可以明確聲明,也可以根據(jù)上下文來(lái)推斷。例如:(int a)與(a)效果相同
          • 所有參數(shù)需包含在圓括號(hào)內(nèi),參數(shù)之間用逗號(hào)相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)
          • 空?qǐng)A括號(hào)代表參數(shù)集為空。例如:() -> 42
          • 當(dāng)只有一個(gè)參數(shù),且其類型可推導(dǎo)時(shí),圓括號(hào)()可省略。例如:a -> return a*a
          • Lambda 表達(dá)式的主體可包含零條或多條語(yǔ)句
          • 如果 Lambda 表達(dá)式的主體只有一條語(yǔ)句,花括號(hào){}可省略。匿名函數(shù)的返回類型與該主體表達(dá)式一致
          • 如果 Lambda 表達(dá)式的主體包含一條以上語(yǔ)句,則表達(dá)式必須包含在花括號(hào){}中(形成代碼塊)。匿名函數(shù)的返回類型與代碼塊的返回類型一致,若沒(méi)有返回則為空

          Lambda 表達(dá)式的使用

          下面我們先使用一個(gè)簡(jiǎn)單的例子來(lái)看看Lambda的效果吧。

          比如我們對(duì)Map 的遍歷 傳統(tǒng)方式遍歷如下:

            Map<String, String> map = new HashMap<>();
            map.put("a""a");
            map.put("b""b");
            map.put("c""c");
            map.put("d""d");

            System.out.println("map普通方式遍歷:");
            for (String key : map.keySet()) {
             System.out.println("k=" + key + ",v=" + map.get(key));
            }

          使用Lambda進(jìn)行遍歷:

            System.out.println("map拉姆達(dá)表達(dá)式遍歷:");
            map.forEach((k, v) -> {
             System.out.println("k=" + k + ",v=" + v);
           });

          List也同理,不過(guò)List還可以通過(guò)雙冒號(hào)運(yùn)算符遍歷:

            List<String> list = new ArrayList<String>();
            list.add("a");
            list.add("bb");
            list.add("ccc");
            list.add("dddd");
            System.out.println("list拉姆達(dá)表達(dá)式遍歷:");
            list.forEach(v -> {
             System.out.println(v);
            });
            System.out.println("list雙冒號(hào)運(yùn)算符遍歷:");
            list.forEach(System.out::println);

          輸出結(jié)果:

           map普通方式遍歷:
           k=a,v=a
           k=b,v=b
           k=c,v=c
           k=d,v=d
           map拉姆達(dá)表達(dá)式遍歷:
           k=a,v=a
           k=b,v=b
           k=c,v=c
           k=d,v=d
           list拉姆達(dá)表達(dá)式遍歷:
           a
           bb
           ccc
           dddd
           list雙冒號(hào)運(yùn)算符遍歷:
           a
           bb
           ccc
           dddd

          Lambda 除了在for循環(huán)遍歷中使用外,它還可以代替匿名的內(nèi)部類。比如下面這個(gè)例子的線程創(chuàng)建:


           //使用普通的方式創(chuàng)建
           Runnable r1 = new Runnable() {
            @Override
            public void run() {
             System.out.println("普通方式創(chuàng)建!");
            }
           };
           
           //使用拉姆達(dá)方式創(chuàng)建
           Runnable r2 = ()-> System.out.println("拉姆達(dá)方式創(chuàng)建!");

          注: 這個(gè)例子中使用Lambda表達(dá)式的時(shí)候,編譯器會(huì)自動(dòng)推斷:根據(jù)線程類的構(gòu)造函數(shù)簽名 Runnable r { },將該 Lambda 表達(dá)式賦 Runnable 接口。

          Lambda 表達(dá)式與匿名類的區(qū)別使用匿名類與 Lambda 表達(dá)式的一大區(qū)別在于關(guān)鍵詞的使用。對(duì)于匿名類,關(guān)鍵詞 this 解讀為匿名類,而對(duì)于 Lambda 表達(dá)式,關(guān)鍵詞 this 解讀為寫就 Lambda 的外部類。

          Lambda表達(dá)式使用注意事項(xiàng)

          Lambda雖然簡(jiǎn)化了代碼的編寫,但同時(shí)也減少了可讀性。

          Stream

          Stream介紹

          Stream 使用一種類似用 SQL 語(yǔ)句從數(shù)據(jù)庫(kù)查詢數(shù)據(jù)的直觀方式來(lái)提供一種對(duì) Java 集合運(yùn)算和表達(dá)的高階抽象。Stream API可以極大提高Java程序員的生產(chǎn)力,讓程序員寫出高效率、干凈、簡(jiǎn)潔的代碼。這種風(fēng)格將要處理的元素集合看作一種流, 流在管道中傳輸, 并且可以在管道的節(jié)點(diǎn)上進(jìn)行處理, 比如篩選, 排序,聚合等。

          Stream特性:

          • 不是數(shù)據(jù)結(jié)構(gòu):它沒(méi)有內(nèi)部存儲(chǔ),它只是用操作管道從 source(數(shù)據(jù)結(jié)構(gòu)、數(shù)組、generator function、IO channel)抓取數(shù)據(jù)。它也絕不修改自己所封裝的底層數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)。例如 Stream 的 filter 操作會(huì)產(chǎn)生一個(gè)不包含被過(guò)濾元素的新 Stream,而不是從 source 刪除那些元素。
          • 不支持索引訪問(wèn):但是很容易生成數(shù)組或者 List 。
          • 惰性化:很多 Stream 操作是向后延遲的,一直到它弄清楚了最后需要多少數(shù)據(jù)才會(huì)開(kāi)始。Intermediate 操作永遠(yuǎn)是惰性化的。
          • 并行能力。當(dāng)一個(gè) Stream 是并行化的,就不需要再寫多線程代碼,所有對(duì)它的操作會(huì)自動(dòng)并行進(jìn)行的。
          • 可以是無(wú)限的:集合有固定大小,Stream 則不必。limit(n) 和 findFirst() 這類的 short-circuiting 操作可以對(duì)無(wú)限的 Stream 進(jìn)行運(yùn)算并很快完成。
          • 注意事項(xiàng):所有 Stream 的操作必須以 lambda 表達(dá)式為參數(shù)。

          Stream 流操作類型:

          • Intermediate:一個(gè)流可以后面跟隨零個(gè)或多個(gè) intermediate 操作。其目的主要是打開(kāi)流,做出某種程度的數(shù)據(jù)映射/過(guò)濾,然后返回一個(gè)新的流,交給下一個(gè)操作使用。這類操作都是惰性化的(lazy),就是說(shuō),僅僅調(diào)用到這類方法,并沒(méi)有真正開(kāi)始流的遍歷。
          • Terminal:一個(gè)流只能有一個(gè) terminal 操作,當(dāng)這個(gè)操作執(zhí)行后,流就被使用“光”了,無(wú)法再被操作。所以這必定是流的最后一個(gè)操作。Terminal操作的執(zhí)行,才會(huì)真正開(kāi)始流的遍歷,并且會(huì)生成一個(gè)結(jié)果,或者一個(gè) side effect。

          Stream使用

          這里我們依舊使用一個(gè)簡(jiǎn)單示例來(lái)看看吧。在開(kāi)發(fā)中,我們有時(shí)需要對(duì)一些數(shù)據(jù)進(jìn)行過(guò)濾,如果是傳統(tǒng)的方式,我們需要對(duì)這批數(shù)據(jù)進(jìn)行遍歷過(guò)濾,會(huì)顯得比較繁瑣,如果使用steam流方式的話,那么可以很方便的進(jìn)行處理。

          首先通過(guò)普通的方式進(jìn)行過(guò)濾:

          List<String> list = Arrays.asList("張三""李四""王五""xuwujing");
           System.out.println("過(guò)濾之前:" + list);
           List<String> result = new ArrayList<>();
           for (String str : list) {
            if (!"李四".equals(str)) {
             result.add(str);
            }
           }
           System.out.println("過(guò)濾之后:" + result);

          使用Steam方式進(jìn)行過(guò)濾:

          List<String> result2 = list.stream().filter(str -> !"李四".equals(str)).collect(Collectors.toList());
          System.out.println("stream 過(guò)濾之后:" + result2);

          輸出結(jié)果:

          過(guò)濾之前:[張三, 李四, 王五, xuwujing]
          過(guò)濾之后:[張三, 王五, xuwujing]
          stream 過(guò)濾之后:[張三, 王五, xuwujing]

          是不是很簡(jiǎn)潔和方便呢。其實(shí)Stream流還有更多的使用方法,filter只是其中的一角而已。那么在這里我們就來(lái)學(xué)習(xí)了解下這些用法吧。

          1.構(gòu)造Stream流的方式

           Stream stream = Stream.of("a""b""c");
           String[] strArray = new String[] { "a""b""c" };
           stream = Stream.of(strArray);
           stream = Arrays.stream(strArray);
           List<String> list = Arrays.asList(strArray);
           stream = list.stream();

          2.Stream流的之間的轉(zhuǎn)換

          注意:一個(gè)Stream流只可以使用一次,這段代碼為了簡(jiǎn)潔而重復(fù)使用了數(shù)次,因此會(huì)拋出 stream has already been operated upon or closed 異常。

          try {
            Stream<String> stream2 = Stream.of("a""b""c");
            // 轉(zhuǎn)換成 Array
            String[] strArray1 = stream2.toArray(String[]::new);

            // 轉(zhuǎn)換成 Collection
            List<String> list1 = stream2.collect(Collectors.toList());
            List<String> list2 = stream2.collect(Collectors.toCollection(ArrayList::new));   
            Set set1 = stream2.collect(Collectors.toSet());
            Stack stack1 = stream2.collect(Collectors.toCollection(Stack::new));

            // 轉(zhuǎn)換成 String
            String str = stream.collect(Collectors.joining()).toString();
           } catch (Exception e) {
            e.printStackTrace();
           }

          3.Stream流的map使用

          map方法用于映射每個(gè)元素到對(duì)應(yīng)的結(jié)果,一對(duì)一。

          示例一:轉(zhuǎn)換大寫

           List<String> list3 = Arrays.asList("zhangSan""liSi""wangWu");
           System.out.println("轉(zhuǎn)換之前的數(shù)據(jù):" + list3);
           List<String> list4 = list3.stream().map(String::toUpperCase).collect(Collectors.toList());
           System.out.println("轉(zhuǎn)換之后的數(shù)據(jù):" + list4); 
           // 轉(zhuǎn)換之后的數(shù)據(jù):[ZHANGSAN, LISI,WANGWU]

          示例二:轉(zhuǎn)換數(shù)據(jù)類型

           List<String> list31 = Arrays.asList("1""2""3");
           System.out.println("轉(zhuǎn)換之前的數(shù)據(jù):" + list31);
           List<Integer> list41 = list31.stream().map(Integer::valueOf).collect(Collectors.toList());
           System.out.println("轉(zhuǎn)換之后的數(shù)據(jù):" + list41); 
           // [1, 2, 3]

          示例三:獲取平方

           List<Integer> list5 = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 });
           List<Integer> list6 = list5.stream().map(n -> n * n).collect(Collectors.toList());
           System.out.println("平方的數(shù)據(jù):" + list6);
           // [1, 4, 9, 16, 25]

          4.Stream流的filter使用

          filter方法用于通過(guò)設(shè)置的條件過(guò)濾出元素。

          示例二:通過(guò)與 findAny 得到 if/else 的值

          List<String> list = Arrays.asList("張三""李四""王五""xuwujing");
          String result3 = list.stream().filter(str -> "李四".equals(str)).findAny().orElse("找不到!");
          String result4 = list.stream().filter(str -> "李二".equals(str)).findAny().orElse("找不到!");

          System.out.println("stream 過(guò)濾之后 2:" + result3);
          System.out.println("stream 過(guò)濾之后 3:" + result4);
          //stream 過(guò)濾之后 2:李四
          //stream 過(guò)濾之后 3:找不到!

          示例三:通過(guò)與 mapToInt 計(jì)算和

           List<User> lists = new ArrayList<User>();
           lists.add(new User(6, "張三"));
           lists.add(new User(2, "李四"));
           lists.add(new User(3, "王五"));
           lists.add(new User(1, "張三"));
           // 計(jì)算這個(gè)list中出現(xiàn) "張三" id的值
           int sum = lists.stream().filter(u -> "張三".equals(u.getName())).mapToInt(u -> u.getId()).sum();

           System.out.println("計(jì)算結(jié)果:" + sum); 
           // 7

          5.Stream 流的 flatMap 使用

          flatMap 方法用于映射每個(gè)元素到對(duì)應(yīng)的結(jié)果,一對(duì)多。

          示例:從句子中得到單詞

           String worlds = "The way of the future";
           List<String> list7 = new ArrayList<>();
           list7.add(worlds);
           List<String> list8 = list7.stream().flatMap(str -> Stream.of(str.split(" ")))
             .filter(world -> world.length() > 0).collect(Collectors.toList());
           System.out.println("單詞:");
           list8.forEach(System.out::println);
           // 單詞:
           // The 
           // way 
           // of 
           // the 
           // future

          6.Stream流的limit使用

          limit 方法用于獲取指定數(shù)量的流。

          示例一:獲取前n條數(shù)的數(shù)據(jù)

           Random rd = new Random();
           System.out.println("取到的前三條數(shù)據(jù):");
           rd.ints().limit(3).forEach(System.out::println);
           // 取到的前三條數(shù)據(jù):
           // 1167267754
           // -1164558977
           // 1977868798

          示例二:結(jié)合skip使用得到需要的數(shù)據(jù)

          skip表示的是扔掉前n個(gè)元素。

          List<User> list9 = new ArrayList<User>();
           for (int i = 1; i < 4; i++) {
            User user = new User(i, "pancm" + i);
            list9.add(user);
           }
           System.out.println("截取之前的數(shù)據(jù):");
           // 取前3條數(shù)據(jù),但是扔掉了前面的2條,可以理解為拿到的數(shù)據(jù)為 2<=i<3 (i 是數(shù)值下標(biāo))
           List<String> list10 = list9.stream().map(User::getName).limit(3).skip(2).collect(Collectors.toList());
           System.out.println("截取之后的數(shù)據(jù):" + list10);
           //  截取之前的數(shù)據(jù):
           //  姓名:pancm1
           //  姓名:pancm2
           //  姓名:pancm3
           //  截取之后的數(shù)據(jù):[pancm3]

          注:User實(shí)體類中 getName 方法會(huì)打印姓名。

          7.Stream流的sort使用

          sorted方法用于對(duì)流進(jìn)行升序排序。

          示例一:隨機(jī)取值排序

           Random rd2 = new Random();
           System.out.println("取到的前三條數(shù)據(jù)然后進(jìn)行排序:");
           rd2.ints().limit(3).sorted().forEach(System.out::println);
           // 取到的前三條數(shù)據(jù)然后進(jìn)行排序:
           // -2043456377
           // -1778595703
           // 1013369565

          示例二:優(yōu)化排序

          tips: 先獲取在排序效率會(huì)更高!

           //普通的排序取值
           List<User> list11 = list9.stream().sorted((u1, u2) -> u1.getName().compareTo(u2.getName())).limit(3)
             .collect(Collectors.toList());
           System.out.println("排序之后的數(shù)據(jù):" + list11);
           //優(yōu)化排序取值
           List<User> list12 = list9.stream().limit(3).sorted((u1, u2) -> u1.getName().compareTo(u2.getName()))
             .collect(Collectors.toList());
           System.out.println("優(yōu)化排序之后的數(shù)據(jù):" + list12);
           //排序之后的數(shù)據(jù):[{"id":1,"name":"pancm1"}, {"id":2,"name":"pancm2"}, {"id":3,"name":"pancm3"}]
           //優(yōu)化排序之后的數(shù)據(jù):[{"id":1,"name":"pancm1"}, {"id":2,"name":"pancm2"}, {"id":3,"name":"pancm3"}]

          8.Stream流的peek使用

          peek對(duì)每個(gè)元素執(zhí)行操作并返回一個(gè)新的Stream

          示例: 雙重操作

           System.out.println("peek使用:");
           Stream.of("one""two""three""four").filter(e -> e.length() > 3).peek(e -> System.out.println("轉(zhuǎn)換之前: " + e))
             .map(String::toUpperCase).peek(e -> System.out.println("轉(zhuǎn)換之后: " + e)).collect(Collectors.toList());
           
           // 轉(zhuǎn)換之前: three
           // 轉(zhuǎn)換之后: THREE
           // 轉(zhuǎn)換之前: four
           // 轉(zhuǎn)換之后: FOUR

          9.Stream流的parallel使用

          parallelStream 是流并行處理程序的代替方法。

          示例:獲取空字符串的數(shù)量

           List<String> strings = Arrays.asList("a""""c""""e",""" ");
           // 獲取空字符串的數(shù)量
           long count =  strings.parallelStream().filter(string -> string.isEmpty()).count();
           System.out.println("空字符串的個(gè)數(shù):"+count);

          10.Stream流的max/min/distinct使用

          示例一:得到最大最小值

           List<String> list13 = Arrays.asList("zhangsan","lisi","wangwu","xuwujing");
           int maxLines = list13.stream().mapToInt(String::length).max().getAsInt();
           int minLines = list13.stream().mapToInt(String::length).min().getAsInt();
           System.out.println("最長(zhǎng)字符的長(zhǎng)度:" + maxLines+",最短字符的長(zhǎng)度:"+minLines);
           //最長(zhǎng)字符的長(zhǎng)度:8,最短字符的長(zhǎng)度:4

          示例二:得到去重之后的數(shù)據(jù)

           String lines = "good good study day day up";
           List<String> list14 = new ArrayList<String>();
           list14.add(lines);
           List<String> words = list14.stream().flatMap(line -> Stream.of(line.split(" "))).filter(word -> word.length() > 0)
             .map(String::toLowerCase).distinct().sorted().collect(Collectors.toList());
           System.out.println("去重復(fù)之后:" + words);
           //去重復(fù)之后:[day, good, study, up]

          11.Stream流的Match使用

          • allMatch:Stream 中全部元素符合則返回 true ;
          • anyMatch:Stream 中只要有一個(gè)元素符合則返回 true;
          • noneMatch:Stream 中沒(méi)有一個(gè)元素符合則返回 true。

          示例:數(shù)據(jù)是否符合

           boolean all = lists.stream().allMatch(u -> u.getId() > 3);
           System.out.println("是否都大于3:" + all);
           boolean any = lists.stream().anyMatch(u -> u.getId() > 3);
           System.out.println("是否有一個(gè)大于3:" + any);
           boolean none = lists.stream().noneMatch(u -> u.getId() > 3);
           System.out.println("是否沒(méi)有一個(gè)大于3的:" + none);  
           // 是否都大于3:false
           // 是否有一個(gè)大于3:true
           // 是否沒(méi)有一個(gè)大于3的:false

          12.Stream流的reduce使用

          reduce 主要作用是把 Stream 元素組合起來(lái)進(jìn)行操作。

          示例一:字符串連接

          String concat = Stream.of("A""B""C""D").reduce("", String::concat);
          System.out.println("字符串拼接:" + concat);

          示例二:得到最小值

           double minValue = Stream.of(-4.0, 1.0, 3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
           System.out.println("最小值:" + minValue);
           //最小值:-4.0

          示例三:求和

           // 求和, 無(wú)起始值
           int sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
           System.out.println("有無(wú)起始值求和:" + sumValue);
           // 求和, 有起始值
            sumValue = Stream.of(1, 2, 3, 4).reduce(1, Integer::sum);
            System.out.println("有起始值求和:" + sumValue);
           // 有無(wú)起始值求和:10
           // 有起始值求和:11

          示例四:過(guò)濾拼接

          concat = Stream.of("a""B""c""D""e""F").filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
          System.out.println("過(guò)濾和字符串連接:" + concat);
           //過(guò)濾和字符串連接:ace

          13.Stream流的iterate使用

          iterate 跟 reduce 操作很像,接受一個(gè)種子值,和一個(gè)UnaryOperator(例如 f)。然后種子值成為 Stream 的第一個(gè)元素,f(seed) 為第二個(gè),f(f(seed)) 第三個(gè),以此類推。在 iterate 時(shí)候管道必須有 limit 這樣的操作來(lái)限制 Stream 大小。

          示例:生成一個(gè)等差隊(duì)列

           System.out.println("從2開(kāi)始生成一個(gè)等差隊(duì)列:");
           Stream.iterate(2, n -> n + 2).limit(5).forEach(x -> System.out.print(x + " "));
           // 從2開(kāi)始生成一個(gè)等差隊(duì)列:
           // 2 4 6 8 10

          14.Stream流的 Supplier 使用

          通過(guò)實(shí)現(xiàn)Supplier類的方法可以自定義流計(jì)算規(guī)則。

          示例:隨機(jī)獲取兩條用戶信息

           System.out.println("自定義一個(gè)流進(jìn)行計(jì)算輸出:");
           Stream.generate(new UserSupplier()).limit(2).forEach(u -> System.out.println(u.getId() + ", " + u.getName()));
           
           //第一次:
           //自定義一個(gè)流進(jìn)行計(jì)算輸出:
           //10, pancm7
           //11, pancm6
           
           //第二次:
           //自定義一個(gè)流進(jìn)行計(jì)算輸出:
           //10, pancm4
           //11, pancm2
           
           //第三次:
           //自定義一個(gè)流進(jìn)行計(jì)算輸出:
           //10, pancm4
           //11, pancm8


          class UserSupplier implements Supplier<User> {
           private int index = 10;
           private Random random = new Random();

           @Override
           public User get() {
            return new User(index++, "pancm" + random.nextInt(10));
           }
          }

          15.Stream流的groupingBy/partitioningBy使用

          • groupingBy:分組排序;
          • partitioningBy:分區(qū)排序。

          示例一:分組排序

           System.out.println("通過(guò)id進(jìn)行分組排序:");
           Map<Integer, List<User>> personGroups = Stream.generate(new UserSupplier2()).limit(5)
             .collect(Collectors.groupingBy(User::getId));
           Iterator it = personGroups.entrySet().iterator();
           while (it.hasNext()) {
            Map.Entry<Integer, List<User>> persons = (Map.Entry) it.next();
            System.out.println("id " + persons.getKey() + " = " + persons.getValue());
           }
           
           // 通過(guò)id進(jìn)行分組排序:
           // id 10 = [{"id":10,"name":"pancm1"}] 
           // id 11 = [{"id":11,"name":"pancm3"}, {"id":11,"name":"pancm6"}, {"id":11,"name":"pancm4"}, {"id":11,"name":"pancm7"}]



           class UserSupplier2 implements Supplier<User> {
            private int index = 10;
            private Random random = new Random();
           
            @Override
            public User get() {
             return new User(index % 2 == 0 ? index++ : index, "pancm" + random.nextInt(10));
            }
           }

          示例二:分區(qū)排序

              System.out.println("通過(guò)年齡進(jìn)行分區(qū)排序:");
           Map<Boolean, List<User>> children = Stream.generate(new UserSupplier3()).limit(5)
             .collect(Collectors.partitioningBy(p -> p.getId() < 18));

           System.out.println("小孩: " + children.get(true));
           System.out.println("成年人: " + children.get(false));
           
           // 通過(guò)年齡進(jìn)行分區(qū)排序:
           // 小孩: [{"id":16,"name":"pancm7"}, {"id":17,"name":"pancm2"}]
           // 成年人: [{"id":18,"name":"pancm4"}, {"id":19,"name":"pancm9"}, {"id":20,"name":"pancm6"}]

            class UserSupplier3 implements Supplier<User> {
            private int index = 16;
            private Random random = new Random();
           
            @Override
            public User get() {
             return new User(index++, "pancm" + random.nextInt(10));
            }
           }

          16.Stream流的summaryStatistics使用

          IntSummaryStatistics 用于收集統(tǒng)計(jì)信息(如count、min、max、sum和average)的狀態(tài)對(duì)象。

          示例:得到最大、最小、之和以及平均數(shù)。

           List<Integer> numbers = Arrays.asList(1, 5, 7, 3, 9);
           IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
            
           System.out.println("列表中最大的數(shù) : " + stats.getMax());
           System.out.println("列表中最小的數(shù) : " + stats.getMin());
           System.out.println("所有數(shù)之和 : " + stats.getSum());
           System.out.println("平均數(shù) : " + stats.getAverage());
           
           // 列表中最大的數(shù) : 9
           // 列表中最小的數(shù) : 1
           // 所有數(shù)之和 : 25
           // 平均數(shù) : 5.0

          Stream 介紹就到這里了,JDK1.8中的Stream流其實(shí)還有很多很多用法,更多的用法則需要大家去查看JDK1.8的API文檔了。

          LocalDateTime

          介紹

          JDK1.8除了新增了lambda表達(dá)式、stream流之外,它還新增了全新的日期時(shí)間API。在JDK1.8之前,Java處理日期、日歷和時(shí)間的方式一直為社區(qū)所詬病,將 java.util.Date設(shè)定為可變類型,以及SimpleDateFormat的非線程安全使其應(yīng)用非常受限。因此推出了java.time包,該包下的所有類都是不可變類型而且線程安全。

          關(guān)鍵類

          • Instant:瞬時(shí)時(shí)間。
          • LocalDate:本地日期,不包含具體時(shí)間, 格式 yyyy-MM-dd。
          • LocalTime:本地時(shí)間,不包含日期. 格式 yyyy-MM-dd HH:mm:ss.SSS 。
          • LocalDateTime:組合了日期和時(shí)間,但不包含時(shí)差和時(shí)區(qū)信息。
          • ZonedDateTime:最完整的日期時(shí)間,包含時(shí)區(qū)和相對(duì)UTC或格林威治的時(shí)差。

          使用

          1.獲取當(dāng)前的日期時(shí)間

          通過(guò)靜態(tài)工廠方法now()來(lái)獲取當(dāng)前時(shí)間。

           //本地日期,不包括時(shí)分秒
           LocalDate nowDate = LocalDate.now();
           //本地日期,包括時(shí)分秒
           LocalDateTime nowDateTime = LocalDateTime.now();
           System.out.println("當(dāng)前時(shí)間:"+nowDate);
           System.out.println("當(dāng)前時(shí)間:"+nowDateTime);
           //  當(dāng)前時(shí)間:2018-12-19
           //  當(dāng)前時(shí)間:2018-12-19T15:24:35.822

          2.獲取當(dāng)前的年月日時(shí)分秒

          獲取時(shí)間之后,直接get獲取年月日時(shí)分秒。

            //獲取當(dāng)前的時(shí)間,包括毫秒
            LocalDateTime ldt = LocalDateTime.now();
            System.out.println("當(dāng)前年:"+ldt.getYear());   //2018
            System.out.println("當(dāng)前年份天數(shù):"+ldt.getDayOfYear());//172 
            System.out.println("當(dāng)前月:"+ldt.getMonthValue());
            System.out.println("當(dāng)前時(shí):"+ldt.getHour());
            System.out.println("當(dāng)前分:"+ldt.getMinute());
            System.out.println("當(dāng)前時(shí)間:"+ldt.toString());
           //   當(dāng)前年:2018
           //   當(dāng)前年份天數(shù):353
           //   當(dāng)前月:12
           //   當(dāng)前時(shí):15
           //   當(dāng)前分:24
           //   當(dāng)前時(shí)間:2018-12-19T15:24:35.833

          3.格式化時(shí)間

          格式時(shí)間格式需要用到DateTimeFormatter類。

          LocalDateTime ldt = LocalDateTime.now();
          System.out.println("格式化時(shí)間: "+ ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
          //格式化時(shí)間:2018-12-19 15:37:47.119

          4.時(shí)間增減

          在指定的時(shí)間進(jìn)行增加/減少年月日時(shí)分秒。

            LocalDateTime ldt = LocalDateTime.now();
            System.out.println("后5天時(shí)間:"+ldt.plusDays(5));
            System.out.println("前5天時(shí)間并格式化:"+ldt.minusDays(5).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); //2018-06-16
            System.out.println("前一個(gè)月的時(shí)間:"+ldt2.minusMonths(1).format(DateTimeFormatter.ofPattern("yyyyMM"))); //2018-06-16
            System.out.println("后一個(gè)月的時(shí)間:"+ldt2.plusMonths(1)); //2018-06-16
            System.out.println("指定2099年的當(dāng)前時(shí)間:"+ldt.withYear(2099)); //2099-06-21T15:07:39.506
           //  后5天時(shí)間:2018-12-24T15:50:37.508
           //  前5天時(shí)間并格式化:2018-12-14
           //  前一個(gè)月的時(shí)間:201712
           //  后一個(gè)月的時(shí)間:2018-02-04T09:19:29.499
           //  指定2099年的當(dāng)前時(shí)間:2099-12-19T15:50:37.508

          5.創(chuàng)建指定時(shí)間

          通過(guò)指定年月日來(lái)創(chuàng)建。

           LocalDate ld3=LocalDate.of(2017, Month.NOVEMBER, 17);
           LocalDate ld4=LocalDate.of(2018, 02, 11);

          6.時(shí)間相差比較

          比較相差的年月日時(shí)分秒。

          示例一: 具體相差的年月日

           LocalDate ld=LocalDate.parse("2017-11-17");
           LocalDate ld2=LocalDate.parse("2018-01-05");
           Period p=Period.between(ld, ld2);
           System.out.println("相差年: "+p.getYears()+" 相差月 :"+p.getMonths() +" 相差天:"+p.getDays());
           // 相差年: 0 相差月 :1 相差天:19

          注:這里的月份是不滿足一年,天數(shù)是不滿足一個(gè)月的。這里實(shí)際相差的是1月19天,也就是49天。

          示例二:相差總數(shù)的時(shí)間

          ChronoUnit 日期周期單位的標(biāo)準(zhǔn)集合。

              LocalDate startDate = LocalDate.of(2017, 11, 17);
                  LocalDate endDate = LocalDate.of(2018, 01, 05);
                  System.out.println("相差月份:"+ChronoUnit.MONTHS.between(startDate, endDate));
                  System.out.println("兩月之間的相差的天數(shù)   : " + ChronoUnit.DAYS.between(startDate, endDate));
            //        相差月份:1
            //        兩天之間的差在天數(shù)   : 49

          注:ChronoUnit也可以計(jì)算相差時(shí)分秒。

          示例三:精度時(shí)間相差

          Duration 這個(gè)類以秒和納秒為單位建模時(shí)間的數(shù)量或數(shù)量。

           Instant inst1 = Instant.now();
              System.out.println("當(dāng)前時(shí)間戳 : " + inst1);
              Instant inst2 = inst1.plus(Duration.ofSeconds(10));
              System.out.println("增加之后的時(shí)間 : " + inst2);
              System.out.println("相差毫秒 : " + Duration.between(inst1, inst2).toMillis());
              System.out.println("相毫秒 : " + Duration.between(inst1, inst2).getSeconds());
           // 當(dāng)前時(shí)間戳 : 2018-12-19T08:14:21.675Z
           // 增加之后的時(shí)間 : 2018-12-19T08:14:31.675Z
           // 相差毫秒 : 10000
           // 相毫秒 : 10

          示例四:時(shí)間大小比較

            LocalDateTime ldt4 = LocalDateTime.now();
            LocalDateTime ldt5 = ldt4.plusMinutes(10);
            System.out.println("當(dāng)前時(shí)間是否大于:"+ldt4.isAfter(ldt5));
            System.out.println("當(dāng)前時(shí)間是否小于"+ldt4.isBefore(ldt5));
            // false
            // true

          7.時(shí)區(qū)時(shí)間計(jì)算

          得到其他時(shí)區(qū)的時(shí)間。

          示例一:通過(guò)Clock時(shí)鐘類獲取計(jì)算

          Clock時(shí)鐘類用于獲取當(dāng)時(shí)的時(shí)間戳,或當(dāng)前時(shí)區(qū)下的日期時(shí)間信息。

            Clock clock = Clock.systemUTC();
            System.out.println("當(dāng)前時(shí)間戳 : " + clock.millis());
            Clock clock2 = Clock.system(ZoneId.of("Asia/Shanghai"));
            System.out.println("亞洲上海此時(shí)的時(shí)間戳:"+clock2.millis());
            Clock clock3 = Clock.system(ZoneId.of("America/New_York"));
            System.out.println("美國(guó)紐約此時(shí)的時(shí)間戳:"+clock3.millis());
            //  當(dāng)前時(shí)間戳 : 1545209277657
            //  亞洲上海此時(shí)的時(shí)間戳:1545209277657
            //  美國(guó)紐約此時(shí)的時(shí)間戳:1545209277658

          示例二: 通過(guò)ZonedDateTime類和ZoneId

            ZoneId zoneId= ZoneId.of("America/New_York");
            ZonedDateTime dateTime=ZonedDateTime.now(zoneId);
            System.out.println("美國(guó)紐約此時(shí)的時(shí)間 : " + dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
            System.out.println("美國(guó)紐約此時(shí)的時(shí)間 和時(shí)區(qū): " + dateTime);
            //  美國(guó)紐約此時(shí)的時(shí)間 : 2018-12-19 03:52:22.494
            // 美國(guó)紐約此時(shí)的時(shí)間 和時(shí)區(qū): 2018-12-19T03:52:22.494-05:00[America/New_York]

          Java 8日期時(shí)間API總結(jié):

          • 提供了javax.time.ZoneId 獲取時(shí)區(qū)。
          • 提供了LocalDate和LocalTime類。
          • Java 8 的所有日期和時(shí)間API都是不可變類并且線程安全,而現(xiàn)有的Date和Calendar API中的java.util.Date和SimpleDateFormat是非線程安全的。
          • 主包是 java.time,包含了表示日期、時(shí)間、時(shí)間間隔的一些類。里面有兩個(gè)子包java.time.format用于格式化, java.time.temporal用于更底層的操作。
          • 時(shí)區(qū)代表了地球上某個(gè)區(qū)域內(nèi)普遍使用的標(biāo)準(zhǔn)時(shí)間。每個(gè)時(shí)區(qū)都有一個(gè)代號(hào),格式通常由區(qū)域/城市構(gòu)成(Asia/Tokyo),在加上與格林威治或 UTC的時(shí)差。例如:東京的時(shí)差是+09:00。
          • OffsetDateTime類實(shí)際上組合了LocalDateTime類和ZoneOffset類。用來(lái)表示包含和格林威治或UTC時(shí)差的完整日期(年、月、日)和時(shí)間(時(shí)、分、秒、納秒)信息。
          • DateTimeFormatter 類用來(lái)格式化和解析時(shí)間。與SimpleDateFormat不同,這個(gè)類不可變并且線程安全,需要時(shí)可以給靜態(tài)常量賦值。DateTimeFormatter類提供了大量的內(nèi)置格式化工具,同時(shí)也允許你自定義。在轉(zhuǎn)換方面也提供了parse()將字符串解析成日期,如果解析出錯(cuò)會(huì)拋出DateTimeParseException。DateTimeFormatter類同時(shí)還有format()用來(lái)格式化日期,如果出錯(cuò)會(huì)拋出DateTimeException異常。
          • 再補(bǔ)充一點(diǎn),日期格式“MMM d yyyy”和“MMM dd yyyy”有一些微妙的不同,第一個(gè)格式可以解析“Jan 2 2014”和“Jan 14 2014”,而第二個(gè)在解析“Jan 2 2014”就會(huì)拋異常,因?yàn)榈诙€(gè)格式里要求日必須是兩位的。如果想修正,你必須在日期只有個(gè)位數(shù)時(shí)在前面補(bǔ)零,就是說(shuō)“Jan 2 2014”應(yīng)該寫成 “Jan 02 2014”。
                 

          程序汪資料鏈接

          程序汪接私活項(xiàng)目目錄,2023年總結(jié)

          Java項(xiàng)目分享  最新整理全集,找項(xiàng)目不累啦 07版

          歡迎添加程序汪微信 itwang007  進(jìn)粉絲群

          瀏覽 37
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  av先锋资源在线 AV性爱在线观看 av在线无码高清 | 亚洲小穴| 久久国产精品精品国产色婷婷 | 一级a一级a爰片免费免免在线 | 五月天成人免费视频 |