Java5的新特性

Java語言特性系列

這是Java語言特性系列的第一篇,從java5的新特性開始講起。初衷就是能夠方便的查看語言的演進歷史。html

特性列表

  • 泛型
  • 枚舉
  • 裝箱拆箱
  • 變長參數
  • 註解
  • foreach循環
  • 靜態導入
  • 格式化
  • 線程框架/數據結構
  • Arrays工具類/StringBuilder/instrument

一、泛型

所謂類型擦除指的就是Java源碼中的範型信息只容許停留在編譯前期,而編譯後的字節碼文件中將再也不保留任何的範型信息。也就是說,範型信息在編譯時將會被所有刪除,其中範型類型的類型參數則會被替換爲Object類型,並在實際使用時強制轉換爲指定的目標數據類型。而C++中的模板則會在編譯時將模板類型中的類型參數根據所傳遞的指定數據類型生成相對應的目標代碼。java

Map<Integer, Integer> squares = new HashMap<Integer, Integer>();
  • 通配符類型:避免unchecked警告,問號表示任何類型均可以接受
public void printList(List<?> list, PrintStream out) throws IOException {
    for (Iterator<?> i = list.iterator(); i.hasNext(); ) {
      out.println(i.next().toString());
    }
  }
  • 限制類型
public static <A extends Number> double sum(Box<A> box1,Box<A> box2){
    double total = 0;
    for (Iterator<A> i = box1.contents.iterator(); i.hasNext(); ) {
      total = total + i.next().doubleValue();
    }
    for (Iterator<A> i = box2.contents.iterator(); i.hasNext(); ) {
      total = total + i.next().doubleValue();
    }
    return total;
  }

二、枚舉

  • EnumMap
public void testEnumMap(PrintStream out) throws IOException {
    // Create a map with the key and a String message
    EnumMap<AntStatus, String> antMessages =
      new EnumMap<AntStatus, String>(AntStatus.class);
    // Initialize the map
    antMessages.put(AntStatus.INITIALIZING, "Initializing Ant...");
    antMessages.put(AntStatus.COMPILING,    "Compiling Java classes...");
    antMessages.put(AntStatus.COPYING,      "Copying files...");
    antMessages.put(AntStatus.JARRING,      "JARring up files...");
    antMessages.put(AntStatus.ZIPPING,      "ZIPping up files...");
    antMessages.put(AntStatus.DONE,         "Build complete.");
    antMessages.put(AntStatus.ERROR,        "Error occurred.");
    // Iterate and print messages
    for (AntStatus status : AntStatus.values() ) {
      out.println("For status " + status + ", message is: " +
                  antMessages.get(status));
    }
  }
  • switch枚舉
public String getDescription() {
    switch(this) {
      case ROSEWOOD:      return "Rosewood back and sides";
      case MAHOGANY:      return "Mahogany back and sides";
      case ZIRICOTE:      return "Ziricote back and sides";
      case SPRUCE:        return "Sitka Spruce top";
      case CEDAR:         return "Wester Red Cedar top";
      case AB_ROSETTE:    return "Abalone rosette";
      case AB_TOP_BORDER: return "Abalone top border";
      case IL_DIAMONDS:   
        return "Diamonds and squares fretboard inlay";
      case IL_DOTS:
        return "Small dots fretboard inlay";
      default: return "Unknown feature";
    }
  }

三、Autoboxing與Unboxing

將primitive類型轉換成對應的wrapper類型:Boolean、Byte、Short、Character、Integer、Long、Float、Doublesegmentfault

public static void m1(Integer i){
        System.out.println("this is integer");
    }
    public static void m1(double d){
        System.out.println("this is double");
    }

m1(1)輸出的是double,方法匹配時線下兼容,不考慮boxing與unboxing。安全

四、vararg

private String print(Object... values) {
    StringBuilder sb = new StringBuilder();
    for (Object o : values) {
      sb.append(o.toString())
        .append(" ");
    }
    return sb.toString();
  }

五、annotation

  • Inherited表示該註解是否對類的子類繼承的方法等起做用
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }
  • 指定Target
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,
         ElementType.METHOD, 
         ElementType.CONSTRUCTOR, 
         ElementType.ANNOTATION_TYPE})
public @interface TODO { 
  String value();
}
  • Target類型
public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,
    /** Field declaration (includes enum constants) */
    FIELD,
    /** Method declaration */
    METHOD,
    /** Parameter declaration */
    PARAMETER,
    /** Constructor declaration */
    CONSTRUCTOR,
    /** Local variable declaration */
    LOCAL_VARIABLE,
    /** Annotation type declaration */
    ANNOTATION_TYPE,
    /** Package declaration */
    PACKAGE
}
  • rentation表示annotation是否保留在編譯過的class文件中仍是在運行時可讀。
