1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 28062字,需瀏覽 57分鐘

         ·

        2024-04-12 03:41

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

        Lambda

        Lambda介紹

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

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

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

        Lambda 表達(dá)式的使用

        下面我們先使用一個簡單的例子來看看Lambda的效果吧。

        比如我們對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也同理,不過List還可以通過雙冒號運(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雙冒號運(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雙冒號運(yùn)算符遍歷:
         a
         bb
         ccc
         dddd

        Lambda 除了在for循環(huán)遍歷中使用外,它還可以代替匿名的內(nèi)部類。比如下面這個例子的線程創(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)建!");

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

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

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

        Lambda雖然簡化了代碼的編寫,但同時也減少了可讀性。

        Stream

        Stream介紹

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

        Stream特性:

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

        Stream 流操作類型:

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

        Stream使用

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

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

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

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

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

        輸出結(jié)果:

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

        是不是很簡潔和方便呢。其實(shí)Stream流還有更多的使用方法,filter只是其中的一角而已。那么在這里我們就來學(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)換

        注意:一個Stream流只可以使用一次,這段代碼為了簡潔而重復(fù)使用了數(shù)次,因此會拋出 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方法用于映射每個元素到對應(yīng)的結(jié)果,一對一。

        示例一:轉(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方法用于通過設(shè)置的條件過濾出元素。

        示例二:通過與 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 過濾之后 2:" + result3);
        System.out.println("stream 過濾之后 3:" + result4);
        //stream 過濾之后 2:李四
        //stream 過濾之后 3:找不到!

        示例三:通過與 mapToInt 計算和

         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, "張三"));
         // 計算這個list中出現(xiàn) "張三" id的值
         int sum = lists.stream().filter(u -> "張三".equals(u.getName())).mapToInt(u -> u.getId()).sum();

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

        5.Stream 流的 flatMap 使用

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

        示例:從句子中得到單詞

         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個元素。

        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 方法會打印姓名。

        7.Stream流的sort使用

        sorted方法用于對流進(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: 先獲取在排序效率會更高!

         //普通的排序取值
         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對每個元素執(zhí)行操作并返回一個新的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("空字符串的個數(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("最長字符的長度:" + maxLines+",最短字符的長度:"+minLines);
         //最長字符的長度:8,最短字符的長度: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 中只要有一個元素符合則返回 true;
        • noneMatch:Stream 中沒有一個元素符合則返回 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("是否有一個大于3:" + any);
         boolean none = lists.stream().noneMatch(u -> u.getId() > 3);
         System.out.println("是否沒有一個大于3的:" + none);  
         // 是否都大于3:false
         // 是否有一個大于3:true
         // 是否沒有一個大于3的:false

        12.Stream流的reduce使用

        reduce 主要作用是把 Stream 元素組合起來進(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

        示例三:求和

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

        示例四:過濾拼接

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

        13.Stream流的iterate使用

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

        示例:生成一個等差隊列

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

        14.Stream流的 Supplier 使用

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

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

         System.out.println("自定義一個流進(jìn)行計算輸出:");
         Stream.generate(new UserSupplier()).limit(2).forEach(u -> System.out.println(u.getId() + ", " + u.getName()));
         
         //第一次:
         //自定義一個流進(jìn)行計算輸出:
         //10, pancm7
         //11, pancm6
         
         //第二次:
         //自定義一個流進(jìn)行計算輸出:
         //10, pancm4
         //11, pancm2
         
         //第三次:
         //自定義一個流進(jìn)行計算輸出:
         //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("通過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());
         }
         
         // 通過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("通過年齡進(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));
         
         // 通過年齡進(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)計信息(如count、min、max、sum和average)的狀態(tài)對象。

        示例:得到最大、最小、之和以及平均數(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流之外,它還新增了全新的日期時間API。在JDK1.8之前,Java處理日期、日歷和時間的方式一直為社區(qū)所詬病,將 java.util.Date設(shè)定為可變類型,以及SimpleDateFormat的非線程安全使其應(yīng)用非常受限。因此推出了java.time包,該包下的所有類都是不可變類型而且線程安全。

        關(guān)鍵類

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

        使用

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

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

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

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

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

          //獲取當(dāng)前的時間,包括毫秒
          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)前時:"+ldt.getHour());
          System.out.println("當(dāng)前分:"+ldt.getMinute());
          System.out.println("當(dāng)前時間:"+ldt.toString());
         //   當(dāng)前年:2018
         //   當(dāng)前年份天數(shù):353
         //   當(dāng)前月:12
         //   當(dāng)前時:15
         //   當(dāng)前分:24
         //   當(dāng)前時間:2018-12-19T15:24:35.833

        3.格式化時間

        格式時間格式需要用到DateTimeFormatter類。

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

        4.時間增減

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

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

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

        通過指定年月日來創(chuàng)建。

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

        6.時間相差比較

        比較相差的年月日時分秒。

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

         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ù)是不滿足一個月的。這里實(shí)際相差的是1月19天,也就是49天。

        示例二:相差總數(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也可以計算相差時分秒。

        示例三:精度時間相差

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

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

        示例四:時間大小比較

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

        7.時區(qū)時間計算

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

        示例一:通過Clock時鐘類獲取計算

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

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

        示例二: 通過ZonedDateTime類和ZoneId

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

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

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

        程序汪資料鏈接

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

        Java項目分享  最新整理全集,找項目不累啦 07版

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

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

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产精品300页 | 午夜一级福利 | 亚洲开心激情 | 99久久久无码国产精品免费 | 在车上做爰吃奶全过程图片 | 黄色电影大香蕉 | 久热精品视频在线播放 | 成人天堂网 | 操逼网站。 | 国产又大又粗 |