日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JDK1.8 新特性(全)

發布時間:2025/3/12 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JDK1.8 新特性(全) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JDK1.8 新特性

本文主要介紹了JDK1.8版本中的一些新特性,乃作者視頻觀后筆記,僅供參考。

jdk1.8新特性知識點:

  • Lambda表達式
  • 函數式接口
  • 方法引用和構造器調用
  • Stream API
  • 接口中的默認方法和靜態方法
  • 新時間日期API

在jdk1.8中對hashMap等map集合的數據結構優化。hashMap數據結構的優化
原來的hashMap采用的數據結構是哈希表(數組+鏈表),hashMap默認大小是16,一個0-15索引的數組,如何往里面存儲元素,首先調用元素的hashcode
方法,計算出哈希碼值,經過哈希算法算成數組的索引值,如果對應的索引處沒有元素,直接存放,如果有對象在,那么比較它們的equals方法比較內容
如果內容一樣,后一個value會將前一個value的值覆蓋,如果不一樣,在1.7的時候,后加的放在前面,形成一個鏈表,形成了碰撞,在某些情況下如果鏈表
無限下去,那么效率極低,碰撞是避免不了的
加載因子:0.75,數組擴容,達到總容量的75%,就進行擴容,但是無法避免碰撞的情況發生
在1.8之后,在數組+鏈表+紅黑樹來實現hashmap,當碰撞的元素個數大于8時 & 總容量大于64,會有紅黑樹的引入
除了添加之后,效率都比鏈表高,1.8之后鏈表新進元素加到末尾
ConcurrentHashMap (鎖分段機制),concurrentLevel,jdk1.8采用CAS算法(無鎖算法,不再使用鎖分段),數組+鏈表中也引入了紅黑樹的使用

Lambda表達式

lambda表達式本質上是一段匿名內部類,也可以是一段可以傳遞的代碼

先來體驗一下lambda最直觀的優點:簡潔代碼

//匿名內部類Comparator<Integer> cpt = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return Integer.compare(o1,o2);}};TreeSet<Integer> set = new TreeSet<>(cpt);System.out.println("=========================");//使用lambda表達式Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y);TreeSet<Integer> set2 = new TreeSet<>(cpt2);123456789101112131415

只需要一行代碼,極大減少代碼量!!

這樣一個場景,在商城瀏覽商品信息時,經常會有條件的進行篩選瀏覽,例如要選顏色為紅色的、價格小于8000千的….

// 篩選顏色為紅色 public List<Product> filterProductByColor(List<Product> list){List<Product> prods = new ArrayList<>();for (Product product : list){if ("紅色".equals(product.getColor())){prods.add(product);}}return prods;}// 篩選價格小于8千的 public List<Product> filterProductByPrice(List<Product> list){List<Product> prods = new ArrayList<>();for (Product product : list){if (product.getPrice() < 8000){prods.add(product);}}return prods;}123456789101112131415161718192021

我們發現實際上這些過濾方法的核心就只有if語句中的條件判斷,其他均為模版代碼,每次變更一下需求,都需要新增一個方法,然后復制黏貼,假設這個過濾方法有幾百行,那么這樣的做法難免笨拙了一點。如何進行優化呢?

優化一:使用設計模式

定義一個MyPredicate接口

public interface MyPredicate <T> {boolean test(T t); }123

如果想要篩選顏色為紅色的商品,定義一個顏色過濾類

public class ColorPredicate implements MyPredicate <Product> {private static final String RED = "紅色";@Overridepublic boolean test(Product product) {return RED.equals(product.getColor());}12345678

定義過濾方法,將過濾接口當做參數傳入,這樣這個過濾方法就不用修改,在實際調用的時候將具體的實現類傳入即可。

public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){List<Product> prods = new ArrayList<>();for (Product prod : list){if (mp.test(prod)){prods.add(prod);}}return prods;}123456789

例如,如果想要篩選價格小于8000的商品,那么新建一個價格過濾類既可

