一笆豁、新的Data/Time API
Java 8引入了新的Date和Time的API描睦,從而修復(fù)了一些舊API的缺陷锯七。
這些缺陷主要有:
- 不是線程安全的:java.util.Data不是線程安全的访敌,因此開發(fā)者在以前用這些API的時(shí)候必須要注意并發(fā)的情況腊嗡。而新的API是不可變的舷手,并且沒有setter方法拧簸。
- 匱乏的設(shè)計(jì):默認(rèn)日期的年從1900年開始、月份從1開始男窟,并且日期從0開始盆赤,它們?nèi)狈y(tǒng)一性。舊的API對于日期的操作缺乏直接的方法歉眷。新的API則對于這些操作提供了許多的設(shè)定方法牺六。
- 較難的時(shí)區(qū)處理:之前,開發(fā)者需要寫大量的代碼來解決時(shí)區(qū)的問題姥芥。新的API則簡化了這個(gè)步驟兔乞。
Java 8在java.time包內(nèi)引入了這些新的API。下面是一些比較重要的類:
- Local:簡化的data/time API凉唐,沒有時(shí)區(qū)處理的特性庸追。
- Zoned:定制的date/time API,用于處理多時(shí)區(qū)的情況台囱。
1. 一個(gè)本地日期時(shí)間的例子
Java 8提供了LocalDate淡溯、LocalTime和LocalDataTime類來簡化不需要時(shí)區(qū)的情況下的開發(fā)工作。
package com.shiyanlou.java8;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.Month;
public class NewFeaturesTester {
public static void main(String args[]){
Java8Tester java8tester = new Java8Tester();
java8tester.testLocalDateTime();
}
public void testLocalDateTime(){
// 獲得當(dāng)前的日期和時(shí)間
LocalDateTime currentTime = LocalDateTime.now();
System.out.println("current date and time: " + currentTime);
// 輸出當(dāng)前時(shí)間的本地值(本時(shí)區(qū))
LocalDate date1 = currentTime.toLocalDate();
System.out.println("local date: " + date1);
Month month = currentTime.getMonth();
int day = currentTime.getDayOfMonth();
int seconds = currentTime.getSecond();
// 由當(dāng)前時(shí)間對象獲得各個(gè)字段簿训,輸出結(jié)果
System.out.println("month: " + month +"day: " + day +"seconds: " + seconds);
// 由當(dāng)前時(shí)間附帶月份和年再輸出
LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
System.out.println("date 2: " + date2);
// 輸出2016年圣誕節(jié)的日期
LocalDate date3 = LocalDate.of(2016, Month.DECEMBER, 25);
System.out.println("date 3: " + date3);
// 輸出新聞聯(lián)播的開始時(shí)間
LocalTime date4 = LocalTime.of(19, 00);
System.out.println("date 4: " + date4);
// 轉(zhuǎn)化為字符串咱娶,再輸出
LocalTime date5 = LocalTime.parse("20:15:30");
System.out.println("date 5: " + date5);
}
}
運(yùn)行結(jié)果:
2. 一個(gè)帶時(shí)區(qū)的Date/Time API例子
具有時(shí)區(qū)功能的日期時(shí)間API被用于需要考慮時(shí)區(qū)信息的情況。
package com.shiyanlou.java8;
import java.time.ZonedDateTime;
import java.time.ZoneId;
public class NewFeaturesTester {
public static void main(String args[]){
NewFeaturesTester tester = new NewFeaturesTester();
tester.testZonedDateTime();
}
public void testZonedDateTime(){
// 將字符串代表的時(shí)區(qū)信息轉(zhuǎn)化
ZonedDateTime date1 = ZonedDateTime.parse("2016-04-20T19:22:15+01:30[Europe/Paris]");
System.out.println("date1: " + date1);
// 設(shè)定地區(qū)ID為亞洲的加爾各答(位于印度)强品,并輸出
ZoneId id = ZoneId.of("Asia/Kolkata");
System.out.println("ZoneId: " + id);
// 獲得系統(tǒng)默認(rèn)的當(dāng)前地區(qū)并輸出
ZoneId currentZone = ZoneId.systemDefault();
System.out.println("CurrentZone: " + currentZone);
}
}
運(yùn)行結(jié)果:
3. 一個(gè)枚舉計(jì)時(shí)單位的例子
在java.time.temporal.ChronoUnit包內(nèi)膘侮,添加了枚舉常量,來代替舊的API里用整數(shù)值代表的日期值的榛。
package com.shiyanlou.java8;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class NewFeaturesTester {
public static void main(String args[]){
NewFeaturesTester tester = new NewFeaturesTester();
tester.testChromoUnits();
}
public void testChromoUnits(){
// 獲得當(dāng)前的日期并輸出
LocalDate today = LocalDate.now();
System.out.println("Current date: " + today);
// 在當(dāng)前日期的基礎(chǔ)上增加兩周時(shí)間再輸出
LocalDate nextWeek = today.plus(2, ChronoUnit.WEEKS);
System.out.println("two weeks after now: " + nextWeek);
// 在當(dāng)前日期的基礎(chǔ)上增加6個(gè)月的時(shí)間再輸出
LocalDate nextMonth = today.plus(6, ChronoUnit.MONTHS);
System.out.println("6 months after now: " + nextMonth);
// 在當(dāng)前日期的基礎(chǔ)上增加5年的時(shí)間再輸出
LocalDate nextYear = today.plus(5, ChronoUnit.YEARS);
System.out.println("5 years after now: " + nextYear);
// 在當(dāng)前日期的基礎(chǔ)上增加20年的時(shí)間再輸出(一個(gè)Decade為10年)
LocalDate nextDecade = today.plus(2, ChronoUnit.DECADES);
System.out.println("20 years after now: " + nextDecade);
}
}
4. 一個(gè)時(shí)間段的例子
在Java 8中琼了,還有兩個(gè)特殊的類用于處理一些特殊的時(shí)間問題:
- Period:該類用于處理日期相關(guān)的時(shí)間段
- Duration:該類用于處理時(shí)間相關(guān)的時(shí)間段
package com.shiyanlou.java8;
import java.time.temporal.ChronoUnit;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Duration;
import java.time.Period;
public class NewFeaturesTester {
public static void main(String args[]){
NewFeaturesTester tester = new NewFeaturesTester();
tester.showPeriod();
tester.showDuration();
}
public void showPeriod(){
// 獲得當(dāng)前的日期
LocalDate date1 = LocalDate.now();
System.out.println("Current date: " + date1);
// 在當(dāng)前日期的基礎(chǔ)上增加一個(gè)月時(shí)間
LocalDate date2 = date1.plus(1, ChronoUnit.MONTHS);
System.out.println("Next month: " + date2);
// 用between方法計(jì)算兩個(gè)日期直接的間隔(稱之為Period)
Period period = Period.between(date2, date1);
System.out.println("Period: " + period);
}
public void showDuration(){
LocalTime time1 = LocalTime.now();
Duration fiveHours = Duration.ofHours(5);
LocalTime time2 = time1.plus(fiveHours);
// 對應(yīng)的,用between方法顯示兩個(gè)時(shí)間直接的間隔(稱之為Duration)
Duration duration = Duration.between(time1, time2);
System.out.println("Duration: " + duration);
}
}
5.一個(gè)時(shí)間調(diào)節(jié)器的例子
TemporalAdjuster是用于計(jì)算日期的數(shù)學(xué)工具夫晌,比如說你可以通過下面的例子雕薪,獲得“下個(gè)月的第二個(gè)周日”這樣的計(jì)算出來的日期。
package com.shiyanlou.java8;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.time.DayOfWeek;
public class NewFeaturesTester {
public static void main(String args[]){
NewFeaturesTester tester = new NewFeaturesTester;
tester.applyAdjusters();
}
public void applyAdjusters(){
// 獲得當(dāng)前的日期
LocalDate date1 = LocalDate.now();
System.out.println("current date: " + date1);
// 計(jì)算下周一的日期并輸出
LocalDate nextMonday = date1.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println("next monday on : " + nextMonday);
// 獲得下個(gè)月的第二個(gè)周期的日期并輸出
LocalDate firstInYear = LocalDate.of(date1.getYear(),date1.getMonth(), 1);
LocalDate secondSunday = firstInYear.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)).with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println("second sunday of next month : " + secondSunday);
}
}
6. 向后兼容能力
為了保持向后兼容的能力晓淀,原始的Date和Calendar對象添加了一個(gè)toInstant
方法所袁。該方法可以將其轉(zhuǎn)換為新API下的對象。當(dāng)然凶掰,還可以用ofInstant方法來獲得LocalDateTime和ZonedDataTime對象燥爷。
package com.shiyanlou.java8;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.Date;
import java.time.Instant;
import java.time.ZoneId;
public class NewFeaturesTester {
public static void main(String args[]){
NewFeaturesTester tester = new NewFeaturesTester();
tester.applyBackwardCompatability();
}
public void applyBackwardCompatability(){
// 獲得當(dāng)前日期并輸出
Date currentDate = new Date();
System.out.println("Current date: " + currentDate);
// 獲得當(dāng)前日期的實(shí)例(以毫秒的形式)
Instant now = currentDate.toInstant();
ZoneId currentZone = ZoneId.systemDefault();
// 用ofInstant方法獲得實(shí)例
LocalDateTime localDateTime = LocalDateTime.ofInstant(now, currentZone);
System.out.println("Local date: " + localDateTime);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, currentZone);
System.out.println("Zoned date: " + zonedDateTime);
}
}
二蜈亩、Base64編碼
在Java 8中,內(nèi)置了Base64編解碼相關(guān)的特性局劲。我們可以在Java 8中使用下面三種類型的Base64編解碼:
- 簡易模式:輸出是完全按照A-Za-z0-9+/字符集映射的勺拣。編碼不會自己增加輸出行,解碼器也不會接受任何超出A-Za-z0-9+/范圍的內(nèi)容鱼填。
- URL模式:輸出基于A-Za-z0-9+/的映射药有,但對于URL和文件名是安全的。
- MIME模式:輸出對于MIME類型的內(nèi)容是友好的苹丸。如果超過76個(gè)字符愤惰,則會換行輸出。赘理,并且換行符\n之后會自動添加一個(gè)\r宦言。如果某行沒有\(zhòng)r則說明輸出的內(nèi)容已經(jīng)結(jié)束。
1. Base64的內(nèi)部類和方法
Base64相關(guān)的內(nèi)部類有:
- Base64.Encoder:這是一個(gè)靜態(tài)類商模。實(shí)現(xiàn)了Base64的編碼功能奠旺,格式遵循了RFC 4648和RFC 2045標(biāo)準(zhǔn)。
- Base64.Decoder:也是一個(gè)靜態(tài)類施流。實(shí)現(xiàn)了Base64的解碼功能响疚。
相關(guān)的方法有:
- getEncoder():該方法返回一個(gè)使用基本Base64編碼格式的Encoder對象。相反的解碼方法是getDecoder()瞪醋。
- getUrlEncoder():該方法返回一個(gè)使用URL類型的Base64編碼格式的Encoder對象忿晕。相反的解碼方法是getUrlDecoder()。
- getMimeEncoder():該方法返回一個(gè)使用MIME類型的Base64編碼格式的Encoder對象银受。相反的解碼方法是getMimeDecoder()践盼。
更多的方法你可以查閱Java 8的官方手冊。
2. 一個(gè)Base64編解碼的例子
package com.shiyanlou.java8;
import java.util.Base64;
import java.util.UUID;
import java.io.UnsupportedEncodingException;
public class NewFeaturesTester {
public static void main(String args[]){
try {
// 使用基本的Base64編碼
String base64encodedString = Base64.getEncoder().encodeToString("Shiyanlou.com".getBytes("utf-8"));
System.out.println("Basic base64 encoding:" + base64encodedString);
// 解碼并輸出結(jié)果
byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
System.out.println("Original content: " + new String(base64decodedBytes, "utf-8"));
// 使用URL類型的Base64編碼
base64encodedString = Base64.getUrlEncoder().encodeToString("Shiyanlou.com".getBytes("utf-8"));
System.out.println("URL base64 encoding:" + base64encodedString);
// MIME類型的Base64編碼
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 10; ++i) {
stringBuilder.append(UUID.randomUUID().toString());
}
byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");
String mimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);
System.out.println("MIME base64 encoding:" + mimeEncodedString);
}catch(UnsupportedEncodingException e){
// 捕獲異常并輸出
System.out.println("Exception:" + e.getMessage());
}
}
}
節(jié)選了最基礎(chǔ)也是最重要的幾個(gè)知識點(diǎn)來進(jìn)行講解宾巍。而諸如Nashorn引擎(JavaScript)咕幻、JavaFX、JDBC等領(lǐng)域則沒有涉及顶霞。建議你在具有一定開發(fā)經(jīng)驗(yàn)后再通過相關(guān)的課程來學(xué)習(xí)它們谅河。
最全的Java 8新功能說明位于Java的官方網(wǎng)站,你可以通過閱讀《What's New in JDK 8》來了解它們确丢。