<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>

          Java8 HashMap優(yōu)化、lambda、Stream等詳解

          共 10527字,需瀏覽 22分鐘

           ·

          2022-05-09 19:51

          你知道的越多,不知道的就越多,業(yè)余的像一棵小草!

          你來(lái),我們一起精進(jìn)!你不來(lái),我和你的競(jìng)爭(zhēng)對(duì)手一起精進(jìn)!

          編輯:業(yè)余草

          modb.pro

          推薦:https://www.xttblog.com/?p=5342

          Java8新特性

          目錄

          • 一、概述
          • 二、優(yōu)化底層數(shù)據(jù)結(jié)構(gòu)
          • 2.1、優(yōu)化HashMap
          • 三、Lambda表達(dá)式
          • 3.1、概述
          • 3.2、匿名內(nèi)部類(lèi)到lambda
          • 3.3、lambda語(yǔ)法
          • 3.4、函數(shù)式接口
          • 3.5、方法引用
          • 四、Stream
          • 4.1、概述
          • 4.2、創(chuàng)建Stream
          • 4.3、中間操作
          • 4.3.1、篩選與切片
          • 4.3.2、映射map
          • 4.3.3、排序sorted
          • 4.4、終止操作
          • 4.4.1、查找與匹配
          • 4.4.2、規(guī)約
          • 4.4.3、收集collect
          • 4.5、并行流
          • 4.5.1、Fork/Join框架
          • 4.5.2、測(cè)試并行流
          • 五、新時(shí)間API
          • 5.1、Java.time
          • 5.1、日期
          • 5.2、時(shí)間
          • 5.3、時(shí)間+日期
          • 5.4、時(shí)間戳
          • 5.5、字符串轉(zhuǎn)日期格式化
          • 5.6、時(shí)間推移
          • 5.7、時(shí)間抽取
          • 5.8、時(shí)區(qū)
          • 5.9、Date與LocalDateTime互轉(zhuǎn)
          • 六、Optional容器類(lèi)
          • 七、接口中的默認(rèn)方法與靜態(tài)方法
          • 八、重復(fù)注解與類(lèi)型注解
          • 8.1、重復(fù)注解
          • 8.2、類(lèi)型注解
          • 8.3、@NonNull注解

          一、概述

          ?

          「Java8 的優(yōu)勢(shì)」

          ?
          • 速度更快
          • 代碼更少
          • 強(qiáng)大的Stream API
          • 便于并行
          • 最大化減少空指針Optional

          二、優(yōu)化底層數(shù)據(jù)結(jié)構(gòu)

          2.1、優(yōu)化HashMap

          ?

          「【原始Map】」

          第10001個(gè)值存入,為避免k值相同,會(huì)進(jìn)行10000次equals,效率非常低

          ?
          優(yōu)化HashMap
          ?

          「【java7 HashMap】:數(shù)組+鏈表」

          HashMap 是 16 個(gè)位置的數(shù)組,并提供"加載因子",當(dāng)達(dá)到75%時(shí),自動(dòng)擴(kuò)容,會(huì)對(duì)所有元素進(jìn)行重新運(yùn)算生成新的數(shù)組+鏈表

          當(dāng)存入值時(shí),會(huì)先把值通過(guò) hashcode 生成對(duì)應(yīng)的索引,

          確定索引后,會(huì)跟該索引下的值進(jìn)行比較,比較len(鏈表長(zhǎng)度)次,沒(méi)有重復(fù)則形成鏈表(放鏈表頭)。

          效率有所提高,但是如果鏈表較長(zhǎng)有10000個(gè)元素,依舊需要比較1000次。

          ?
          數(shù)組+鏈表
          ?

          「【java8 HashMap】:數(shù)組+(鏈表/紅黑樹(shù))」

          當(dāng)鏈表長(zhǎng)度大于8,且hashmap總?cè)萘看笥?4,會(huì)將鏈表自動(dòng)轉(zhuǎn)為紅黑樹(shù)

          添加元素比鏈表慢,其他的都比鏈表更快速

          ?
          java8 HashMap

          三、Lambda表達(dá)式

          3.1、概述

          ?

          【概述】

          ?

          Lambda是一個(gè)匿名函數(shù),可以理解為一段可以傳遞的代碼

          Lambda是特殊的匿名內(nèi)部類(lèi),允許將函數(shù)當(dāng)做方法的參數(shù)傳遞

          ?

          優(yōu)勢(shì)

          ?

          可以寫(xiě)出更簡(jiǎn)潔、更靈活的代碼。

          ?

          經(jīng)驗(yàn)

          ?
          Lambda表達(dá)式的作用主要是用來(lái)簡(jiǎn)化接口的創(chuàng)建,interface。
          需要注意的是:
          1.任何需要使用interface的地方都可以使用Lambda表達(dá)式來(lái)簡(jiǎn)化;
          2.Lambda表達(dá)式不能夠簡(jiǎn)化類(lèi)或者抽象類(lèi)得創(chuàng)建,如果試圖使用Lambda表達(dá)式去創(chuàng)建一個(gè)類(lèi)或者抽象類(lèi)
          將會(huì)報(bào)錯(cuò)如下英文信息 ”Target type of a lambda conversion must be an interface“
          這就是為什么Lambda表達(dá)式只用用來(lái)簡(jiǎn)化創(chuàng)建接口

          3.2、匿名內(nèi)部類(lèi)到lambda

          • 「匿名內(nèi)部類(lèi)」
          //?匿名內(nèi)部類(lèi)
          Runnable?runnable?=?new?Runnable()?{
          ????@Override
          ????public?void?run()?{
          ????????System.out.println("子線程開(kāi)始執(zhí)行。。。。");
          ????}
          };
          new?Thread(runnable).start();
          • 「lambda表達(dá)式」
          //?lambda表達(dá)式
          Runnable?runnable2?=?()?->?System.out.println("lambda子線程開(kāi)始執(zhí)行。。。。");
          new?Thread(runnable2).start();

          3.3、lambda語(yǔ)法

          ?

          參數(shù)列表 -> 方法體

          ?
          • 「1、無(wú)參要寫(xiě)括號(hào)」

            () -> System.out.println("無(wú)參");

          • 「2、只有一個(gè)參數(shù),可以不寫(xiě)括號(hào)」

            x -> System.out.println(x);

          • 「3、多條語(yǔ)句用{}」

          Comparator?com?=?(x,?y)?->?{
          ????System.out.println("...");
          ????return?Integer.compare(x,?y);
          }
          • 「4、若lambda體中只有一條語(yǔ)句,return和{}都可以不寫(xiě)」

          Comparator com = (x, y) -> Integer.compare(x, y);

          • 「5、lambda參數(shù)列表的數(shù)據(jù)類(lèi)型可以省略不寫(xiě)(JVM編譯器通過(guò)上下文做"類(lèi)型推斷")」
          Comparator?com?=?(Integer?x,?Integer?y)?->??Integer.compare(x,?y);
          Comparator?com?=?(x,?y)?->??Integer.compare(x,?y);
          • 「6、匿名內(nèi)部類(lèi)會(huì)單獨(dú)生成一個(gè)單獨(dú)的.class文件,lambda表達(dá)式不會(huì)生成。」

          3.4、函數(shù)式接口

          只有函數(shù)式接口(只有一個(gè)抽象方法的接口@FunctionalInterface)才能使用lambda表達(dá)式

          ?

          常見(jiàn)函數(shù)式接口

          ?
          常見(jiàn)函數(shù)式接口
          ?

          常用函數(shù)式接口子接口

          ?
          常用函數(shù)式接口子接口
          ?

          使用演示

          ?
          • 「Consumer(有參無(wú)返回值)」
          @Test
          public?void?test(){
          ????//?匿名內(nèi)部類(lèi)
          ????Consumer?consumer1?=?new?Consumer(){
          ????????@Override
          ????????public?void?accept(Integer?n)?{
          ????????????System.out.println(n?+?1);
          ????????}
          ????};
          ????consumer(consumer1,?100);

          ????//?lambda
          ????Consumer?consumer?=?n?->?System.out.println(n?+?1);
          ????consumer(consumer,?100);
          }

          public?void?consumer(Consumer?consumer,?Integer?n){
          ????consumer.accept(n);
          }
          • 「Supplier(無(wú)參有返回值)」
          @Test
          public?void?test(){
          ????//?lambda表達(dá)式
          ????int[]?arr?=?getNums(()?->?new?Random().nextInt(100),?10);
          ????System.out.println(Arrays.toString(arr));
          }

          public?int[]?getNums(Supplier?supplier,?int?count){
          ????int[]?arr?=?new?int[count];
          ????for(int?i=0;?i????????arr[i]?=?supplier.get();
          ????}
          ????return?arr;
          }
          • 「Function有參有返回值」
          @Test
          public?void?test(){
          ????//?lambda表達(dá)式
          ????String?str?=?dealStr(s?->?s.toUpperCase(),?"abc");
          ????System.out.println(str);
          }

          public?String?dealStr(Function?function,?String?str){
          ????return?function.apply(str);
          }
          • 「Predicate有參,返回布爾值」
          @Test
          public?void?test(){
          ????//?lambda表達(dá)式
          ????List?ageList?=?new?ArrayList<>();
          ????ageList.add(10);
          ????ageList.add(19);
          ????List?resultList?=?filterAge(age?->?age?>?18,?ageList);
          ????System.out.println(resultList.toString());
          }

          public?List?filterAge(Predicate?predicate,?List?ageList){
          ????List?resultList?=?new?ArrayList<>();
          ????for?(Integer?i:?ageList)?{
          ????????if(predicate.test(i)){
          ????????????resultList.add(i);
          ????????}
          ????}
          ????return?resultList;
          }

          3.5、方法引用

          • 是Lambda表達(dá)式的一種簡(jiǎn)寫(xiě)

          • 如果lambda表達(dá)式中,只是調(diào)用一個(gè)特定的已存在的方法,則可以使用方法引用

          ?

          「對(duì)象::實(shí)例方法」

          ?
          //?lambda表達(dá)式
          Consumer?consumer?=?s?->?System.out.println(s);
          consumer.accept("hello");

          //?對(duì)象::實(shí)例方法
          Consumer?consumer2?=?System.out::println;
          consumer2.accept("world");
          ?

          「對(duì)象::靜態(tài)方法」

          ?
          //?lambda表達(dá)式
          Comparator?comparator?=?(x,?y)?->?Integer.compare(x,?y);

          //?對(duì)象::靜態(tài)方法
          Comparator?comparator2?=?Integer::compare;
          ?

          「類(lèi)::實(shí)例方法」

          ?

          【注意】

          1、Lambda體中參數(shù)列表和返回值類(lèi)型,要與函數(shù)式抽象方法中抽象方法的保持一致

          2、若Lambda參數(shù)列表中,第一個(gè)參數(shù)是實(shí)例方法的調(diào)用者,第二個(gè)是實(shí)例方法的參數(shù),可以使用ClassName::method

          //?lambda表達(dá)式
          BiPredicate?bp?=?(x,?y)?->?x.equals(y);

          //?對(duì)象::靜態(tài)方法(ClassName::method)
          BiPredicate?bp2?=?String::equals;
          ?

          「類(lèi)::new」

          ?
          • 「構(gòu)造器引用」
          //?lambda表達(dá)式
          Supplier?supplier?=?()?->?new?User();

          //?對(duì)象::靜態(tài)方法
          Supplier?supplier2?=?User?::?new;
          • 「數(shù)組引用」
          //?lambda表達(dá)式
          Function?function?=?x?->?new?String[x];

          //?對(duì)象::靜態(tài)方法
          Function?function2?=?String[]::new;

          四、Stream

          Stream

          4.1、概述

          ?

          「概述」

          ?

          【概述】:流(Stream)中保存對(duì)集合數(shù)組數(shù)據(jù)的操作

          【特點(diǎn)】:

          1、Stream只保存操作,自己不保存數(shù)據(jù)

          2、Stream不會(huì)改變?cè)瓕?duì)象

          3、Stream操作是延遲執(zhí)行的(只有執(zhí)行終止操作,才一次性全部執(zhí)行,稱(chēng)為"惰性求值")

          ?

          「操作步驟」

          ?
          • 「1、創(chuàng)建Stream」

            一個(gè)數(shù)據(jù)源(如:集合、數(shù)組),獲取一個(gè)流

          • 「2、中間操作」

            一個(gè)中間操作鏈,對(duì)數(shù)據(jù)源的數(shù)據(jù)進(jìn)行處理

          • 「3、終止操作」

            一個(gè)終止操作,執(zhí)行中間操作鏈,并產(chǎn)生結(jié)果。在這之后,該Stream就不能使用了

          4.2、創(chuàng)建Stream

          ?

          「【方式一】:通過(guò)Collection對(duì)象的stream()或parallelStream()方法」

          ?
          ArrayList?arrayList?=?new?ArrayList<>();
          arrayList.add("hello")

          //?創(chuàng)建Stream(單線程)
          Stream?stream?=?arrayList.stream();

          //?創(chuàng)建Stream(并行流,多線程)
          Stream?stream?=?arrayList.parallelStream();

          stream.forEach(Systerm.out::println);
          ?

          「【方式二】:通過(guò)Arrays類(lèi)的stream()方法」

          ?
          String[]?arr?=?{"aaa",?"bbb",?"ccc"};

          //?創(chuàng)建Stream
          Stream?stream?=?Arrays.stream(arr);

          stream.forEach(Systerm.out::println);
          ?

          「【方式三】:通過(guò)Stream接口的of()、iterate()、generate()方法」

          ?
          //?創(chuàng)建Stream(直接把一組數(shù)變?yōu)榱?
          Stream?stream?=?Stream.of(10,?20,?30,?40,?50,?60);

          //?創(chuàng)建Stream(迭代流,iterate(起始值,?操作方法),配合limit限制)
          Stream?stream?=?Stream.iterate(0,?x?->?x+2);

          //?創(chuàng)建Stream(生成流,無(wú)參有返回值)
          Stream?stream?=?Stream.generate(()?->?new?Random().nextInt(100));

          stream.forEach(Systerm.out::println);
          //?stream.limit(10).forEach(Systerm.out::println);
          ?

          「【方式四】:IntStream」

          ?
          //?創(chuàng)建Stream(1,?2,?3)
          IntStream?stream?=?IntStream.of(1,?2,?3);

          //?創(chuàng)建Stream([1,?10))
          IntStream?stream?=?IntStream.range(1,?10)

          //?創(chuàng)建Stream([1,?10])
          IntStream?stream?=?IntStream.rangeClosed(1,?10)

          4.3、中間操作

          //?創(chuàng)建一個(gè)集合用于測(cè)試操作
          List?employees?=?Arrays.asList(
          ????new?Employee("張三",?18,?9999.99,?Status.FREE),
          ????new?Employee("李四",?18,?8999.99,?Status.FREE),
          ????new?Employee("王五",?18,?7999.99,?Status.FREE),
          ????new?Employee("趙六",?18,?6999.99,?Status.BASY),
          ????new?Employee("田七",?18,?5999.99,?Status.BASY)
          );

          4.3.1、篩選與切片

          ?

          「【filter】」:接收l(shuí)ambda,從流中排除某些元素

          ?
          //?filter
          Stream?stream?=?employees.stream().filter(e?->?e.getAge()>18);
          stream.forEach(System.out?::?println);
          ?

          「【limit】」:截?cái)嗔?/p>?

          //?limit
          Stream?stream?=?employees.stream().limit(2);
          stream.forEach(System.out?::?println);
          ?

          「【skip】」:skip(n)類(lèi)似于pandas的iloc[n:]

          ?
          //?skip
          Stream?stream?=?employees.stream().skip(2);
          stream.forEach(System.out?::?println);
          ?

          「【distinct】」:去重(根據(jù)hashcode和equals去重,因此,類(lèi)要重寫(xiě)hashcode和equals方法)

          ?
          //?distinct
          Stream?stream?=?employees.stream().distinct();
          stream.forEach(System.out?::?println);

          4.3.2、映射map

          map和flatmap的區(qū)別就相當(dāng)于python list中append和extend的區(qū)別

          ?

          「【map】」:接收函數(shù),把函數(shù)應(yīng)用在所有元素上(多個(gè)流相互獨(dú)立在一個(gè)大流中)

          ?
          //?將元素轉(zhuǎn)為大寫(xiě)
          List?list?=?Array.aslist("aaa",?"bbb",?"ccc");
          list.stream().map(str)?->?str.toUpperCase().forEach(System.out?::?println);

          //?提取員工名
          employess.stream().map(Employee:getName).forEach(System.out?::?println);
          ?

          「【flatmap】」:接收函數(shù),把函數(shù)應(yīng)用在所有元素上(多個(gè)流合完全混合成一個(gè)大流)

          ?
          List?list?=?Arrays.aslist("aaa",?"bbb",?"ccc");

          //?編寫(xiě)將字符串拆分為字符的方法,返回一個(gè)流
          public?Stream?filterCharacter(String?str){
          ????List?list?=?new?ArrayList<>();
          ????
          ????for?(Character?ch?:?str.toCharArray()){
          ????????list.add(ch)
          ????}
          ????return?list.stream()
          }


          //?【方式1】:使用map的方法使用以上方法
          Stream>?stream?=?list.stream().map(str)?->?filterCharacter(str);?//[['a',?'a',?'a'],?['b',?'b',?'b'],?['c',?'c',?'c']]
          stream.forEach((sm)?->?sm.forEach(System.out?::?println));


          //?【方式1】:使用flatmap的方法使用以上方法
          Stream?stream?=?list.stream().flatmap(str)?->?filterCharacter(str);?//['a',?'a',?'a',?'b',?'b',?'b',?'c',?'c',?'c']
          stream.forEach(System.out?::?println);

          4.3.3、排序sorted

          ?

          【sorted】:排序

          ?
          //?員工自定義定義排序[sorted(無(wú)參)代表默認(rèn)排序]
          employees.stream().sorted(
          ????(e1,?e2)?->?{
          ????????if?(e1.getAge().equals(e2.getAge())){
          ????????????return?e1.getName().compareTo(e2.getName());?//?名字正序
          ????????}else?{
          ????????????return?-e1.getAge().compareTo(e2.getAge());?//?年齡倒序
          ????????}
          ????}
          ).forEach(System.out::println)

          4.4、終止操作

          4.4.1、查找與匹配

          allMatch:檢查是否匹配所有元素

          anyMatch:檢查是否至少匹配一個(gè)元素

          noneMatch:檢查是否沒(méi)有匹配所有元素

          findFirst:返回第一個(gè)元素

          findAny:返回流中任意一個(gè)元素

          count:返回流中元素的總個(gè)數(shù)

          max:返回流中最大值

          min:返回流中最小值

          //?查看員工是不是全是18歲
          Booblean?b?=?employees.stream().allMatch((e)?->?e.getAge().equals(18));

          //?查看工資最高的員工?[Optional避免空指針]
          Optional?op?=?employees.stream()
          ????.max((e1,?e2)?->?Double.compare(e1.getSalary(),?e2.getSalary());
          System.out.println(op.get())
          ????
          //?查出工資為9999.99的隨便一個(gè)員工
          Optional?op?=?employees.stream()
          ????.filter((e)?->?e.getSalary()?==?9999.99)
          ????.findAny();
          System.out.println(op.get())

          4.4.2、規(guī)約

          ?

          reduce():將流中元素反復(fù)結(jié)合起來(lái),得到一個(gè)值

          ?
          //?列表累加
          List?list?=?Arrays.asList(1,?2,?3,?4,?5,?6);
          Integer?sum?=?list.stream()
          ????.reduce(0,?(x,?y)?->?x?+?y);?//?從索引0開(kāi)始,累加
          System.out.println(sum);

          //?所有人工資總和
          Optional?op?=?employees.stream()
          ????.map(Emplyee?::?getSalary)
          ????.reduce(Double?::?sum);
          System.out.println(op.get());

          4.4.3、收集collect

          Collectors實(shí)用類(lèi)提供了很多靜態(tài)方法,可以方便的創(chuàng)建常見(jiàn)收集器實(shí)例

          ?

          將流轉(zhuǎn)為其他格式

          ?
          //?把所有員工名放到列表
          List?li?=?employees.stream()
          ????.map(Employee?::?getName)
          ????.collect(Collectors.toList());

          //?把所有員工名放到HashSet
          HashSet?hs?=?employees.stream()
          ????.map(Employee?::?getName)
          ????.collect(Collectors.toCollection(HashSet::new));
          ?

          分組

          ?
          //?根據(jù)狀態(tài)分組
          Map>?map?=?employees.stream()
          ????.collect(Collectors.groupingBy(Employee?::?getStatus));
          System.out.println(map)
          ????
          //?多級(jí)分組(先根據(jù)狀態(tài)分,再根據(jù)年齡分)
          Map>>?map?=?employees.stream()
          ????.collect(Collectors.groupingBy(Employee?::?getStatus,?Collectors.groupingBy(
          ????????(e)?->?{
          ????????????if?(e.getAge()<18){
          ????????????????return?"未成年";
          ????????????}?else{
          ????????????????return?"成年";
          ????????????}
          ????????}));
          System.out.println(map)
          ?

          分區(qū)

          ?
          Map>?map?=?employees.stream()
          ????.collect(Collectors.partitioningBy((e)?->?e.getSalary()>8000));
          ?

          統(tǒng)計(jì)

          ?
          //?公司總?cè)藬?shù)
          Long?count?=?employees.stream()
          ????.collect(Collectors.counting());

          //?工資平均值
          Double?avg?=?employees.stream()
          ????.collect(Collectors.averagingDouble(Employee?::?getSalary));

          //?工資總和
          Double?sum?=?employees.stream()
          ????.collect(Collectors.summingDouble(Employee?::?getSalary));

          //?最大值
          List?li?=?Arrays.asList(1,?3,?5,?6,?7);
          Optional?max?=?li.stream()
          ????.collect(Collectors.maxBy((n1,?n2)?->?Double.compare(n1,?n2)));
          System.out.println(max.get());

          //?最小值
          List?li?=?Arrays.asList(1,?3,?5,?6,?7);
          Optional?max?=?li.stream()
          ????.collect(Collectors.maxBy((n1,?n2)?->?Double.compare(n1,?n2)));
          System.out.println(max.get());
          DoubleSummaryStatistics?dss?=?employees.stream()
          ????.collect(Collectors.summarizingDouble(Employee::getSalary));
          System.out.println(dss.getSum());?//?求和
          System.out.println(dss.getAverage());?//?求平均數(shù)
          System.out.println(dss.getMax());?//?求最大值
          ?

          連接

          ?
          String?str?=?employees.stream()
          ????.map(Employee::getName)
          ????.collect(Collectors.joining(",",?"===",?"==="));
          //?===張三,李四,王五,趙六,田七===

          4.5、并行流

          ?

          并行流 就是把一個(gè)內(nèi)容分成多個(gè)數(shù)據(jù)塊,并用不同的線程分別處理每個(gè)數(shù)據(jù)塊的流(Fork/Join框架

          java8中Stream API 可以通過(guò)parallel()sequential()在并行流與順序流之間進(jìn)行切換

          ?

          4.5.1、Fork/Join框架

          ?

          更能充分的利用到cpu性能(各個(gè)CPU的利用率基本保持一致)

          【多線程】:某一核上線程阻塞,這樣會(huì)造成多核中有的在阻塞有的在空閑,不能很好利用cpu資源

          【Fork/Join】:使用工作竊取模式,當(dāng)某一核上執(zhí)行完,會(huì)幫助別的核執(zhí)行任務(wù)

          ?
          Fork/Join

          4.5.2、測(cè)試并行流

          ?

          測(cè)試1000億累加

          ?
          • 「循環(huán)累加」
          Instant?start?=?Instant.now();
          long?sum?=?0;
          for?(long?num=0;?num<=100000000000L;?num++){
          ????sum?+=?num;
          }
          Instant?end?=?Instant.now();
          System.out.println("耗時(shí):"?+?Duration.between(start,?end).toMillis());?//?耗時(shí):30827
          • 「Fork/Join并行流」
          Instant?start?=?Instant.now();
          LongStream.rangeClosed(0,?100000000000L).parallel().reduce(0,?Long::sum);
          Instant?end?=?Instant.now();
          System.out.println("耗時(shí):"?+?Duration.between(start,?end).toMillis());//?耗時(shí):27704

          五、新時(shí)間API

          ?

          【Java.time】

          線程安全、使用方便

          ?

          5.1、Java.time

          5.1、日期

          LocalDate?localDate?=?LocalDate.now();
          LocalDate?localDate2?=?LocalDate.of(2015,?12,?31);

          5.2、時(shí)間

          LocalTime?localTime?=?LocalTime.now();
          LocalTime?localTime2?=?LocalTime.of(21,?30,?59,?11001);

          5.3、時(shí)間+日期

          LocalDateTime?localDateTime?=?LocalDateTime.now();
          LocalDateTime?localDateTime2?=?LocalDateTime.of(2015,?11,?30,?23,?45,?59,?1234);
          LocalDateTime?localDateTime3?=?LocalDateTime.of(localDate2,?localTime2);

          5.4、時(shí)間戳

          //毫秒數(shù)時(shí)間戳
          Long?milliSecond?=?LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();?
          //秒數(shù)時(shí)間戳
          Long?second?=?LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));?

          //?時(shí)間戳轉(zhuǎn)時(shí)間字符串
          String?result?=?new?SimpleDateFormat("yyyy-MM-dd?HH:mm:ss").format(milliSecond);

          5.5、字符串轉(zhuǎn)日期格式化

          //?指定格式
          DateTimeFormatter?dtf?=?DateTimeFormatter.ofPattern("yyyy-MM-dd?HH:mm:ss");?
          //?將時(shí)間轉(zhuǎn)化為指定格式字符串
          String?df?=?dtf.format(LocalDateTime.now());?
          //?LocalDateTime格式字符串轉(zhuǎn)LocalDateTime
          LocalDateTime?dt1?=?LocalDateTime.parse("2016-11-30T15:16:17");?
          //?將指定格式字符串轉(zhuǎn)化為L(zhǎng)ocalDateTime
          LocalDateTime?dt2?=?LocalDateTime.parse("2016-11-30?15:16:17",?dtf);?

          5.6、時(shí)間推移

          //?5天后
          LocalDateTime?after5days?=?LocalDateTime.now().plusDays(5);?
          //?5天前
          LocalDateTime?before5days?=?LocalDateTime.now().minusDays(5);?
          ?//?加1月減2周
          LocalDateTime?monthWeek?=?LocalDateTime.now().plusMonths(1).minusWeeks(2);

          5.7、時(shí)間抽取

          //?年份
          Integer?year?=?LocalDate.now().getYear();?
          //?本年第幾天
          Integer?dayOfYear?=?LocalDate.now().getDayOfYear();?
          //?月份
          Integer?month?=?LocalDate.now().getMonthValue();?
          //?幾號(hào)
          Integer?dayOfMonth?=?LocalDate.now().getMonthValue();?
          //?周幾
          Integer?week?=?LocalDate.now().getDayOfWeek().getValue();

          //?獲得本月第1天
          LocalDate?firstDay?=?LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());?
          //?獲得本月最后1天
          LocalDate?lastDay?=?LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());?
          //?本月第1個(gè)星期天
          LocalDate?firstSunday?=?LocalDate.now().with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY));?
          //?判斷那個(gè)日期在前
          Boolean?b?=?firstSunday.isBefore(LocalDate.now());?
          //相距多少年月日
          Period?p?=?LocalDate.now().until(LocalDate.of(2050,?1,?1));?
          //相距多少天
          Long?d?=?LocalDate.of(2050,?1,?1).toEpochDay()?-?LocalDate.now().toEpochDay();?

          5.8、時(shí)區(qū)

          //?獲取當(dāng)前默認(rèn)時(shí)區(qū)的日期和時(shí)間
          ZonedDateTime?now?=?ZonedDateTime.now();?
          //?獲得時(shí)區(qū)(Asia/Shanghai)
          now.getZone();?
          //?時(shí)區(qū)為0的時(shí)間
          Instant?ins?=?now.toInstant();?
          //?指定時(shí)區(qū)的時(shí)間
          ZonedDateTime?london?=?ZonedDateTime.now(ZoneId.of("Europe/London"));?
          //把倫敦時(shí)間轉(zhuǎn)換到紐約時(shí)間
          ZonedDateTime?newYork?=?london.withZoneSameInstant(ZoneId.of("America/New_York"));?

          5.9、Date與LocalDateTime互轉(zhuǎn)

          //?Date轉(zhuǎn)LocalDateTime
          LocalDateTime?localDateTime?=?date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime()

          //?LocalDateTime轉(zhuǎn)Date
          Date?date?=?Date.from(localDateTime.toInstant(ZoneOffset.of("+8")))

          六、Optional容器類(lèi)

          ?

          使用Optional后,如果空指針一定是創(chuàng)建Optional實(shí)例時(shí)出現(xiàn)的,更容易定位

          Optional類(lèi)(java.util.Optional)是一個(gè)容器類(lèi),代表一個(gè)值存在或不存在,原來(lái)用null表示一個(gè)值不存在,現(xiàn)在Optional可以更好的表達(dá)這個(gè)概念。并且可以避免空指針異常。

          ?
          • 「常用方法」
          「函數(shù)」「描述」
          Optional.of(T t)創(chuàng)建一個(gè) Optional 實(shí)例
          Optional.empty()創(chuàng)建一個(gè)空的 Optional 實(shí)例
          Optional.ofNullable(T t)若 t 不為 null,創(chuàng)建 Optional 實(shí)例,否則創(chuàng)建空實(shí)例
          isPresent()判斷是否包含值
          orElse(T t)如果調(diào)用對(duì)象包含值,返回該值,否則返回t
          orElseGet(Supplier s)如果調(diào)用對(duì)象包含值,返回該值,否則返回 s 獲取的值
          map(Function f)如果有值對(duì)其處理,并返回處理后的Optional,否則返回 Optional.empty()
          flatMap(Function mapper)與 map 類(lèi)似,要求返回值必須是Optional

          七、接口中的默認(rèn)方法與靜態(tài)方法

          ?

          在java8中允許有實(shí)現(xiàn)的靜態(tài)方法和默認(rèn)方法

          ?
          • 「"類(lèi)優(yōu)先"原則」
            • 接口和父類(lèi)沖突,使用父類(lèi)的方法。(一個(gè)類(lèi)繼承的父類(lèi)和接口實(shí)現(xiàn)了同名的方法,父類(lèi)的會(huì)生效)
            • 接口沖突,需要指定。(一個(gè)類(lèi)實(shí)現(xiàn)兩個(gè)接口,兩個(gè)接口有同名的實(shí)現(xiàn)方法,需要使用接口名.supper.方法名,指定使用哪個(gè))
          • 「示例」
          public?interface?MyInterface?{
          ????//?允許有實(shí)現(xiàn)的默認(rèn)方法
          ????default?String?getName(){
          ????????return?"接口中的默認(rèn)方法";
          ????}
          ????//?允許有實(shí)現(xiàn)的靜態(tài)方法
          ????public?static?String?show(){
          ????????return?"接口中的靜態(tài)方法";
          ????}
          }

          八、重復(fù)注解與類(lèi)型注解

          8.1、重復(fù)注解

          ?

          java8支持方法使用重復(fù)注解(同一個(gè)注解使用兩次)

          新的反射API提供了getAnnotationsByType()方法,獲得該注解所有的值

          ?
          • 「定義注解容器類(lèi)」

            要想定義重復(fù)注解,必須要先定義一個(gè)該注解的容器

          @Target({ElementType.TYPE,?ElementType.METHOD})
          @Retention(RetentionPolicy.RUNTIME)
          @interface?MyAnnotations{
          ????MyAnnotation[]?value();
          }
          • 「自定義一個(gè)注解」

            要用@Repeatable修飾,并指定容器類(lèi)

          //?要用@Repeatable修飾,并指定容器類(lèi)
          @Repeatable(MyAnnotations.class)
          //?表示注解的適用范圍(TYPE:類(lèi),?METHOD:方法)
          @Target(
          {ElementType.TYPE,?ElementType.METHOD})
          @Retention(RetentionPolicy.RUNTIME)
          @interface?MyAnnotation{
          ????//?注解的參數(shù):類(lèi)型?參數(shù)名
          ????int?time()?default?1000;
          }
          • 「重復(fù)注解」
          public?class?TestAnnotation?{
          ????@MyAnnotation(100)
          ????@MyAnnotation(200)
          ????public?void?show(){
          ????}
          }
          • 「使用反射的getAnnotationsByType()獲取所有值」
          Class?clazz?=?TestAnnotation.class;
          Method?m1?=?clazz.getMethod("show");
          MyAnnotation[]?mas?=?m1.getAnnotationsByType(MyAnnotation.class);
          for?(MyAnnotation?myAnnotation?:?mas){
          ????System.out.println(myAnnotation.value());?//?100、200
          }

          8.2、類(lèi)型注解

          ?

          注解的@Target可以使用TYPE_PARAMETER,可以用注解給參數(shù)賦默認(rèn)值

          類(lèi)似于@RequestParam,@RequestParam使用的是PARAMETER,給形參設(shè)置默認(rèn)值

          ?
          @MyAnnotation(100)
          public?void?show(@MyAnnotation(111)?Integer?num){
          }

          8.3、@NonNull注解

          ?

          提供@NonNull注解,如果運(yùn)行時(shí)加了該注解的值是null則運(yùn)行時(shí)則會(huì)報(bào)錯(cuò)(運(yùn)行時(shí)異常)

          但是在java8中并沒(méi)有內(nèi)置,不可以直接使用,可以配合框架使用,不如SpringBoot中可以使用

          ?

          // obj如果為null,運(yùn)行時(shí)會(huì)報(bào)錯(cuò) private @NonNull Object obj;

          瀏覽 96
          點(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>
                  青青操日日干 | 牛牛影视一区二区 | 欧美18禁黄免费网站 | 国产一呦二呦三呦 | 影音先锋女人av鲁色资源网小说 |