I want to fly higher
          programming Explorer
          posts - 114,comments - 263,trackbacks - 0
              本篇用代碼示例結合JDk源碼及本人的理解講了Java8新的時間API以及Repeatable Annotation.       
               參考:http://winterbe.com/posts/2014/03/16/java-8-tutorial/

              1.java.time API

          package com.mavsplus.java8.turtorial.time;

          import java.time.Clock;
          import java.time.DayOfWeek;
          import java.time.Instant;
          import java.time.LocalDate;
          import java.time.LocalDateTime;
          import java.time.LocalTime;
          import java.time.Month;
          import java.time.ZoneId;
          import java.time.format.DateTimeFormatter;
          import java.time.format.FormatStyle;
          import java.time.temporal.ChronoField;
          import java.time.temporal.ChronoUnit;
          import java.util.Date;
          import java.util.Locale;
          import java.util.Set;

          /**
           * Java 8 包含了全新的時間日期API,這些功能都放在了java.time包下。新的時間日期API是基于Joda-Time庫開發的,但是也不盡相同
           * 
           * <p>
           * public abstract class Clock {
           * 
           * @author landon
           * @since 1.8.0_25
           
          */

          public class TimeAPIExample {

              
          /**
               * Clock提供了對當前時間和日期的訪問功能。Clock是對當前時區敏感的,并可用于替代System.currentTimeMillis()
               * 方法來獲取當前的毫秒時間。當前時間線上的時刻可以用Instance類來表示。Instance也能夠用于創建原先的java.util.Date對象。
               
          */

              
          public void useClock() {
                  Clock clock = Clock.systemDefaultZone();

                  
          long clockMillis = clock.millis();
                  
          long curMillis = System.currentTimeMillis();

                  
          // %d格式包括了int/long等
                  
          // 從輸出可以看出,二者完全相同
                  System.out.format("clockMillis:%d,curMillis:%d", clockMillis, curMillis).println();

                  Instant instant = clock.instant();
                  
          // 這里lagacy可以理解為傳統的
                  Date legacyDate = Date.from(instant);

                  System.out.println(String.format("legacyDate:%d", legacyDate.getTime()));
              }


              
          /**
               * 時區類可以用一個ZoneId來表示。時區類的對象可以通過靜態工廠方法方便地獲取。時區類還定義了一個偏移量,
               * 用來在當前時刻或某時間與目標時區時間之間進行轉換
               
          */

              
          public void useTimeZone() {
                  
          // public abstract class ZoneId implements Serializable

                  
          // 迭代可用的時區
                  Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
                  
          // 現學現賣!lambda!
                  availableZoneIds.stream().forEach(System.out::println);

                  ZoneId zoneId1 = ZoneId.of("Asia/Shanghai");
                  ZoneId zoneId2 = ZoneId.of("America/New_York");

                  
          // 輸出:ZoneRules[currentStandardOffset=+08:00]
                  System.out.println(zoneId1.getRules());
                  
          // 輸出:ZoneRules[currentStandardOffset=-05:00]
                  System.out.println(zoneId2.getRules());
              }


              
          /**
               * 本地時間類表示一個沒有指定時區的時間,例如,10
               * p.m.或者17:30:15,下面的例子會用上面的例子定義的時區創建兩個本地時間對象。然后我們會比較兩個時間,并計算它們之間的小時和分鐘的不同
               * 
               * LocalTime是由多個工廠方法組成,其目的是為了簡化對時間對象實例的創建和操作,包括對時間字符串進行解析的操作
               
          */

              
          public void useLocalTime() {
                  ZoneId zoneId1 = ZoneId.of("Asia/Shanghai");
                  ZoneId zoneId2 = ZoneId.of("America/New_York");

                  LocalTime now1 = LocalTime.now(zoneId1);
                  LocalTime now2 = LocalTime.now(zoneId2);

                  System.out.println(now1.isBefore(now2));
                  System.out.println(now1.isAfter(now2));

                  
          // public enum ChronoUnit implements TemporalUnit
                  
          // Chrono_計時器
                  long hoursBetween = ChronoUnit.HOURS.between(now1, now2);
                  
          long minutesBetween = ChronoUnit.MINUTES.between(now1, now2);

                  
          // 因為一個是s+8,一個是s-5,相差13個小時
                  System.out.println(hoursBetween);
                  System.out.println(minutesBetween);

                  LocalTime lt = LocalTime.of(161915);
                  System.out.println(lt);

                  
          // public final class DateTimeFormatter
                  DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(
                          Locale.SIMPLIFIED_CHINESE);
                  
          // 注意這里必須要用"下午6:30"(或者上午),因為Locale選擇的是中國,否則其他形式報錯
                  LocalTime lt2 = LocalTime.parse("下午6:30", formatter);
                  
          // 輸出:18:30
                  System.out.println(lt2);
              }


              
          /**
               * 本地日期表示了一個獨一無二的時間,例如:2014-03-11。這個時間是不可變的,與LocalTime是同源的。下面的例子演示了如何通過加減日,月
               * , 年等指標來計算新的日期。記住,每一次操作都會返回一個新的時間對象
               * 
               * 解析字符串并形成LocalDate對象,這個操作和解析LocalTime一樣簡單
               
          */

              
          public void useLocalDate() {
                  LocalDate today = LocalDate.now();
                  
          // 輸出:2014-11-19
                  System.out.println(today);

                  
          // 獲取明天
                  LocalDate tomorrow = today.plus(1, ChronoUnit.DAYS);
                  
          // 獲取昨天
                  LocalDate yesterday = tomorrow.minusDays(2);

                  System.out.println(String.format("tomorrow:%s,yesterday:%s", tomorrow, yesterday));

                  
          // 國慶節
                  LocalDate nationalDay = LocalDate.of(2014, Month.OCTOBER, 1);
                  DayOfWeek dayOfWeek = nationalDay.getDayOfWeek();

                  
          // 2014年10月1是星期三
                  
          // 輸出:WEDNESDAY
                  System.out.println(dayOfWeek);

                  DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(
                          Locale.SIMPLIFIED_CHINESE);
                  
          // 注意這里第一個參數文本"2014-11-19",目前測試必須這樣,因為Locale為中國
                  LocalDate ld = LocalDate.parse("2014-11-19", formatter);

                  System.out.println(ld);
              }


              
          /**
               * LocalDateTime表示的是日期-時間。它將剛才介紹的日期對象和時間對象結合起來,形成了一個對象實例。LocalDateTime是不可變的,
               * 與LocalTime和LocalDate的工作原理相同。我們可以通過調用方法來獲取日期時間對象中特定的數據域
               
          */

              
          public void useLocalDateTime() {
                  LocalDateTime end2014 = LocalDateTime.of(2014, Month.DECEMBER, 31235959);

                  
          // 2014年12月31日是星期三
                  DayOfWeek dayOfWeek = end2014.getDayOfWeek();
                  
          // 輸出:WEDNESDAY
                  System.out.println(dayOfWeek);

                  Month month = end2014.getMonth();
                  
          // 輸出:DECEMBER
                  System.out.println(month);

                  
          // This counts the minute within the day(23 * 60 + 59 = 1439)
                  long minuteOfDay = end2014.getLong(ChronoField.MINUTE_OF_DAY);
                  
          // 輸出:1439
                  System.out.println(minuteOfDay);

                  
          // 如果再加上的時區信息,LocalDateTime能夠被轉換成Instance實例。Instance能夠被轉換成以前的java.util.Date對象
                  Instant instant = end2014.atZone(ZoneId.systemDefault()).toInstant();
                  Date legacyDate = Date.from(instant);

                  
          // 輸出:Wed Dec 31 23:59:59 CST 2014
                  System.out.println(legacyDate);

                  
          // 格式化日期-時間對象就和格式化日期對象或者時間對象一樣。除了使用預定義的格式以外,我們還可以創建自定義的格式化對象,然后匹配我們自定義的格式。
                  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy,MM-dd HH:mm");
                  LocalDateTime parsed = LocalDateTime.parse("2014,11-19 19:23", formatter);

                  System.out.println(formatter.format(parsed));

                  
          // 不同于java.text.NumberFormat,新的DateTimeFormatter類是不可變的,也是線程安全的
                  
          // ->因為public final class DateTimeFormatter->final的
              }


              
          public static void main(String[] args) {
                  TimeAPIExample example = new TimeAPIExample();

                  example.useClock();
                  example.useTimeZone();
                  example.useLocalTime();
                  example.useLocalDate();
                  example.useLocalDateTime();
              }

          }



              2.Repeatable Annotation

          package com.mavsplus.java8.turtorial.annotation;

          import java.lang.annotation.Documented;
          import java.lang.annotation.ElementType;
          import java.lang.annotation.Repeatable;
          import java.lang.annotation.Retention;
          import java.lang.annotation.RetentionPolicy;
          import java.lang.annotation.Target;

          /**
           * Annotations in Java 8 are repeatable
           * 
           * @author landon
           * @since 1.8.0_25
           
          */

          public class AnnotationRepeatableExample {

              
          // 包裝注解,其包括了Hint的數組
              
          // 這里必須加上@Retention(RetentionPolicy.RUNTIME),因為運行時反射要讀取該信息
              @Target(ElementType.TYPE)
              @Retention(RetentionPolicy.RUNTIME)
              @Documented
              
          public @interface Hints {
                  Hint[] value();
              }


              
          /**
               * <code>
               * 
               * @Documented
               * @Retention(RetentionPolicy.RUNTIME)
               * @Target(ElementType.ANNOTATION_TYPE) public @interface Repeatable {
               *                                      Class<? extends Annotation> value();
               *                                      } </code>
               *
               
          */


              
          // 實際的注解
              
          // 這里必須加上@Retention(RetentionPolicy.RUNTIME),因為運行時反射要讀取該信息
              @Target(ElementType.TYPE)
              @Retention(RetentionPolicy.RUNTIME)
              @Documented
              @Repeatable(Hints.class)
              
          public @interface Hint {
                  String str();
              }


              
          // 老辦法
              @Hints({ @Hint(str = "hint1"), @Hint(str = "hint2") })
              
          public class Bean {
              }


              
          // 新方法,使用可重復注解

              
          // 如果Hint注解沒有加上Repetable則會編譯錯誤
              
          // Only annotation types marked @Repeatable can be used multiple times at
              
          // one target.
              @Hint(str = "hint1")
              @Hint(str = "hint2")
              
          public class Bean2 {
              }


              
          // 使用變體2,Java編譯器能夠在內部自動對@Hint進行設置
              public void reflectAnnotation() throws Exception {
                  Hint hint = Bean2.class.getAnnotation(Hint.class);
                  
          // 輸出null
                  System.out.println(hint);

                  
          // 注意這里是$Bean
                  Hints hints3 = Class.forName("com.mavsplus.java8.turtorial.annotation.AnnotationRepeatableExample$Bean")
                          .getAnnotation(Hints.class);
                  
          // 輸出2
                  System.out.println(hints3.value().length);

                  Hints hints4 = Bean.class.getAnnotation(Hints.class);
                  
          // 輸出2
                  System.out.println(hints4.value().length);

                  
          // 這里傳入Hints.class依然可以獲取注解信息(因為Hint上有@Repeatable(Hints.class)這個注解)
                  
          // 盡管我們沒有在Bean2類上聲明@Hints注解,但是它的信息仍然可以通過getAnnotation(Hints.class)來讀取
                  Hints hints1 = Bean2.class.getAnnotation(Hints.class);
                  
          // 輸出2
                  System.out.println(hints1.value().length);

                  
          // getAnnotationsByType方法會更方便,因為它賦予了所有@Hint注解標注的方法直接的訪問權限。
                  
          // 看一下這段注釋:
                  
          // The difference between this method and getAnnotation(Class)
                  
          // is that this method detects if its argument is a repeatable
                  
          // annotation type (JLS 9.6), and if so, attempts to find one or more
                  
          // annotations of that type by "looking through" a container annotation
                  Hint[] hints2 = Bean2.class.getAnnotationsByType(Hint.class);
                  
          // 輸出2
                  System.out.println(hints2.length);
              }


              
          public static void main(String[] args) throws Exception {
                  AnnotationRepeatableExample example = new AnnotationRepeatableExample();

                  example.reflectAnnotation();
              }

          }



          package com.mavsplus.java8.turtorial.annotation;

          import java.lang.annotation.Documented;
          import java.lang.annotation.ElementType;
          import java.lang.annotation.Retention;
          import java.lang.annotation.RetentionPolicy;
          import java.lang.annotation.Target;

          /**
           * 和AnnotationRepeatableExample對比的一個例子
           * 
           * @author landon
           * @since 1.8.0_25
           
          */

          public class AnnotationExample {

              
          // 經測試發現,這段代碼要通過編譯, WrappedAnno中的方法名必須為value.
              
          // 同時參考了@Target源代碼以及@Retention源代碼,發現方法命名也為value.

              
          // 解釋(by landon)
              
          // 1.個人認為注解內部方法返回值如果為數組的話,如果方法名為value的話,可以不用寫類似于Anno(xxx =
              
          // {}),可直接寫Anno({}),參見AnnoModified2
              
          // 2.其實不一定返回值為數組,只要方法名定義為value的話,則賦值的話均無須指明value=xxx,參見AnnoModified3

              
          // 總結:編譯器默認注解內部方法名為value. 注:當且僅當注解內部只有一個方法時可以這樣,參見AnnoModified4

              @Target(ElementType.TYPE)
              @Retention(RetentionPolicy.RUNTIME)
              @Documented
              @interface WrappedAnno {
                  Anno[] value();
              }


              @Target(ElementType.TYPE)
              @Retention(RetentionPolicy.RUNTIME)
              @Documented
              @interface Anno {
                  String name();

                  
          int num();
              }


              @WrappedAnno({ @Anno(name = "value1", num = 1), @Anno(name = "value2", num = 2) })
              
          class AnnoModified {
              }


              @Target(ElementType.TYPE)
              @Retention(RetentionPolicy.RUNTIME)
              @Documented
              @
          interface WrappedAnno2 {
                  String[] values();
              }


              @Target(ElementType.TYPE)
              @Retention(RetentionPolicy.RUNTIME)
              @Documented
              @
          interface WrappedAnno3 {
                  
          int value();
              }


              @Target(ElementType.TYPE)
              @Retention(RetentionPolicy.RUNTIME)
              @Documented
              @
          interface WrappedAnno4 {
                  
          int value();

                  String name();
              }


              @WrappedAnno2(values 
          = "HI""Anno" })
              
          class AnnoModified2 {
              }


              @WrappedAnno3(
          2)
              
          class AnnoModified3 {
              }


              @WrappedAnno4(value 
          = 4, name = "Anno")
              
          class AnnoModified4 {
              }

          }


          posted on 2014-11-20 14:37 landon 閱讀(5631) 評論(0)  編輯  收藏 所屬分類: Program
          主站蜘蛛池模板: 会宁县| 郓城县| 安新县| 会泽县| 延寿县| 澄江县| 明溪县| 治县。| 高尔夫| 尉犁县| 和政县| 同仁县| 洪雅县| 铜鼓县| 乌兰察布市| 来安县| 和顺县| 武安市| 徐闻县| 阿巴嘎旗| 泾阳县| 原阳县| 乌鲁木齐市| 读书| 郁南县| 浦城县| 桃园市| 呼和浩特市| 天祝| 镇赉县| 滨州市| 临夏县| 台中市| 时尚| 山阴县| 明光市| 阿尔山市| 通化县| 普兰店市| 浑源县| 卓尼县|