public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,
    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,
    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}
  • 經過反射獲取元信息
public class ReflectionTester {
  public ReflectionTester() {
  }
  public void testAnnotationPresent(PrintStream out) throws IOException {
    Class c = Super.class;
    boolean inProgress = c.isAnnotationPresent(InProgress.class);
    if (inProgress) {
      out.println("Super is In Progress");
    } else {
      out.println("Super is not In Progress");
    }
  }
  public void testInheritedAnnotation(PrintStream out) throws IOException {
    Class c = Sub.class;
    boolean inProgress = c.isAnnotationPresent(InProgress.class);
    if (inProgress) {
      out.println("Sub is In Progress");
    } else {
      out.println("Sub is not In Progress");
    }
  }
  public void testGetAnnotation(PrintStream out) 
    throws IOException, NoSuchMethodException {
    Class c = AnnotationTester.class;
    AnnotatedElement element = c.getMethod("calculateInterest", 
                                  float.class, float.class);
    GroupTODO groupTodo = element.getAnnotation(GroupTODO.class);
    String assignedTo = groupTodo.assignedTo();
    out.println("TODO Item on Annotation Tester is assigned to: '" + 
        assignedTo + "'");
  }
  public void printAnnotations(AnnotatedElement e, PrintStream out)
    throws IOException {
    out.printf("Printing annotations for '%s'%n%n", e.toString());
    Annotation[] annotations = e.getAnnotations();
    for (Annotation a : annotations) {
      out.printf("    * Annotation '%s' found%n", 
        a.annotationType().getName());
    }
  }
  public static void main(String[] args) {
    try {
      ReflectionTester tester = new ReflectionTester();
      tester.testAnnotationPresent(System.out);
      tester.testInheritedAnnotation(System.out);
      tester.testGetAnnotation(System.out);
      Class c = AnnotationTester.class;
      AnnotatedElement element = c.getMethod("calculateInterest", 
                                    float.class, float.class);      
      tester.printAnnotations(element, System.out);
    } catch (Exception e) {
      e.printStackTrace();
    } 
  }
}

六、for/in

for/in循環辦不到的事情:
(1)遍歷同時獲取index
(2)集合逗號拼接時去掉最後一個
(3)遍歷的同時刪除元素數據結構

七、靜態import

