站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2SE 专题J2SE 5.0 新特性

J2SE 5.0 新特性

摘要: J2SE 5.0 新特性

The Tiger feature list is defined in JSR-176 (J2SE 5.0 (Tiger) Release Content), which serves as an umbrella JSR that only lists APIs defined in other component JSRs. Please see JSR-176 for details about the component JSRs.

The J2SE 5.0 release includes several new language features. The rest of this article discusses these language features and shows how to use them to improve programs.


Generics

<table class="grey4" cellspacing="0" cellpadding="0" width="100%" border="0"><tr><td></td></tr></table>

To the most despised collections' cast
We'll bid a fond farewell at last
With generics' burning spear
The need for cast will disappear

The Collection interface, which is implemented by all collection classes, suggests that all concrete collections are collections of Objects at runtime. This places a burden on the developer of the calling class by forcing him to know the actual type of the elements in the collections, that can be accomplished by looking at the API or using the reflection API. As an example, consider the following class, Ex1, which creates a collection of two strings and one integer, and then prints out the collection:

Ex1.java BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

import java.util.*;public class Ex1 {  private void testCollection() {    List list = new ArrayList();    list.add(new String("Hello world!"));    list.add(new String("Good bye!"));    list.add(new Integer(95));    printCollection(list);  }  private void printCollection(Collection c) {    Iterator i = c.iterator();    while(i.hasNext()) {      String item = (String) i.next();      System.out.println("Item: "+item);    }  }  public static void main(String argv[]) {    Ex1 e = new Ex1();    e.testCollection();  }}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

The problem here is that an explicit cast is required in the printCollection method. This class compiles fine, but throws a CLassCastException at runtime as it attempts to cast an Integer to a String:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

Item: Hello world!Item: Good bye!Exception in thread "main" java.lang.ClassCastException: java.lang.Integer        at Ex1.printCollection(Ex1.java:16)        at Ex1.testCollection(Ex1.java:10)        at Ex1.main(Ex1.java:23)
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Generics, which are also known as parameterized types, provide compile-time typesafety for collections and eliminate the drudgery of casting. Using generics, the Ex1 class above can be written as follows:

Ex2.java

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

import java.util.*;public class Ex2 {  private void testCollection() {    List list = new ArrayList();    list.add(new String("Hello world!"));    list.add(new String("Good bye!"));    list.add(new Integer(95));    printCollection(list);  }  private void printCollection(Collection c) {    Iterator i = c.iterator();    while(i.hasNext()) {      String item = i.next();      System.out.println("Item: "+item);    }  }  public static void main(String argv[]) {    Ex2 e = new Ex2();    e.testCollection();  }}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Now, if you try to compile this code, a compile-time error will be produced, informing you that you cannot add an Integer to a collection of Strings. Therefore, generics enable more compile-time type checking and therefore mismatch errors are caught at compile time rather than at runtime.

You may have already noticed the new syntax used to create an instance of ArrayList (i.e. List list = new ArrayList). ArrayList is now a generic or parameterized type. A parameterized type consists of a class or interface E and a parameter section , which must match the number of declared parameters of E, and each actual parameter must be a subtype of the formal parameter's bound types. The following segment of code shows parts of the new class definition for ArrayList:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, Serializable {   // ...}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Here E is a type variable, which is an unqualified identifier. It simply acts as a placeholder for a type to be defined when the list is used.

Java Generics vs. C++ Templates

While generics look like the C++ templates, it is important to note that they are not the same. Generics simply provide compile-time type safety and eliminate the need for casts. The main difference is encapsulation: errors are flagged where they occur and not later at some use site, and source code is not exposed to clients. Generics use a technique known as type erasure as described above, and the compiler keeps track of the generics internally, and all instances use the same class file at compile/run time.

A C++ template on the other hand is just a fancy macro processor; whenever a template class is instantiated with a new class, the entire code for the class is reproduced and recompiled for the new class.


Enhanced for Loop

<table class="grey4" cellspacing="0" cellpadding="0" width="100%" border="0"><tr><td></td></tr></table>