public class PricePredicate implements MyPredicate<Product> {@Overridepublic boolean test(Product product) {return product.getPrice() < 8000;} }123456

這樣實現的話可能有人會說,每次變更需求都需要新建一個實現類,感覺還是有點繁瑣呀,那么再來優化一下

優化二:使用匿名內部類

定義過濾方法:

public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){List<Product> prods = new ArrayList<>();for (Product prod : list){if (mp.test(prod)){prods.add(prod);}}return prods;}123456789

調用過濾方法的時候:

// 按價格過濾 public void test2(){filterProductByPredicate(proList, new MyPredicate<Product>() {@Overridepublic boolean test(Product product) {return product.getPrice() < 8000;}}); }// 按顏色過濾public void test3(){filterProductByPredicate(proList, new MyPredicate<Product>() {@Overridepublic boolean test(Product product) {return "紅色".equals(product.getColor());}});}12345678910111213141516171819

使用匿名內部類,就不需要每次都新建一個實現類,直接在方法內部實現。看到匿名內部類,不禁想起了Lambda表達式。

優化三:使用lambda表達式

定義過濾方法:

public List<Product> filterProductByPredicate(List<Product> list,MyPredicate<Product> mp){List<Product> prods = new ArrayList<>();for (Product prod : list){if (mp.test(prod)){prods.add(prod);}}return prods;}123456789

使用lambda表達式進行過濾

@Test public void test4(){List<Product> products = filterProductByPredicate(proList, (p) -> p.getPrice() < 8000);for (Product pro : products){System.out.println(pro);}}1234567

在jdk1.8中還有更加簡便的操作 Stream API

優化四:使用Stream API

甚至不用定義過濾方法,直接在集合上進行操作

// 使用jdk1.8中的Stream API進行集合的操作 @Test public void test(){// 根據價格過濾proList.stream().fliter((p) -> p.getPrice() <8000).limit(2).forEach(System.out::println);// 根據顏色過濾proList.stream().fliter((p) -> "紅色".equals(p.getColor())).forEach(System.out::println);// 遍歷輸出商品名稱proList.stream().map(Product::getName).forEach(System.out::println); }12345678910111213141516171819

Lmabda表達式的語法總結: () -> ();

前置語法
無參數無返回值() -> System.out.println(“Hello WOrld”)
有一個參數無返回值(x) -> System.out.println(x)
有且只有一個參數無返回值x -> System.out.println(x)
有多個參數,有返回值,有多條lambda體語句(x,y) -> {System.out.println(“xxx”);return xxxx;};
有多個參數,有返回值,只有一條lambda體語句(x,y) -> xxxx

口訣:左右遇一省括號,左側推斷類型省

注:當一個接口中存在多個抽象方法時,如果使用lambda表達式,并不能智能匹配對應的抽象方法,因此引入了函數式接口的概念

函數式接口

函數式接口的提出是為了給Lambda表達式的使用提供更好的支持。

什么是函數式接口?
簡單來說就是只定義了一個抽象方法的接口(Object類的public方法除外),就是函數式接口,并且還提供了注解:@FunctionalInterface

常見的四大函數式接口

  • Consumer 《T》:消費型接口,有參無返回值
@Testpublic void test(){changeStr("hello",(str) -> System.out.println(str));}/*** Consumer<T> 消費型接口* @param str* @param con*/public void changeStr(String str, Consumer<String> con){con.accept(str);}12345678910111213
  • Supplier 《T》:供給型接口,無參有返回值
@Testpublic void test2(){String value = getValue(() -> "hello");System.out.println(value);}/*** Supplier<T> 供給型接口* @param sup* @return*/public String getValue(Supplier<String> sup){return sup.get();}1234567891011121314
  • Function 《T,R》::函數式接口,有參有返回值
@Testpublic void test3(){Long result = changeNum(100L, (x) -> x + 200L);System.out.println(result);}/*** Function<T,R> 函數式接口* @param num* @param fun* @return*/public Long changeNum(Long num, Function<Long, Long> fun){return fun.apply(num);}123456789101112131415
  • Predicate《T》: 斷言型接口,有參有返回值,返回值是boolean類型