import static java.lang.System.err;
import static java.lang.System.out;
import java.io.IOException;
import java.io.PrintStream;
public class StaticImporter {
  public static void writeError(PrintStream err, String msg) 
    throws IOException {
   
    // Note that err in the parameter list overshadows the imported err
    err.println(msg); 
  }
  public static void main(String[] args) {
    if (args.length < 2) {
      err.println(
        "Incorrect usage: java com.oreilly.tiger.ch08 [arg1] [arg2]");
      return;
    }
    out.println("Good morning, " + args[0]);
    out.println("Have a " + args[1] + " day!");
    try {
      writeError(System.out, "Error occurred.");
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

八、格式化

/**
 * java.text.DateFormat
 * java.text.SimpleDateFormat
 * java.text.MessageFormat
 * java.text.NumberFormat
 * java.text.ChoiceFormat
 * java.text.DecimalFormat
 */
public class FormatTester {
    public static void printf() {
        //printf
        String filename = "this is a file";
        try {
            File file = new File(filename);
            FileReader fileReader = new FileReader(file);
            BufferedReader reader = new BufferedReader(fileReader);
            String line;
            int i = 1;
            while ((line = reader.readLine()) != null) {
                System.out.printf("Line %d: %s%n", i++, line);
            }
        } catch (Exception e) {
            System.err.printf("Unable to open file named '%s': %s",
                    filename, e.getMessage());
        }
    }
    public static void stringFormat() {
        // Format a string containing a date.
        Calendar c = new GregorianCalendar(1995, MAY, 23);
        String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
        // -> s == "Duke's Birthday: May 23, 1995"
        System.out.println(s);
    }
    public static void formatter() {
        StringBuilder sb = new StringBuilder();
        // Send all output to the Appendable object sb
        Formatter formatter = new Formatter(sb, Locale.US);
        // Explicit argument indices may be used to re-order output.
        formatter.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d");
        // -> " d  c  b  a"
        // Optional locale as the first argument can be used to get
        // locale-specific formatting of numbers.  The precision and width can be
        // given to round and align the value.
        formatter.format(Locale.FRANCE, "e = %+10.4f", Math.E);
        // -> "e =    +2,7183"
        // The '(' numeric flag may be used to format negative numbers with
        // parentheses rather than a minus sign.  Group separators are
        // automatically inserted.
        formatter.format("Amount gained or lost since last statement: $ %(,.2f",
                6217.58);
        // -> "Amount gained or lost since last statement: $ (6,217.58)"
    }
    public static void messageFormat() {
        String msg = "歡迎光臨,當前({0})等待的業務受理的顧客有{1}位,請排號辦理業務!";
        MessageFormat mf = new MessageFormat(msg);
        String fmsg = mf.format(new Object[]{new Date(), 35});
        System.out.println(fmsg);
    }
    public static void dateFormat(){
        String str = "2010-1-10 17:39:21";
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        try {
            System.out.println(format.format(format.parse(str)));
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        formatter();
        stringFormat();
        messageFormat();
        dateFormat();
        printf();
    }
}

九、threading

  • uncaught exception
public class BubbleSortThread extends Thread {
  private int[] numbers;
  public BubbleSortThread(int[] numbers) {
    setName("Simple Thread");
    setUncaughtExceptionHandler(
      new SimpleThreadExceptionHandler());
    this.numbers = numbers;
  }
  public void run() {
    int index = numbers.length;
    boolean finished = false;
    while (!finished) {
      index--;
      finished = true;
      for (int i=0; i<index; i++) {
        // Create error condition
        if (numbers[i+1] < 0) {
          throw new IllegalArgumentException(
            "Cannot pass negative numbers into this thread!");
        }
        if (numbers[i] > numbers[i+1]) {
          // swap
          int temp = numbers[i];
          numbers[i] = numbers[i+1];
          numbers[i+1] = temp;
          finished = false;
        }
      }
    }    
  }
}
class SimpleThreadExceptionHandler implements
    Thread.UncaughtExceptionHandler {
  public void uncaughtException(Thread t, Throwable e) {
    System.err.printf("%s: %s at line %d of %s%n",
        t.getName(), 
        e.toString(),
        e.getStackTrace()[0].getLineNumber(),
        e.getStackTrace()[0].getFileName());
  }
}
  • blocking queue
public class Producer extends Thread {
  private BlockingQueue q;
  private PrintStream out;
  public Producer(BlockingQueue q, PrintStream out) {
    setName("Producer");
    this.q = q;
    this.out = out;
  }
  public void run() {
    try {
      while (true) {
        q.put(produce());
      }
    } catch (InterruptedException e) {
      out.printf("%s interrupted: %s", getName(), e.getMessage());
    }
  }
  private String produce() {
    while (true) {
      double r = Math.random();
      // Only goes forward 1/10 of the time
      if ((r*100) < 10) {
        String s = String.format("Inserted at %tc", new Date());
        return s;
      }
    }
  }
}
  • 線程池

著名的JUC類庫。oracle

  • 每次提交任務時,若是線程數還沒達到coreSize就建立新線程並綁定該任務。 因此第coreSize次提交任務後線程總數必達到coreSize,不會重用以前的空閒線程。
  • 線程數達到coreSize後,新增的任務就放到工做隊列裏,而線程池裏的線程則努力的使用take()從工做隊列里拉活來幹。
  • 若是隊列是個有界隊列,又若是線程池裏的線程不能及時將任務取走,工做隊列可能會滿掉,插入任務就會失敗,此時線程池就會緊急的再建立新的臨時線程來補救。
  • 臨時線程使用poll(keepAliveTime,timeUnit)來從工做隊列拉活,若是時候到了仍然兩手空空沒拉到活,代表它太閒了,就會被解僱掉。
  • 若是core線程數+臨時線程數 >maxSize,則不能再建立新的臨時線程了,轉頭執行RejectExecutionHanlder。默認的AbortPolicy拋RejectedExecutionException異常,其餘選擇包括靜默放棄當前任務(Discard),放棄工做隊列裏最老的任務(DisacardOldest),或由主線程來直接執行(CallerRuns),或你本身發揮想象力寫的一個。

十、其餘

  • Arrays
Arrays.sort(myArray);
Arrays.toString(myArray)
Arrays.binarySearch(myArray, 98)
Arrays.deepToString(ticTacToe)
Arrays.deepEquals(ticTacToe, ticTacToe3)
  • Queue

避開集合的add/remove操做,使用offer、poll操做(不拋異常)app

Queue q = new LinkedList(); 採用它來實現queue
  • Override返回類型

支持協變返回框架

  • 單線程StringBuilder

線程不安全,在單線程下替換string buffer提升性能dom

  • java.lang.instrument

參考

相關文章
相關標籤/搜索