While Iterators have their uses
They sometimes strangle us like nooses
With enhanced-for's deadly ray
Iterator's kept at bay

The current for statement is quite powerful and can be used to iterate over arrays or collections. However, it is not optimized for collection iteration, simply because the iterator serves no other purpose than getting elements out of the collection. The new enhanced for construct lets you iterate over collections and arrays without using iterators or index variables.

The new form of the for statement has the following syntax:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>for (FormalParameter : Expression) Statement </td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Note that Expression must be an array or an instance of a new interface called java.lang.Iterable, which is meant to ease the task of enabling a type for use with the enhanced for statement. This means that the java.util.Collection now extends the Iterable interface that has the following signature:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

package java.lang;public interface Iterable {      /**        * Returns an iterator over the elements in this collection.        * There are no guarantees concerning the order in which the elements        * are returned (unless this collection is an instance of some class        * that provides such a guarantee).        *         * @return an iterator over the elements in this collection        */       Iterator iterator();}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

As an example, consider the following method that uses the conventional for statement to iterate over a collection:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

// Assume we have an instance of StringBuffer "sb"public void oldFor(Collection c) {  for(Iterator i = c.iterator(); i.hasNtext(); ) {    String str = (String) i.next();    sb.append(str);  }}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

With the addition of generics, the above segment of code can be rewritten using the enhanced for statement as follows:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

// Assume we have an instance of StringBuffer "sb"public void newFor(Collection c) {  for(String str : c) {    sb.append(str);  }}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Much cleaner, eh?

The enhanced for statement can be used to iterate over an array. Consider the following segment of code for a method that calculates the sum of the elements in an array:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