public void test4(){boolean result = changeBoolean("hello", (str) -> str.length() > 5);System.out.println(result);}/*** Predicate<T> 斷言型接口* @param str* @param pre* @return*/public boolean changeBoolean(String str, Predicate<String> pre){return pre.test(str);}1234567891011121314

在四大核心函數式接口基礎上,還提供了諸如BiFunction、BinaryOperation、toIntFunction等擴展的函數式接口,都是在這四種函數式接口上擴展而來的,不做贅述。

總結:函數式接口的提出是為了讓我們更加方便的使用lambda表達式,不需要自己再手動創建一個函數式接口,直接拿來用就好了,貼

方法引用

若lambda體中的內容有方法已經實現了,那么可以使用“方法引用”
也可以理解為方法引用是lambda表達式的另外一種表現形式并且其語法比lambda表達式更加簡單

(a) 方法引用
三種表現形式:
\1. 對象::實例方法名
\2. 類::靜態方法名
\3. 類::實例方法名 (lambda參數列表中第一個參數是實例方法的調用 者,第二個參數是實例方法的參數時可用)

public void test() {/***注意:* 1.lambda體中調用方法的參數列表與返回值類型,要與函數式接口中抽象方法的函數列表和返回值類型保持一致!* 2.若lambda參數列表中的第一個參數是實例方法的調用者,而第二個參數是實例方法的參數時,可以使用ClassName::method**/Consumer<Integer> con = (x) -> System.out.println(x);con.accept(100);// 方法引用-對象::實例方法Consumer<Integer> con2 = System.out::println;con2.accept(200);// 方法引用-類名::靜態方法名BiFunction<Integer, Integer, Integer> biFun = (x, y) -> Integer.compare(x, y);BiFunction<Integer, Integer, Integer> biFun2 = Integer::compare;Integer result = biFun2.apply(100, 200);// 方法引用-類名::實例方法名BiFunction<String, String, Boolean> fun1 = (str1, str2) -> str1.equals(str2);BiFunction<String, String, Boolean> fun2 = String::equals;Boolean result2 = fun2.apply("hello", "world");System.out.println(result2);}12345678910111213141516171819202122232425

(b)構造器引用
格式:ClassName::new

public void test2() {// 構造方法引用 類名::newSupplier<Employee> sup = () -> new Employee();System.out.println(sup.get());Supplier<Employee> sup2 = Employee::new;System.out.println(sup2.get());// 構造方法引用 類名::new (帶一個參數)Function<Integer, Employee> fun = (x) -> new Employee(x);Function<Integer, Employee> fun2 = Employee::new;System.out.println(fun2.apply(100));}12345678910111213

?數組引用

格式:Type[]::new

public void test(){// 數組引用Function<Integer, String[]> fun = (x) -> new String[x];Function<Integer, String[]> fun2 = String[]::new;String[] strArray = fun2.apply(10);Arrays.stream(strArray).forEach(System.out::println); }1234567

Stream API

Stream操作的三個步驟

  • 創建stream
  • 中間操作(過濾、map)
  • 終止操作

stream的創建:

// 1,校驗通過Collection 系列集合提供的stream()或者paralleStream()List<String> list = new ArrayList<>();Strean<String> stream1 = list.stream();// 2.通過Arrays的靜態方法stream()獲取數組流String[] str = new String[10];Stream<String> stream2 = Arrays.stream(str);// 3.通過Stream類中的靜態方法ofStream<String> stream3 = Stream.of("aa","bb","cc");// 4.創建無限流// 迭代Stream<Integer> stream4 = Stream.iterate(0,(x) -> x+2);//生成Stream.generate(() ->Math.random());1234567891011121314151617

Stream的中間操作:

/*** 篩選 過濾 去重*/emps.stream().filter(e -> e.getAge() > 10).limit(4).skip(4)// 需要流中的元素重寫hashCode和equals方法.distinct().forEach(System.out::println);/*** 生成新的流 通過map映射*/emps.stream().map((e) -> e.getAge()).forEach(System.out::println);/*** 自然排序 定制排序*/emps.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); 123456789101112131415161718192021222324252627282930313233

Stream的終止操作:

/*** 查找和匹配* allMatch-檢查是否匹配所有元素* anyMatch-檢查是否至少匹配一個元素* noneMatch-檢查是否沒有匹配所有元素* findFirst-返回第一個元素* findAny-返回當前流中的任意元素* count-返回流中元素的總個數* max-返回流中最大值* min-返回流中最小值*//*** 檢查是否匹配元素*/boolean b1 = emps.stream().allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));System.out.println(b1);boolean b2 = emps.stream().anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));System.out.println(b2);boolean b3 = emps.stream().noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));System.out.println(b3);Optional<Employee> opt = emps.stream().findFirst();System.out.println(opt.get());// 并行流Optional<Employee> opt2 = emps.parallelStream().findAny();System.out.println(opt2.get());long count = emps.stream().count();System.out.println(count);Optional<Employee> max = emps.stream().max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));System.out.println(max.get());Optional<Employee> min = emps.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));System.out.println(min.get());1234567891011121314151617181920212223242526272829303132333435363738394041424344454647

