Java8--是時候丟掉DateUtils了,新的時間API和Base64

1 新的 Date/Time API

Java 8引入了新的Date和Time的API,從而修復了一些舊API的缺陷。
這些缺陷主要有:

  • 不是線程安全的:java.util.Date不是線程安全的,因此開發者在以前用這些API的時候必須要注意併發的情況。而新的API是不可變的,並且沒有setter方法。
  • 匱乏的設計:默認日期的年從1900年開始、月份從1開始,並且日期從0開始,它們缺乏統一性。舊的API對於日期的操作缺乏直接的方法。新的API則對於這些操作提供了許多的設定方法。
  • 較難的時區處理:之前,開發者需要寫大量的代碼來解決時區的問題。新的API則簡化了這個步驟。
    Java 8在java.time包內引入了這些新的API。下面是一些比較重要的類:
  • Local:簡化的date/time API,沒有時區處理的特性。
  • Zoned:定製的date/time API,用於處理多時區的情況。

1.1 一個本地日期時間的例子

Java 8提供了LocalDate、LocalTime和LocalDataTime類來簡化不需要時區的情況下的開發工作。下面我們通過一個例子來學習它們。
以下是NewFeaturesTester.java類中應當輸入的代碼:

public class NewFeaturesTester {
   public static void main(String args[]){
      NewFeaturesTester tester = new NewFeaturesTester();
      tester.testLocalDateTime();
   }
   public void testLocalDateTime(){
      // 獲得當前的日期和時間
      LocalDateTime currentTime = LocalDateTime.now();
      System.out.println("current date and time: " + currentTime);
      // 輸出當前時間的本地值(本時區)
      LocalDate date1 = currentTime.toLocalDate();
      System.out.println("local date: " + date1);
      Month month = currentTime.getMonth();
      int day = currentTime.getDayOfMonth();
      int seconds = currentTime.getSecond();
      // 由當前時間對象獲得各個字段,輸出結果
      System.out.println("month: " + month +"day: " + day +"seconds: " + seconds);
      // 由當前時間附帶月份和年再輸出
      LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
      System.out.println("date 2: " + date2);
      // 輸出2016年聖誕節的日期
      LocalDate date3 = LocalDate.of(2016, Month.DECEMBER, 25);
      System.out.println("date 3: " + date3);
      // 輸出新聞聯播的開始時間
      LocalTime date4 = LocalTime.of(19, 00);
      System.out.println("date 4: " + date4);
      // 轉化爲字符串,再輸出
      LocalTime date5 = LocalTime.parse("20:15:30");
      System.out.println("date 5: " + date5);
   }
}

1.2 一個帶時區的 Date/Time API例子

具有時區功能的日期時間API被用於需要考慮時區信息的情況。同樣的,我們通過一個例子來使用它們。

public class NewFeaturesTester {
   public static void main(String args[]){
      NewFeaturesTester tester = new NewFeaturesTester();
      tester.testZonedDateTime();
   }
   public void testZonedDateTime(){
      // 將字符串代表的時區信息轉化
      ZonedDateTime date1 = ZonedDateTime.parse("2016-04-20T19:22:15+01:30[Europe/Paris]");
      System.out.println("date1: " + date1);
      // 設定地區ID爲亞洲的加爾各答(位於印度),並輸出
      ZoneId id = ZoneId.of("Asia/Kolkata");
      System.out.println("ZoneId: " + id);
      // 獲得系統默認的當前地區並輸出
      ZoneId currentZone = ZoneId.systemDefault();
      System.out.println("CurrentZone: " + currentZone);
   }
}

1.3 一個枚舉計時單位的例子

在java.time.temporal.ChronoUnit包內,添加了枚舉常量,來代替舊的API裏用整數值代表的日期值。

public class NewFeaturesTester {
   public static void main(String args[]){
      NewFeaturesTester tester = new NewFeaturesTester();
      tester.testChromoUnits();
   }
   public void testChromoUnits(){
      // 獲得當前的日期並輸出
      LocalDate today = LocalDate.now();
      System.out.println("Current date: " + today);
      // 在當前日期的基礎上增加兩週時間再輸出
      LocalDate nextWeek = today.plus(2, ChronoUnit.WEEKS);
      System.out.println("two weeks after now: " + nextWeek);
      // 在當前日期的基礎上增加6個月的時間再輸出
      LocalDate nextMonth = today.plus(6, ChronoUnit.MONTHS);
      System.out.println("6 months after now: " + nextMonth);
      // 在當前日期的基礎上增加5年的時間再輸出
      LocalDate nextYear = today.plus(5, ChronoUnit.YEARS);
      System.out.println("5 years after now: " + nextYear);
      // 在當前日期的基礎上增加20年的時間再輸出(一個Decade爲10年)
      LocalDate nextDecade = today.plus(2, ChronoUnit.DECADES);
      System.out.println("20 years after now: " + nextDecade);
   }
}