public int sumArray(int array[]) {  int sum = 0;  for(int i=0;i</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Using the enhanced for statement, this can be rewritten as:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

public int sumArray(int array[]) {  int sum = 0;  for(int i : array) {    sum += i;  }  return sum;}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

The new for statement, however, is not a replacement for counting for loops for arrays. Sometimes, the index variable serves more than just an array index -- when a different traversal order is needed, for example. In addition, the enhanced for construct is a compiler 'trick' and can actually end up being slower when used for large collections.

Many developers are asking why they didn't add the foreach and in so that we can write:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>foreach (element in collection) </td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

The fact of the matter is that adding new keywords to a language such as Java is quite costly. In addition, it wouldn't be compatible with existing source code that uses the in keyword, for example, as in System.in. So the whole idea is just to keep things upwardly-compatible.


Autoboxing/Unboxing

<table class="grey4" cellspacing="0" cellpadding="0" width="100%" border="0"><tr><td></td></tr></table>

When from the collections ints are drawn
Wrapper classes make us mourn
When Tiger comes, we'll shed no tears
We'll autobox them in the ears

Manual conversion between primitive types (such as an int) and wrapper classes (such as Integer) is necessary when adding a primitive data type to a collection. As an example, consider an int being stored and then retrieved from an ArrayList:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

list.add(0, new Integer(59));int n = ((Integer)(list.get(0))).intValue();
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

The new autoboxing/unboxing feature eliminates this manual conversion. The above segment of code can be written as:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

list.add(0, 59);int total = list.get(0);
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

However, note that the wrapper class, Integer for example, must be used as a generic type:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>List list = new ArrayList(); </td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Programming language critics may have a lot to say about the autoboxing/unboxing feature. On one hand, Java developers agree that the distinction between primitive data types and references can be burdensome. In a pure object-oriented language there should be no difference between a primitive data type and a reference, as everything is an object. The other issue is that of identity: many think of primitive data types as entities that represent mathematical values, which are different from references.

The purpose of the autoboxing/unboxing feature, however, is simply to ease the interoperability between primitive types and references without any radical changes.


Typesafe Enumerations

<table class="grey4" cellspacing="0" cellpadding="0" width="100%" border="0"><tr><td></td></tr></table>

The int-enum will soon be gone
Like a foe we've known too long.
With type safe-enum's mighty power
Our foe will bother us no more

An enumerated type is a type whose values consist of a fixed set of constants. The C-style enumerated type, enum was omitted from the Java programming language. A commonly used pattern for enumerated types in Java is to define a class of constants as follows:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

public class MainMenu {  public static final int MENU_FILE   = 0;  public static final int MENU_EDIT   = 1;  public static final int MENU_FORMAT = 2;  public static final int MENU_VIEW   = 3;}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

This pattern has several drawbacks including:

  1. It is not type safe
  2. Constants are compiled into clients and therefore adding more constants require recompilation of the clients
  3. It has no namespace and therefore must prefix constants
  4. Provides no easy way to translate the constants into informative printable values

In addition to the above, and as we all know, an object is an instance of a class. An object has state (represented by variables) and behavior (represented by methods). The above MainMenu class has state only. So from an object-oriented point of view, it is not really a class since its instances or objects would have no behavior.

A type safe enum pattern that avoids all of the above problems has been proposed by Joshua Bloch in his book "Effective Java Programming Language Guide". The idea is to define an enum as a class that represents a single element of the enumerated type; such a class must not provide public constructors. Here is an example:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

public class MainMenu {  private final String name;  private MainMenu(String name) {    this.name = name;  }  public static final MainMenu FILE = new MainMenu("file");  public static final MainMenu EDIT = new MainMenu("edit");  public static final MainMenu FORMAT = new MainMenu("format");  public static final MainMenu VIEW = new MainMenu("view");  public String toString() {    return name;  }}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Using MainMenu, there is no way for a client to create an object of the class or extend it. This is a compile-time typesafe enumerated type: it is guaranteed that if you declare a method with a parameter of type MainMenu, then any non-null object reference passed in represents one of the four valid menu items. Any attempt to pass an incorrectly-typed object results in a compile-time error. In addition, this is a truly object-oriented class as it contains both state and behavior.

In J2SE 5.0, however, you do not need to worry about inventing your own enumeration patterns since it provides a typesafe enumerated type facility. The J2SE 5.0 enum declaration looks as follows:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>public enum MainMenu {FILE, EDIT, FORMAT, VIEW}; </td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

This syntax looks much like enums in other languages such as C/C++, but in C/C++ enums are simply glorified integers where in Java a full-fledged class is generated for each enum type. This approach has many advantages including:

  1. It provides strong compile-time type safety
  2. It provides a separate namespace for each enum type and thus eliminates the need to include a prefix in each constant name
  3. Constants are not compiled into clients so you can freely add, remove, or reorder them without recompiling the clients
  4. Printed values are informative instead of just numbers
  5. Enum constants can be used wherever objects can be used

There are a couple of important things to note about enum declarations. As an example, consider the following declaration:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>public enum MainMenu {FILE, EDIT, FORMAT, VIEW}; </td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

  1. The word enum is reserved and therefore if you have been using it as an identifier, you should adjust your code when compiling with a J2SE 5.0 compiler.
  2. The above enum declaration generates a class (MainMenu in the above example), which automatically implements the Comparable and Serializable interfaces, and provides several members including:
    • Static variables FILE, EDIT, FORMAT, and VIEW
    • Static method values(), which is an array containing the constants in the enum
    • static method valueOf(String) that returns the appropriate enum for the string passed in
    • Appropriately overloaded equals(), hasCode, toString(), and compareTo() methods.

Here is a complete example that declares an enumeration and then prints the values:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

public class Example {  public enum MainMenu {FILE, EDIT, FORMAT, VIEW}  public static void main(String[] argv) {    for (MainMenu menu : MainMenu.values())       System.out.println(menu);      }}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

And the following segment of code shows another example using the switch statement:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

for(MainMenu menu : MainMenu.values()) {  switch(menu) {    case FILE:      System.out.println("FILE Menu");      break;    case EDIT:      System.out.println("EDIT Menu");      break;    case FORMAT:      System.out.println("FORMAT Menu");      break;    case VIEW:      System.out.println("VIEW Menu");      break;  }}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

It is worth noting that two classes have been added to java.util in support of enums: EnumSet (a high-performance Set implementation for enums; all members of an enum set must be of the same enum type) and EnumMap (a high-performance Map implementation for use with enum keys).

Static Imports

<table class="grey4" cellspacing="0" cellpadding="0" width="100%" border="0"><tr><td></td></tr></table>

And from the constant interface
We shall inherit no disgrace
With static import at our side
Our joy will be unqualified

The static import feature enables you to import static members from a class or an interface and thus use them without a qualifying name. As an example, consider the following interface that contains two constant values:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

package com.name;interface XYZ {  public static final double Constant1 = someValue;  public static final double Constant2 = anotherValue;}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Now, the constants in the XYZ interface can be used as follows:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

public class MyClass implements XYZ {  ....  double value = 2 * Constant1;  ...}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

As you can see, a class must implement the interface in order to have access to the constants defined in the interface.

In J2SE 5.0, static import solves this problem as shown in the following example:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

import static com.name.XYZ.*;public class MyClass {  ...  double value = 2 * Constant1;  ...}
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

As another example, consider the following static imports:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

import static java.lang.Math.*;import static java.lang.System.*;
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

With these two static imports, you now can use sin(x) instead of Math.sin(x), and out.println("Hello there"); instead of System.out.println("Hello there");.


Metadata

<table class="grey4" cellspacing="0" cellpadding="0" width="100%" border="0"><tr><td></td></tr></table>

As for noble metadata
I'll have to sing its praises later
Its uses are so numerous
To give their due, I'd miss the bus

The J2SE 5.0 metadata feature is a facility that allows developers to annotate their code so that tools can generate boilerplate code (e.g stub generation to remote procedure calls) as directed by annotations. This facility allows for parsing of your Java files and generating artifacts such as XML descriptors or source code. For more information on the metadata facility, please see A Metadata Facility for the Java Programming Language.


Others

<table class="grey4" cellspacing="0" cellpadding="0" width="100%" border="0"><tr><td></td></tr></table>

In addition to the new language constructs and features, several other enhancements have been introduced. This section provides an overview of some of the significant enhancements.

Variable Arguments:

O joyless nights, o joyless days
Our programs cluttered with arrays
With varargs here, we needn't whine;
We'll simply put the args inline

The variable arguments new functionality in J2SE 5.0 allows multiple arguments to be passed as parameters to methods as in:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

void someMethod(Object ... args) {   // do something}// invoke the methodsomeMethod("arg1", "arg2", "arg3");
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

The notation ... is required. The printf statement, which is discussed later, is an example of using variable arguments.

Formatted Output: The variable arguments functionality has been used to implement the flexible number of arguments required for printf. That is right! J2SE 5.0 provides C-like printf functionality, so now it is possible to easily format output using printf:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>System.out.printf("%s %3d", name, age); </td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Enhanced Input: Prior to J2SE 5.0, in order to read an integer value from the keyboard, it has to be read as a String and then parsed as follows (this code doesn't include the try and catch constructs):

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String str = br.readLine();int n = Integer.parseInt(str);
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

In J2SE 5.0, the java.util.Scanner class can be used to accomplish the same thing but with less code as follows:

BEGIN VCD7 CODE SAMPLE COMPONENT <table class="grey4" cellspacing="0" cellpadding="10" width="100%" border="0"><tr><td>

Scanner reader = new Scanner(System.in);int n = reader.nextInt();
</td></tr></table>
END VCD7 CODE SAMPLE COMPONENT

Programming educators are going to love this enhanced input functionality, as it will make it easy to explain how to read primitive data types from the keyboard.

If you need to process more complex input, use the java.util.Formatter class, which includes pattern matching algorithms.

Synchronization: J2SE 5.0 provides higher-level synchronization constructs in the form of a comprehensive library of concurrency utilities (java.util.concurrent) containing thread pools, queues, concurrent collection, special purpose locks, and barriers. This is a substantial addition that will change the way we develop concurrent Java applications. Stay tuned for an article that explains this new functionality.




↑返回目录
前一篇: J2SE(TM) 5.0专题之语言特性
后一篇: J2SE 5.0的新特性---Autoboxing