還有功能比較強大的兩個終止操作 reduce和collect
reduce操作: reduce:(T identity,BinaryOperator)/reduce(BinaryOperator)-可以將流中元素反復結合起來,得到一個值

/*** reduce :規約操作*/List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);Integer count2 = list.stream().reduce(0, (x, y) -> x + y);System.out.println(count2);Optional<Double> sum = emps.stream().map(Employee::getSalary).reduce(Double::sum);System.out.println(sum); 12345678910111213

collect操作:Collect-將流轉換為其他形式,接收一個Collection接口的實現,用于給Stream中元素做匯總的方法

/*** collect:收集操作*/List<Integer> ageList = emps.stream().map(Employee::getAge).collect(Collectors.toList());ageList.stream().forEach(System.out::println);12345678

并行流和串行流

在jdk1.8新的stream包中針對集合的操作也提供了并行操作流和串行操作流。并行流就是把內容切割成多個數據塊,并且使用多個線程分別處理每個數據塊的內容。Stream api中聲明可以通過parallel()與sequential()方法在并行流和串行流之間進行切換。
jdk1.8并行流使用的是fork/join框架進行并行操作

ForkJoin框架

Fork/Join 框架:就是在必要的情況下,將一個大任務,進行拆分(fork)成若干個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進行 join 匯總。
關鍵字:遞歸分合、分而治之。
采用 “工作竊取”模式(work-stealing):
當執行新的任務時它可以將其拆分分成更小的任務執行,并將小任務加到線
程隊列中,然后再從一個隨機線程的隊列中偷一個并把它放在自己的隊列中
相對于一般的線程池實現,fork/join框架的優勢體現在對其中包含的任務的
處理方式上.在一般的線程池中,如果一個線程正在執行的任務由于某些原因
無法繼續運行,那么該線程會處于等待狀態.而在fork/join框架實現中,如果
某個子問題由于等待另外一個子問題的完成而無法繼續運行.那么處理該子
問題的線程會主動尋找其他尚未運行的子問題來執行.這種方式減少了線程
的等待時間,提高了性能.。

