JDK1.8 新特性(全)
JDK1.8 新特性
本文主要介紹了JDK1.8版本中的一些新特性,乃作者視頻觀后筆記,僅供參考。
jdk1.8新特性知識(shí)點(diǎn):
- Lambda表達(dá)式
- 函數(shù)式接口
- 方法引用和構(gòu)造器調(diào)用
- Stream API
- 接口中的默認(rèn)方法和靜態(tài)方法
- 新時(shí)間日期API
在jdk1.8中對(duì)hashMap等map集合的數(shù)據(jù)結(jié)構(gòu)優(yōu)化。hashMap數(shù)據(jù)結(jié)構(gòu)的優(yōu)化
原來(lái)的hashMap采用的數(shù)據(jù)結(jié)構(gòu)是哈希表(數(shù)組+鏈表),hashMap默認(rèn)大小是16,一個(gè)0-15索引的數(shù)組,如何往里面存儲(chǔ)元素,首先調(diào)用元素的hashcode
方法,計(jì)算出哈希碼值,經(jīng)過哈希算法算成數(shù)組的索引值,如果對(duì)應(yīng)的索引處沒有元素,直接存放,如果有對(duì)象在,那么比較它們的equals方法比較內(nèi)容
如果內(nèi)容一樣,后一個(gè)value會(huì)將前一個(gè)value的值覆蓋,如果不一樣,在1.7的時(shí)候,后加的放在前面,形成一個(gè)鏈表,形成了碰撞,在某些情況下如果鏈表
無(wú)限下去,那么效率極低,碰撞是避免不了的
加載因子:0.75,數(shù)組擴(kuò)容,達(dá)到總?cè)萘康?5%,就進(jìn)行擴(kuò)容,但是無(wú)法避免碰撞的情況發(fā)生
在1.8之后,在數(shù)組+鏈表+紅黑樹來(lái)實(shí)現(xiàn)hashmap,當(dāng)碰撞的元素個(gè)數(shù)大于8時(shí) & 總?cè)萘看笥?4,會(huì)有紅黑樹的引入
除了添加之后,效率都比鏈表高,1.8之后鏈表新進(jìn)元素加到末尾
ConcurrentHashMap (鎖分段機(jī)制),concurrentLevel,jdk1.8采用CAS算法(無(wú)鎖算法,不再使用鎖分段),數(shù)組+鏈表中也引入了紅黑樹的使用
Lambda表達(dá)式
lambda表達(dá)式本質(zhì)上是一段匿名內(nèi)部類,也可以是一段可以傳遞的代碼
先來(lái)體驗(yàn)一下lambda最直觀的優(yōu)點(diǎn):簡(jiǎn)潔代碼
//匿名內(nèi)部類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表達(dá)式Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y);TreeSet<Integer> set2 = new TreeSet<>(cpt2);123456789101112131415只需要一行代碼,極大減少代碼量!!
這樣一個(gè)場(chǎng)景,在商城瀏覽商品信息時(shí),經(jīng)常會(huì)有條件的進(jìn)行篩選瀏覽,例如要選顏色為紅色的、價(jià)格小于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;}// 篩選價(jià)格小于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我們發(fā)現(xiàn)實(shí)際上這些過濾方法的核心就只有if語(yǔ)句中的條件判斷,其他均為模版代碼,每次變更一下需求,都需要新增一個(gè)方法,然后復(fù)制黏貼,假設(shè)這個(gè)過濾方法有幾百行,那么這樣的做法難免笨拙了一點(diǎn)。如何進(jìn)行優(yōu)化呢?
優(yōu)化一:使用設(shè)計(jì)模式
定義一個(gè)MyPredicate接口
public interface MyPredicate <T> {boolean test(T t); }123如果想要篩選顏色為紅色的商品,定義一個(gè)顏色過濾類
public class ColorPredicate implements MyPredicate <Product> {private static final String RED = "紅色";@Overridepublic boolean test(Product product) {return RED.equals(product.getColor());}12345678定義過濾方法,將過濾接口當(dāng)做參數(shù)傳入,這樣這個(gè)過濾方法就不用修改,在實(shí)際調(diào)用的時(shí)候?qū)⒕唧w的實(shí)現(xiàn)類傳入即可。
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例如,如果想要篩選價(jià)格小于8000的商品,那么新建一個(gè)價(jià)格過濾類既可
public class PricePredicate implements MyPredicate<Product> {@Overridepublic boolean test(Product product) {return product.getPrice() < 8000;} }123456這樣實(shí)現(xiàn)的話可能有人會(huì)說,每次變更需求都需要新建一個(gè)實(shí)現(xiàn)類,感覺還是有點(diǎn)繁瑣呀,那么再來(lái)優(yōu)化一下
優(yōu)化二:使用匿名內(nèi)部類
定義過濾方法:
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調(diào)用過濾方法的時(shí)候:
// 按價(jià)格過濾 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使用匿名內(nèi)部類,就不需要每次都新建一個(gè)實(shí)現(xiàn)類,直接在方法內(nèi)部實(shí)現(xiàn)??吹侥涿麅?nèi)部類,不禁想起了Lambda表達(dá)式。
優(yōu)化三:使用lambda表達(dá)式
定義過濾方法:
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表達(dá)式進(jìn)行過濾
@Test public void test4(){List<Product> products = filterProductByPredicate(proList, (p) -> p.getPrice() < 8000);for (Product pro : products){System.out.println(pro);}}1234567在jdk1.8中還有更加簡(jiǎn)便的操作 Stream API
優(yōu)化四:使用Stream API
甚至不用定義過濾方法,直接在集合上進(jìn)行操作
// 使用jdk1.8中的Stream API進(jìn)行集合的操作 @Test public void test(){// 根據(jù)價(jià)格過濾proList.stream().fliter((p) -> p.getPrice() <8000).limit(2).forEach(System.out::println);// 根據(jù)顏色過濾proList.stream().fliter((p) -> "紅色".equals(p.getColor())).forEach(System.out::println);// 遍歷輸出商品名稱proList.stream().map(Product::getName).forEach(System.out::println); }12345678910111213141516171819Lmabda表達(dá)式的語(yǔ)法總結(jié): () -> ();
| 無(wú)參數(shù)無(wú)返回值 | () -> System.out.println(“Hello WOrld”) |
| 有一個(gè)參數(shù)無(wú)返回值 | (x) -> System.out.println(x) |
| 有且只有一個(gè)參數(shù)無(wú)返回值 | x -> System.out.println(x) |
| 有多個(gè)參數(shù),有返回值,有多條lambda體語(yǔ)句 | (x,y) -> {System.out.println(“xxx”);return xxxx;}; |
| 有多個(gè)參數(shù),有返回值,只有一條lambda體語(yǔ)句 | (x,y) -> xxxx |
口訣:左右遇一省括號(hào),左側(cè)推斷類型省
注:當(dāng)一個(gè)接口中存在多個(gè)抽象方法時(shí),如果使用lambda表達(dá)式,并不能智能匹配對(duì)應(yīng)的抽象方法,因此引入了函數(shù)式接口的概念
函數(shù)式接口
函數(shù)式接口的提出是為了給Lambda表達(dá)式的使用提供更好的支持。
什么是函數(shù)式接口?
簡(jiǎn)單來(lái)說就是只定義了一個(gè)抽象方法的接口(Object類的public方法除外),就是函數(shù)式接口,并且還提供了注解:@FunctionalInterface
常見的四大函數(shù)式接口
- Consumer 《T》:消費(fèi)型接口,有參無(wú)返回值
- Supplier 《T》:供給型接口,無(wú)參有返回值
- Function 《T,R》::函數(shù)式接口,有參有返回值
- Predicate《T》: 斷言型接口,有參有返回值,返回值是boolean類型
在四大核心函數(shù)式接口基礎(chǔ)上,還提供了諸如BiFunction、BinaryOperation、toIntFunction等擴(kuò)展的函數(shù)式接口,都是在這四種函數(shù)式接口上擴(kuò)展而來(lái)的,不做贅述。
總結(jié):函數(shù)式接口的提出是為了讓我們更加方便的使用lambda表達(dá)式,不需要自己再手動(dòng)創(chuàng)建一個(gè)函數(shù)式接口,直接拿來(lái)用就好了,貼
方法引用
若lambda體中的內(nèi)容有方法已經(jīng)實(shí)現(xiàn)了,那么可以使用“方法引用”
也可以理解為方法引用是lambda表達(dá)式的另外一種表現(xiàn)形式并且其語(yǔ)法比lambda表達(dá)式更加簡(jiǎn)單
(a) 方法引用
三種表現(xiàn)形式:
\1. 對(duì)象::實(shí)例方法名
\2. 類::靜態(tài)方法名
\3. 類::實(shí)例方法名 (lambda參數(shù)列表中第一個(gè)參數(shù)是實(shí)例方法的調(diào)用 者,第二個(gè)參數(shù)是實(shí)例方法的參數(shù)時(shí)可用)
(b)構(gòu)造器引用
格式:ClassName::new
?數(shù)組引用
格式:Type[]::new
public void test(){// 數(shù)組引用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); }1234567Stream API
Stream操作的三個(gè)步驟
- 創(chuàng)建stream
- 中間操作(過濾、map)
- 終止操作
stream的創(chuàng)建:
// 1,校驗(yàn)通過Collection 系列集合提供的stream()或者paralleStream()List<String> list = new ArrayList<>();Strean<String> stream1 = list.stream();// 2.通過Arrays的靜態(tài)方法stream()獲取數(shù)組流String[] str = new String[10];Stream<String> stream2 = Arrays.stream(str);// 3.通過Stream類中的靜態(tài)方法ofStream<String> stream3 = Stream.of("aa","bb","cc");// 4.創(chuàng)建無(wú)限流// 迭代Stream<Integer> stream4 = Stream.iterate(0,(x) -> x+2);//生成Stream.generate(() ->Math.random());1234567891011121314151617Stream的中間操作:
/*** 篩選 過濾 去重*/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); 123456789101112131415161718192021222324252627282930313233Stream的終止操作:
/*** 查找和匹配* allMatch-檢查是否匹配所有元素* anyMatch-檢查是否至少匹配一個(gè)元素* noneMatch-檢查是否沒有匹配所有元素* findFirst-返回第一個(gè)元素* findAny-返回當(dāng)前流中的任意元素* count-返回流中元素的總個(gè)數(shù)* 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還有功能比較強(qiáng)大的兩個(gè)終止操作 reduce和collect
reduce操作: reduce:(T identity,BinaryOperator)/reduce(BinaryOperator)-可以將流中元素反復(fù)結(jié)合起來(lái),得到一個(gè)值
collect操作:Collect-將流轉(zhuǎn)換為其他形式,接收一個(gè)Collection接口的實(shí)現(xiàn),用于給Stream中元素做匯總的方法
/*** collect:收集操作*/List<Integer> ageList = emps.stream().map(Employee::getAge).collect(Collectors.toList());ageList.stream().forEach(System.out::println);12345678并行流和串行流
在jdk1.8新的stream包中針對(duì)集合的操作也提供了并行操作流和串行操作流。并行流就是把內(nèi)容切割成多個(gè)數(shù)據(jù)塊,并且使用多個(gè)線程分別處理每個(gè)數(shù)據(jù)塊的內(nèi)容。Stream api中聲明可以通過parallel()與sequential()方法在并行流和串行流之間進(jìn)行切換。
jdk1.8并行流使用的是fork/join框架進(jìn)行并行操作
ForkJoin框架
Fork/Join 框架:就是在必要的情況下,將一個(gè)大任務(wù),進(jìn)行拆分(fork)成若干個(gè)小任務(wù)(拆到不可再拆時(shí)),再將一個(gè)個(gè)的小任務(wù)運(yùn)算的結(jié)果進(jìn)行 join 匯總。
關(guān)鍵字:遞歸分合、分而治之。
采用 “工作竊取”模式(work-stealing):
當(dāng)執(zhí)行新的任務(wù)時(shí)它可以將其拆分分成更小的任務(wù)執(zhí)行,并將小任務(wù)加到線
程隊(duì)列中,然后再?gòu)囊粋€(gè)隨機(jī)線程的隊(duì)列中偷一個(gè)并把它放在自己的隊(duì)列中
相對(duì)于一般的線程池實(shí)現(xiàn),fork/join框架的優(yōu)勢(shì)體現(xiàn)在對(duì)其中包含的任務(wù)的
處理方式上.在一般的線程池中,如果一個(gè)線程正在執(zhí)行的任務(wù)由于某些原因
無(wú)法繼續(xù)運(yùn)行,那么該線程會(huì)處于等待狀態(tài).而在fork/join框架實(shí)現(xiàn)中,如果
某個(gè)子問題由于等待另外一個(gè)子問題的完成而無(wú)法繼續(xù)運(yùn)行.那么處理該子
問題的線程會(huì)主動(dòng)尋找其他尚未運(yùn)行的子問題來(lái)執(zhí)行.這種方式減少了線程
的等待時(shí)間,提高了性能.。
展示多線程的效果:
@Testpublic void test(){// 并行流 多個(gè)線程執(zhí)行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);}12345678910111213Optional容器
使用Optional容器可以快速的定位NPE,并且在一定程度上可以減少對(duì)參數(shù)非空檢驗(yàn)的代碼量。 1 /*** Optional.of(T t); // 創(chuàng)建一個(gè)Optional實(shí)例* Optional.empty(); // 創(chuàng)建一個(gè)空的Optional實(shí)例* Optional.ofNullable(T t); // 若T不為null,創(chuàng)建一個(gè)Optional實(shí)例,否則創(chuàng)建一個(gè)空實(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類似。返回值是Optional** 總結(jié):Optional.of(null) 會(huì)直接報(bào)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接口中可以定義默認(rèn)實(shí)現(xiàn)方法和靜態(tài)方法
在接口中可以使用default和static關(guān)鍵字來(lái)修飾接口中定義的普通方法
public interface Interface {default String getName(){return "zhangsan";}static String getName2(){return "zhangsan";} } 12345678910在JDK1.8中很多接口會(huì)新增方法,為了保證1.8向下兼容,1.7版本中的接口實(shí)現(xiàn)類不用每個(gè)都重新實(shí)現(xiàn)新添加的接口方法,引入了default默認(rèn)實(shí)現(xiàn),static的用法是直接用接口名去調(diào)方法即可。當(dāng)一個(gè)類繼承父類又實(shí)現(xiàn)接口時(shí),若后兩者方法名相同,則優(yōu)先繼承父類中的同名方法,即“類優(yōu)先”,如果實(shí)現(xiàn)兩個(gè)同名方法的接口,則要求實(shí)現(xiàn)類必須手動(dòng)聲明默認(rèn)實(shí)現(xiàn)哪個(gè)接口中的方法。
新的日期API LocalDate | LocalTime | LocalDateTime
新的日期API都是不可變的,更使用于多線程的使用環(huán)境中
@Testpublic void test(){// 從默認(rèn)時(shí)區(qū)的系統(tǒng)時(shí)鐘獲取當(dāng)前的日期時(shí)間。不用考慮時(shí)區(qū)差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());// 手動(dòng)創(chuàng)建一個(gè)LocalDateTime實(shí)例LocalDateTime date2 = LocalDateTime.of(2017, 12, 17, 9, 31, 31, 31);System.out.println(date2);// 進(jìn)行加操作,得到新的日期實(shí)例LocalDateTime date3 = date2.plusDays(12);System.out.println(date3);// 進(jìn)行減操作,得到新的日期實(shí)例LocalDateTime date4 = date3.minusYears(2);System.out.println(date4);} 1234567891011121314151617181920212223242526@Testpublic void test2(){// 時(shí)間戳 1970年1月1日00:00:00 到某一個(gè)時(shí)間點(diǎn)的毫秒值// 默認(rèn)獲取UTC時(shí)區(qū)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:計(jì)算兩個(gè)時(shí)間之間的間隔// Period:計(jì)算兩個(gè)日期之間的間隔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 時(shí)間校驗(yàn)器// 例如獲取下周日 下一個(gè)工作日LocalDateTime ldt1 = LocalDateTime.now();System.out.println(ldt1);// 獲取一年中的第一天LocalDateTime ldt2 = ldt1.withDayOfYear(1);System.out.println(ldt2);// 獲取一個(gè)月中的第一天LocalDateTime ldt3 = ldt1.withDayOfMonth(1);System.out.println(ldt3);LocalDateTime ldt4 = ldt1.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));System.out.println(ldt4);// 獲取下一個(gè)工作日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: 格式化時(shí)間/日期// 自定義格式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時(shí)間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轉(zhuǎn)成String類型的時(shí)間:"+localTime);System.out.println("String類型的時(shí)間轉(zhuǎn)成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補(bǔ)充:
表示日期的LocalDate
表示時(shí)間的LocalTime
表示日期時(shí)間的LocalDateTime
新的日期API的幾個(gè)優(yōu)點(diǎn):
* 之前使用的java.util.Date月份從0開始,我們一般會(huì)+1使用,很不方便,java.time.LocalDate月份和星期都改成了enum* java.util.Date和SimpleDateFormat都不是線程安全的,而LocalDate和LocalTime和最基本的String一樣,是不變類型,不但線程安全,而且不能修改。* java.util.Date是一個(gè)“萬(wàn)能接口”,它包含日期、時(shí)間,還有毫秒數(shù),更加明確需求取舍* 新接口更好用的原因是考慮到了日期時(shí)間的操作,經(jīng)常發(fā)生往前推或往后推幾天的情況。用java.util.Date配合Calendar要寫好多代碼,而且一般的開發(fā)人員還不一定能寫對(duì)。 1234- LocalDate
- LocalDate常用轉(zhuǎn)化
- LocalTime
- LocalDateTime
總結(jié)
以上是生活随笔為你收集整理的JDK1.8 新特性(全)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: carsim的学习笔记2——test s
- 下一篇: carsim学习笔记3——仿真环境(驾驶