JDK 7 新特性

Improved Type Inference

i. Constructors

The addition of generics to the language greatly improved compile time type checking and largely eliminated the need for casting.  Unfortunately it also increased the verbosity of declarations, for example:

    Map<String, List<String>> anagrams = new HashMap<String, List<String>>();

As a result, generic declarations often require multiple lines. It would be nice if you could omit the second occurrence of the type parameters (<String, List<String>>) and let the compiler figure it out ("constructor type inference"). This would remove the redundancy from the declaration, geatly enhancing readability and ease-of-use:

    Map<String, List<String>> anagrams = new HashMap<>();

See also http://gafter.blogspot.com/2007/07/constructor-type-inference.html

ii. Argument Positions

The result of a generic method, such as:

    public <E> Set<E> emptySet() { ... }

may be used on the right-hand side of an assignment:

    Set<Person> honestPoliticians = Collections.emptySet();

The compiler's type-inference mechanism figures out that the type parameter to the emptySet invocation is Person.  It seems reasonable that the compiler should be able to infer the type when the result of such a generic method invocation is passed to another method:

    void timeWaitsFor(Set<Man> people) { ... }

       ...

    timeWaitsFor(Collections.emptySet());  // * Won't compile!

Sadly, this is not allowed.  The specification currently requires an explicit type argument under these circumstances:

    timeWaitsFor(Collections.<Man>emptySet());

Not only are explicit type arguments awkward, but many programmers are unfamiliar with them and unable to cope when the compiler requires them.  With inference in argument positions, the explicit type argument is rarely required and the starred method invocation above becomes legal.

See also http://lampwww.epfl.ch/~odersky/ftp/local-ti.ps and http://www.javac.info/Inference.html

Enum Comparison

Enum constants can safely be compared for equality use the == operator.  All enum types implement Comparable, so it stands to reason that it should be possible to compare constants of an enumerated type for order using the <, >, <=, and >= operators.  Unfortunately, it isn't, so programmers are forced to litter their code with calls to the compareTo method:

    enum Size { SMALL, MEDIUM, LARGE }

    if (mySize.compareTo(yourSize) >= 0)

        System.out.println("You can wear my shirt.");

If the <, >, <=, and >= operators worked for enums, this code could be replaced by the clearer:

    if (mySize >= yourSize)

        System.out.println("You can wear my shirt.");

See also http://www.javac.info/EnumCompare.html

String Switch

Information often comes into programs in string form, and some action (often translation into another form) takes place depending on the string value.  For example, the following method translates strings to boolean values:

     static boolean booleanFromString(String s) {
        if (s.equals("true")) {
            return true;
        } else if (s.equals("false")) {
            return false;
        } else {
            throw new IllegalArgumentException(s);
        }
     }

This code is not pretty, and somewhat bug-prone.  If it were possible to switch on string values, this code could be replaced by the prettier and safer:

     static boolean booleanFromString(String s) {
        switch(s) {
          case "true":
            return true;
          case "false":
            return false;
        }
        throw new IllegalArgumentException(s);
    }

See also http://yost.com/computers/java/string-switch/index.html

Chained Invocations

Some mutation-based APIs have a number of methods that return void. This is common in the factory pattern:

    class Factory {

        void setSomething(Something something) { ... }

        void setOther(Other other) { ... }

        Thing result() { ... }

    }

Using such a class can be awkward

    Factory fac = new Factory();

    fac.setSomething(something);

    fac.setOther(other);
    Thing thing = fac.result();

With chained invocations, you can reuse the receiver of the previous invocation and chain the calls together:

    Thing thing = new Factory()

        .setSomething(something)

        .setOther(other)

        .result();
With this language support, it is much easier to define "fluent" APIs.

See also http://docs.google.com/View?docid=dg8rbgp8_0gnjwr2

Extension methods

Existing interfaces cannot be extended with additional methods without breaking some clients. Instead, functionality is typically "added to an interface" by static methods in a separate utility class. Using them is somewhat awkward:

    List<String> list = ...;

    Collections.sort(list);

With extension methods, client can designate utility methods to act as if they were members of the interface (or class)

    import static java.util.Collections.sort;

    list.sort();


See also http://www.javac.info/ExtensionMethods.html

Improved Catch Clauses 

i. Catching Multiple Exception Types

It is often necessary to do the same thing when one of several exceptions occurs.  Currently the only way to do this is to duplicate code in multiple catch clauses:

    try {
        return klass.newInstance();
    } catch (InstantiationException e) {
        throw new AssertionError(e);
    } catch (IllegalAccessException e) {
        throw new AssertionError(e);
    }

It may be tempting to replace several catch clauses with one for the class that is the "least common ancestor" of the each of the exception types in question:

    // Broken - catches exceptions that should be allowed to propagate! 

    try {
        return klass.newInstance();
    } catch (Exception e) {
        throw new AssertionError(e);
    }

Unfortunatley this does not have the correct semantics. In the case of this example, it erroneously wraps unchecked exceptions in assertion errors.  To solve this problem, we propose that it be possible to catch two or more exception types in a single catch clause:

    try {
        return klass.newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
        throw new AssertionError(e);
    }


See also http://www.javac.info/Multicatch.html

ii. Improved Checking for Rethrown Exceptions

It is not uncommon that you want to catch an exception, perform some action, and rethrow the exception:

    try {

        doable.doIt();  // Specified to throw several different exceptions

    } catch (Throwable ex) {

        logger.log(ex);

        throw ex;  // Won't compile unless method is specified to throw Throwable!

    }

Unfortunately, it is not generally possible to do this, as the resulting catch clause throws the type of exception that was caught, which the enclosing method is typically not specified to throw.  To get around this, programmers often wrap the exception prior to rethrowing it:

    try { 
        doable.doIt();

    } catch (Throwable ex) {

        logger.log(ex);

        throw new WrappedException(ex);  // Obscures exception type!

    }

If a caught exception is declared final, it is safe to rethrow any caught exception:

    try {

        doable.doIt();

    } catch (final Throwable ex) {

        logger.log(ex);

        throw ex;

    }

Because the catch parameter is final, it can only hold exceptions that are thrown from the try block. Exception checking should take advantage of that fact: the compiler should treat this rethrown exception as if it can throw only checked exceptions that occur in the try block.

 
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值