/*** 要想使用Fark—Join,類必須繼承* RecursiveAction(無返回值)* Or* RecursiveTask(有返回值) * */ public class ForkJoin extends RecursiveTask<Long> {/*** 要想使用Fark—Join,類必須繼承RecursiveAction(無返回值) 或者* RecursiveTask(有返回值)** @author Wuyouxin*/private static final long serialVersionUID = 23423422L;private long start;private long end;public ForkJoin() {}public ForkJoin(long start, long end) {this.start = start;this.end = end;}// 定義闕值private static final long THRESHOLD = 10000L;@Overrideprotected Long compute() {if (end - start <= THRESHOLD) {long sum = 0;for (long i = start; i < end; i++) {sum += i;}return sum;} else {long middle = (end - start) / 2;ForkJoin left = new ForkJoin(start, middle);//拆分子任務,壓入線程隊列left.fork();ForkJoin right = new ForkJoin(middle + 1, end);right.fork();//合并并返回return left.join() + right.join();}}/*** 實現數的累加*/@Testpublic void test1() {//開始時間Instant start = Instant.now();//這里需要一個線程池的支持ForkJoinPool pool = new ForkJoinPool();ForkJoinTask<Long> task = new ForkJoin(0L, 10000000000L);// 沒有返回值 pool.execute();// 有返回值long sum = pool.invoke(task);//結束時間Instant end = Instant.now();System.out.println(Duration.between(start, end).getSeconds());}/*** java8 并行流 parallel()*/@Testpublic void test2() {//開始時間Instant start = Instant.now();// 并行流計算 累加求和LongStream.rangeClosed(0, 10000000000L).parallel().reduce(0, Long :: sum);//結束時間Instant end = Instant.now();System.out.println(Duration.between(start, end).getSeconds());}@Testpublic void test3(){List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);list.stream().forEach(System.out::print);list.parallelStream().forEach(System.out::print);}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798

展示多線程的效果:

@Testpublic void test(){// 并行流 多個線程執行List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);numbers.parallelStream().forEach(System.out::print);//System.out.println("=========================");numbers.stream().sequential().forEach(System.out::print);}12345678910111213

Optional容器

使用Optional容器可以快速的定位NPE,并且在一定程度上可以減少對參數非空檢驗的代碼量。 1 /*** Optional.of(T t); // 創建一個Optional實例* Optional.empty(); // 創建一個空的Optional實例* Optional.ofNullable(T t); // 若T不為null,創建一個Optional實例,否則創建一個空實例* isPresent(); // 判斷是夠包含值* orElse(T t); //如果調用對象包含值,返回該值,否則返回T* orElseGet(Supplier s); // 如果調用對象包含值,返回該值,否則返回s中獲取的值* map(Function f): // 如果有值對其處理,并返回處理后的Optional,否則返回Optional.empty();* flatMap(Function mapper);// 與map類似。返回值是Optional** 總結:Optional.of(null) 會直接報NPE*/Optional<Employee> op = Optional.of(new Employee("zhansan", 11, 12.32, Employee.Status.BUSY));System.out.println(op.get());// NPEOptional<Employee> op2 = Optional.of(null);System.out.println(op2); @Testpublic void test2(){Optional<Object> op = Optional.empty();System.out.println(op);// No value presentSystem.out.println(op.get());} @Testpublic void test3(){Optional<Employee> op = Optional.ofNullable(new Employee("lisi", 33, 131.42, Employee.Status.FREE));System.out.println(op.get());Optional<Object> op2 = Optional.ofNullable(null);System.out.println(op2);// System.out.println(op2.get());}@Testpublic void test5(){Optional<Employee> op1 = Optional.ofNullable(new Employee("張三", 11, 11.33, Employee.Status.VOCATION));System.out.println(op1.orElse(new Employee()));System.out.println(op1.orElse(null));}@Testpublic void test6(){Optional<Employee> op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));op1 = Optional.empty();Employee employee = op1.orElseGet(() -> new Employee());System.out.println(employee);}@Testpublic void test7(){Optional<Employee> op1 = Optional.of(new Employee("田七", 11, 12.31, Employee.Status.BUSY));System.out.println(op1.map( (e) -> e.getSalary()).get());}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

接口中可以定義默認實現方法和靜態方法

在接口中可以使用default和static關鍵字來修飾接口中定義的普通方法

public interface Interface {default String getName(){return "zhangsan";}static String getName2(){return "zhangsan";} } 12345678910

在JDK1.8中很多接口會新增方法,為了保證1.8向下兼容,1.7版本中的接口實現類不用每個都重新實現新添加的接口方法,引入了default默認實現,static的用法是直接用接口名去調方法即可。當一個類繼承父類又實現接口時,若后兩者方法名相同,則優先繼承父類中的同名方法,即“類優先”,如果實現兩個同名方法的接口,則要求實現類必須手動聲明默認實現哪個接口中的方法。

新的日期API LocalDate | LocalTime | LocalDateTime

新的日期API都是不可變的,更使用于多線程的使用環境中

@Testpublic void test(){// 從默認時區的系統時鐘獲取當前的日期時間。不用考慮時區差LocalDateTime date = LocalDateTime.now();//2018-07-15T14:22:39.759System.out.println(date);System.out.println(date.getYear());System.out.println(date.getMonthValue());System.out.println(date.getDayOfMonth());System.out.println(date.getHour());System.out.println(date.getMinute());System.out.println(date.getSecond());System.out.println(date.getNano());// 手動創建一個LocalDateTime實例LocalDateTime date2 = LocalDateTime.of(2017, 12, 17, 9, 31, 31, 31);System.out.println(date2);// 進行加操作,得到新的日期實例LocalDateTime date3 = date2.plusDays(12);System.out.println(date3);// 進行減操作,得到新的日期實例LocalDateTime date4 = date3.minusYears(2);System.out.println(date4);} 1234567891011121314151617181920212223242526@Testpublic void test2(){// 時間戳 1970年1月1日00:00:00 到某一個時間點的毫秒值// 默認獲取UTC時區Instant ins = Instant.now();System.out.println(ins);System.out.println(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());System.out.println(System.currentTimeMillis());System.out.println(Instant.now().toEpochMilli());System.out.println(Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant().toEpochMilli());}12345678910111213@Testpublic void test3(){// Duration:計算兩個時間之間的間隔// Period:計算兩個日期之間的間隔Instant ins1 = Instant.now();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}Instant ins2 = Instant.now();Duration dura = Duration.between(ins1, ins2);System.out.println(dura);System.out.println(dura.toMillis());System.out.println("======================");LocalTime localTime = LocalTime.now();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}LocalTime localTime2 = LocalTime.now();Duration du2 = Duration.between(localTime, localTime2);System.out.println(du2);System.out.println(du2.toMillis());}1234567891011121314151617181920212223242526272829 @Testpublic void test4(){LocalDate localDate =LocalDate.now();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}LocalDate localDate2 = LocalDate.of(2016,12,12);Period pe = Period.between(localDate, localDate2);System.out.println(pe);}1234567891011121314@Testpublic void test5(){// temperalAdjust 時間校驗器// 例如獲取下周日 下一個工作日LocalDateTime ldt1 = LocalDateTime.now();System.out.println(ldt1);// 獲取一年中的第一天LocalDateTime ldt2 = ldt1.withDayOfYear(1);System.out.println(ldt2);// 獲取一個月中的第一天LocalDateTime ldt3 = ldt1.withDayOfMonth(1);System.out.println(ldt3);LocalDateTime ldt4 = ldt1.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));System.out.println(ldt4);// 獲取下一個工作日LocalDateTime ldt5 = ldt1.with((t) -> {LocalDateTime ldt6 = (LocalDateTime)t;DayOfWeek dayOfWeek = ldt6.getDayOfWeek();if (DayOfWeek.FRIDAY.equals(dayOfWeek)){return ldt6.plusDays(3);}else if (DayOfWeek.SATURDAY.equals(dayOfWeek)){return ldt6.plusDays(2);}else {return ldt6.plusDays(1);}});System.out.println(ldt5);}123456789101112131415161718192021222324252627282930313233@Testpublic void test6(){// DateTimeFormatter: 格式化時間/日期// 自定義格式LocalDateTime ldt = LocalDateTime.now();DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");String strDate1 = ldt.format(formatter);String strDate = formatter.format(ldt);System.out.println(strDate);System.out.println(strDate1);// 使用api提供的格式DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;LocalDateTime ldt2 = LocalDateTime.now();String strDate3 = dtf.format(ldt2);System.out.println(strDate3);// 解析字符串to時間DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime time = LocalDateTime.now();String localTime = df.format(time);LocalDateTime ldt4 = LocalDateTime.parse("2017-09-28 17:07:05",df);System.out.println("LocalDateTime轉成String類型的時間:"+localTime);System.out.println("String類型的時間轉成LocalDateTime:"+ldt4);}12345678910111213141516171819202122232425// ZoneTime ZoneDate ZoneDateTime@Testpublic void test7(){LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));System.out.println(now);LocalDateTime now2 = LocalDateTime.now();ZonedDateTime zdt = now2.atZone(ZoneId.of("Asia/Shanghai"));System.out.println(zdt);Set<String> set = ZoneId.getAvailableZoneIds();set.stream().forEach(System.out::println);}12345678910111213

補充:

表示日期的LocalDate
表示時間的LocalTime
表示日期時間的LocalDateTime

新的日期API的幾個優點:

* 之前使用的java.util.Date月份從0開始,我們一般會+1使用,很不方便,java.time.LocalDate月份和星期都改成了enum* java.util.Date和SimpleDateFormat都不是線程安全的,而LocalDate和LocalTime和最基本的String一樣,是不變類型,不但線程安全,而且不能修改。* java.util.Date是一個“萬能接口”,它包含日期、時間,還有毫秒數,更加明確需求取舍* 新接口更好用的原因是考慮到了日期時間的操作,經常發生往前推或往后推幾天的情況。用java.util.Date配合Calendar要寫好多代碼,而且一般的開發人員還不一定能寫對。 1234
  • LocalDate
public static void localDateTest() {//獲取當前日期,只含年月日 固定格式 yyyy-MM-dd 2018-05-04LocalDate today = LocalDate.now();// 根據年月日取日期,5月就是5,LocalDate oldDate = LocalDate.of(2018, 5, 1);// 根據字符串取:默認格式yyyy-MM-dd,02不能寫成2LocalDate yesteday = LocalDate.parse("2018-05-03");// 如果不是閏年 傳入29號也會報錯LocalDate.parse("2018-02-29");}1234567891011121314
  • LocalDate常用轉化
/*** 日期轉換常用,第一天或者最后一天...*/public static void localDateTransferTest(){//2018-05-04LocalDate today = LocalDate.now();// 取本月第1天: 2018-05-01LocalDate firstDayOfThisMonth = today.with(TemporalAdjusters.firstDayOfMonth());// 取本月第2天:2018-05-02LocalDate secondDayOfThisMonth = today.withDayOfMonth(2);// 取本月最后一天,再也不用計算是28,29,30還是31: 2018-05-31LocalDate lastDayOfThisMonth = today.with(TemporalAdjusters.lastDayOfMonth());// 取下一天:2018-06-01LocalDate firstDayOf2015 = lastDayOfThisMonth.plusDays(1);// 取2018年10月第一個周三 so easy?: 2018-10-03LocalDate thirdMondayOf2018 = LocalDate.parse("2018-10-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.WEDNESDAY));}1234567891011121314151617
  • LocalTime
public static void localTimeTest(){//16:25:46.448(納秒值)LocalTime todayTimeWithMillisTime = LocalTime.now();//16:28:48 不帶納秒值LocalTime todayTimeWithNoMillisTime = LocalTime.now().withNano(0);LocalTime time1 = LocalTime.parse("23:59:59");}1234567
  • LocalDateTime
public static void localDateTimeTest(){//轉化為時間戳 毫秒值long time1 = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();long time2 = System.currentTimeMillis();//時間戳轉化為localdatetimeDateTimeFormatter df= DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss.SSS");System.out.println(df.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time1),ZoneId.of("Asia/Shanghai"))));}12345678910 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的JDK1.8 新特性(全)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。