New features of Java5

  java

Java language feature series

Order

This is the first in a series of Java language features, starting with the new features of java5. The original intention is to view the evolution history of language conveniently.

Property list

  • Generics
  • enumeration
  • Packing and unpacking
  • Variable length parameter
  • annotation
  • Foreach loop
  • Static import
  • Format
  • Thread Framework/Data Structure
  • Arrays tool class /StringBuilder/instrument

1. Generics

The so-called type erasure refers to that the pattern information in Java source code is only allowed to stay in the pre-compilation period, and no pattern information will be retained in the compiled bytecode file. In other words, the template information will be completely deleted at compile time, in which the type parameters of the template type will be replaced with Object type, and will be forcibly converted to the specified target data type when actually used. The template in C++ generates the corresponding object code according to the specified data type passed by the type parameter in the template type at compile time.

Map<Integer, Integer> squares = new HashMap<Integer, Integer>();
  • Wildcard Type: Avoid unchecked warnings. Question marks indicate that any type is acceptable.
public void printList(List<?> list, PrintStream out) throws IOException {
    for (Iterator<?> i = list.iterator(); i.hasNext(); ) {
      out.println(i.next().toString());
    }
  }
  • Type of restriction
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;
  }

2. Enumeration

  • 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 enumeration
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";
    }
  }

3. Autoboxing and Unboxing

Converts primitive type to corresponding wrapper type: Boolean, Byte, Short, Character, Integer, Long, Float, Double

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

The output of m1(1) is double, and the method is compatible offline when matching, regardless of boxing and unboxing.

4、vararg

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

5、annotation

  • Inherited indicates whether the annotation has effect on methods inherited by subclasses of the class, etc.
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InProgress { }
  • Specify Target
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,
         ElementType.METHOD, 
         ElementType.CONSTRUCTOR, 
         ElementType.ANNOTATION_TYPE})
public @interface TODO { 
  String value();
}
  • Target type
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 indicates whether the annotation remains in the compiled class file or is readable at run time.
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
}
  • Meta-information is acquired by reflection
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();
    } 
  }
}

6、for/in

What the for/in loop cannot do:
(1) traversing and acquiring index at the same time
(2) remove the last one when assembling commas
(3) delete elements while traversing

7. Static 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();
    }
  }
}

8. Format

/**
 * 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();
    }
}

9、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;
      }
    }
  }
}
  • Thread pool

The famous JUC class library.

  • Each time a task is submitted, if the number of threads has not reached coreSize, a new thread is created and the task is bound. Therefore, the total number of threads must reach coreSize after the task is submitted for the first coreSize, and the previous idle threads will not be reused.
  • After the number of threads reaches coreSize, the new tasks are put into the work queue, while the threads in the thread pool try to use take () to pull the work from the work queue.
  • If the queue is a bounded queue, and if the threads in the thread pool cannot take away the tasks in time, the work queue may be full and the inserted tasks will fail. At this time, the thread pool will urgently create new temporary threads to remedy the situation.
  • Temporary threads use poll(keepAliveTime, timeUnit) to pull jobs from the work queue. if the time comes and they still don’t pull jobs with empty hands, it indicates that they are too idle and will be fired.
  • If the number of core threads+temporary threads > maxSize, no new temporary threads can be created and RejectExecutionHanlder will be executed instead. The default AbortPolicy throws a RejectedExecutionExcept ion exception. Other options include silently discarding the current task, discarding the oldest task in the work queue, or directly executing it by the main thread (CallerRuns), or writing one by your imagination.

10. Other

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

Avoid the add/remove operation of the collection and use the offer and poll operations (do not throw exceptions)

Queue q = new LinkedList(); 采用它来实现queue
  • Override return type

Support covariant return

  • Single-threaded StringBuilder

Thread is unsafe, replacing string buffer under single thread improves performance.

  • java.lang.instrument

References