1.4 一個時間段的例子

在Java 8中,還有兩個特殊的類用於處理一些特殊的時間問題:

  • Period:該類用於處理日期相關的時間段
  • Duration:該類用於處理時間相關的時間段
public class NewFeaturesTester {
   public static void main(String args[]){
      NewFeaturesTester tester = new NewFeaturesTester();
      tester.showPeriod();
      tester.showDuration();
   }
   public void showPeriod(){
      // 獲得當前的日期
      LocalDate date1 = LocalDate.now();
      System.out.println("Current date: " + date1);
      // 在當前日期的基礎上增加一個月時間
      LocalDate date2 = date1.plus(1, ChronoUnit.MONTHS);
      System.out.println("Next month: " + date2);
      // 用between方法計算兩個日期直接的間隔(稱之爲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);
      // 對應的,用between方法顯示兩個時間直接的間隔(稱之爲Duration)
      Duration duration = Duration.between(time1, time2);
      System.out.println("Duration: " + duration);
   }
}

1.5 一個時間調節器的例子

TemporalAdjuster是用於計算日期的數學工具,比如說你可以通過下面的例子,獲得“下個月的第二個週日”這樣的計算出來的日期。:

public class NewFeaturesTester {
   public static void main(String args[]){
      NewFeaturesTester tester = new  NewFeaturesTester();
      tester.applyAdjusters();
   }
   public void applyAdjusters(){
      // 獲得當前的日期
      LocalDate date1 = LocalDate.now();
      System.out.println("current date: " + date1);
      // 計算下週一的日期並輸出
      LocalDate nextMonday = date1.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
      System.out.println("next monday on : " + nextMonday);
      // 獲得下個月的第二個週期的日期並輸出
      LocalDate date2 = date1.plus(1, ChronoUnit.MONTHS);
      LocalDate firstInMonth = LocalDate.of(date2.getYear(),date2.getMonth(), 1);
      LocalDate secondSunday = firstInMonth.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)).with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
      System.out.println("second sunday of next month : " + secondSunday);
   }
}

1.6 向後兼容能力

爲了保持向後兼容的能力,原始的Date和Calendar對象添加了一個toInstant方法。該方法可以將其轉換爲新API下的對象。當然,還可以用ofInstant方法來獲得LocalDateTime和ZonedDataTime對象。

public class NewFeaturesTester {
   public static void main(String args[]){
      NewFeaturesTester tester = new NewFeaturesTester();
      tester.applyBackwardCompatability();
   }
   public void applyBackwardCompatability(){
      // 獲得當前日期並輸出
      Date currentDate = new Date();
      System.out.println("Current date: " + currentDate);
      // 獲得當前日期的實例(以毫秒的形式)
      Instant now = currentDate.toInstant();
      ZoneId currentZone = ZoneId.systemDefault();
      // 用ofInstant方法獲得實例
      LocalDateTime localDateTime = LocalDateTime.ofInstant(now, currentZone);
      System.out.println("Local date: " + localDateTime);
      ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, currentZone);
      System.out.println("Zoned date: " + zonedDateTime);
   }
}

2 Base64編碼

在Java 8中,內置了Base64編解碼相關的特性。我們可以在Java 8中使用下面三種類型的Base64編解碼:

  • 簡易模式:輸出是完全按照A-Za-z0-9+/字符集映射的。編碼不會自己增加輸出行,解碼器也不會接受任何超出A-Za-z0-9+/範圍的內容。
  • URL模式:輸出基於A-Za-z0-9+/的映射,但對於URL和文件名是安全的。
  • MIME模式:輸出對於MIME類型的內容是友好的。如果超過76個字符,則會換行輸出,並且換行符\n之後會自動添加一個\r。如果某行沒有\r則說明輸出的內容已經結束。

2.1 Base64的內部類和方法

Base64相關的內部類有:

  • Base64.Encoder:這是一個靜態類。實現了Base64的編碼功能,格式遵循了RFC 4648和RFC 2045標準。
  • Base64.Decoder:也是一個靜態類。實現了Base64的解碼功能。
    相關的方法有:
  • getEncoder():該方法返回一個使用基本Base64編碼格式的Encoder對象。相反的解碼方法是getDecoder()。
  • getUrlEncoder():該方法返回一個使用URL類型的Base64編碼格式的Encoder對象。相反的解碼方法是getUrlDecoder()。
  • getMimeEncoder():該方法返回一個使用MIME類型的Base64編碼格式的Encoder對象。相反的解碼方法是getMimeDecoder()。
    更多的方法你可以查閱Java 8的官方手冊。

2.2 一個Base64編解碼的例子

使用Java 8的API,進行Base64編解碼。

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);
         // 解碼並輸出結果
         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());
      }
   }
}

最全的Java 8新功能說明位於Java的官方網站,你可以通過閱讀《What’s New in JDK 8》來了解它們。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章