Effective Java(Item: 38 to 56)

Six:Methods
Item 38: Check parameters for validity
Most methods and constructors have some restrictions on what values may be passed into their parameters. And constructors represent a special case of the principle that you should check the validity of parameters that are to be stored away for later use. I think follow this item is very easy. But do not inter from this item that arbitrary restrictions on parameters are a good thing. On the contrary, you should design methods to be as general as it is practical to make them. The fewer restrictions that you place on parameters, the better, assuming the method can do something reasonable with all of the parameter values that it accepts. Often, however, some restrictions are intrinsic to the abstraction being implemented.
Each time you write a method or constructor, you should think about what restrictions exist on its parameters,. You should document these restrictions and enforce them with explicit checks at the beginning of the method body. It is important to get into the habit of doing this. The modest work that it entails will be paid back with interest the first time a validity check fails.
For Example:

/*
 *Return a BigInteger whose value is(this mod m). This method
 *differs from the remainder method in that it always return a 
 *non-negative BigInteger
 *
 * @param m the modulus, which must be positive
 * @return this mod m
 * @throws ArithmeticException if m is less than or equal to 0
 */
public BigInteger mod(BigInteger m) {
    if(m.signum() <= 0)
        throw new ArithmeticException("Modulus <= 0" + m);
    ...//Do the computation
}
...
//Private helper function for a recursive sort
private static void sort(long a[], int offset, int length) {
    assert a != null;
    assert offset >=0 && offset <= a.length;
    assert length >=0 && length <= a.length - offset;
    ...//Do the computation
}
...

Item 39: Make defensive copies when needed
1).You must program defensively, with the assumption that clients of your class will do their best to destroy its invariants;
2).It is essential to make a defensive copy of each mutable parameter to the constructor;
3).Note that defensive copies are before checking the validity of the parameters, and the validity check is performed on the copies rather than on the originals;
4).Do not use the clone method to make a defensive copy of a parameter whose type is subclassable by untrusted parties;
5).Return defensive copies of mutable internal fields;
Arguably, the real reason in all of this is that you should, where possible, use immutable objects as components of your objects. If the cost of the copy would be prohibitive and the class trusts its clients not to modify the components inappropriately, then the defensive copy may be replaced by documentation outlining the client’s responsibility not to modify the affected components.
Example:

import java.util.Date;

public class DefensiveCopy {

    public static void main(String[] args) {
        Date start = new Date();
        Date end = new Date();
        Period p = new Period(start, end);
        //First attack - can be repaired in constructor
        //Attack the internals of a Period instance
        end.setYear(78);
        //Second attack - can be repaired in accessors method of Period
        //Attack on the internals of a Period instance
        p.end().setYear(78);
    }
}
//Broken "immutable" time period class
class Period {
    private final Date start;
    private final Date end;

    /**
     *@param start the beginning of the period
     *@param end the end of the period; must not precede start
     *@throws IllegalArgumentException if start is after end
     *@throws NullPointerException if start or end is null
     */

    /*
    public Period (Date start, Date end) {
        if (start.compareTo(end) > 0)
            throw new IllegalArgumentException(
                    start + " after " + end);
        this.start = start;
        this.end = end;
    }*/ 

    //Repaired constructor - make defensive copies of parameters
    public Period (Date start, Date end) {
        this.start = new Date(start.getTime());
        this.end = new Date(end.getTime());
        if (this.start.compareTo(this.end) > 0)
            throw new IllegalArgumentException(
                    start + " after " + end);
    }

    /*
    public Date start() {
        return start;
    }

    public Date end() {
        return end;
    }*/

    //Repaired accessors - make defensive copies of internal fields
    public Date start() {
        return new Date(start.getTime());
    }

    public Date end() {
        return new Date(end.getTime());
    }

}///:~

Item 40: Design method signatures carefully
Just follow these hits, they’ll help make your API easier to learn and use and less prone to errors.
1).Choose method names carefully;
2).Don’t go overboard in providing convenience methods;
3).Avoid long parameter lists. Long sequences of identically typed parameters are especially harmful;
(1).One is to break the method up into multiple methods;
(2).A second technique for shortening long parameter lists is to create helper classes to hold groups of parameters;
(3).A third technique that combines aspects of the first two is to adapt the Builder pattern from object construction to method invocation;
4).For parameter types, favor interfaces over classes;
5).Prefer two-element enum types to boolean parameters;

Item 41: Use overloading judiciously
1).About overloading, the choice of which overloading to invoke is made at compile time;
2).Selection among overloaded methods is static, while selection among overridden methods is dynamic;
3).Because overriding is the norm and overloading is the exception, overriding sets people’s exceptions for the behavior of method invocation. Overloading can easily confound these expectations. It is bad practice to write code whose behavior is likely to confuse programmers. Therefore you should avoid confusing uses of overloading.
4).A safe, conservative policy is never to export two overloadings with the same number of parameters.
5).For constructors, you don’t have the option of using different names;
6).Exporting multiple overloadings with the same number of parameters is nulikely to confuse programmers if it is always clear which overloading will apply to given set of actual parameters;
For Example:
1).

import java.util.*;

public class Overloading {

    public static void main(String[] args) {
        CollectionClassifier cc = new CollectionClassifier();
        Collection<?>[] collections = {
        new HashSet<String>(),
        new ArrayList<Integer>(),
        new HashMap<String, String>().values()
        };

        for(Collection<?> c : collections) 
            System.out.println(cc.classify(c));
    }
}

class CollectionClassifier {

    //Broken! - What does this program print?
    /*public static String classify(Set<?> s) {
        return "Set";
    }

    public static String classify(List<?> lst) {
        return "List";
    }

    public static String classify(Collection<?> c) {
        return "Unknown Collection";
    }
    Output:
    Unknown Collection
    Unknown Collection
    Unknown Collection
    *///:~

    //Repaired the problem
    public static String classify(Collection<?> c) {
        return c instanceof Set ? "Set" :
            c instanceof List ? "List" : "Unknown Collection";
    }/*Output:
    Set
    List 
    Unknown Collection
    *///:~
}

2).

class Wine {
    String name() { return "Wine"; }
}

class SparklingWine extends Wine {
    @Override String name() { return "Sparkling Wine"; }
}

class Champagne extends SparklingWine {
    @Override String name() { return "Champagne"; }
}

public class OverloadingSovledByOverride {
    public static void main(String[] args) {
        Wine[] wines = {
        new Wine(), new SparklingWine(), new Champagne() };
        for(Wine wine : wines)
            System.out.println(wine.name());
    }
}/*Output:
*///:~

3).Problem of autoboxing:

import java.util.*;

public class SetList {

    public static void main(String[] args) {
        Set<Integer> set = new TreeSet<Integer>();
        List<Integer> list = new ArrayList<Integer>();

        for(int i=-3; i<3; i++) {
            set.add(i);
            list.add(i);
        }
        /*Autoboxing problem
        for(int i=0; i<3; i++) {
            set.remove(i);
            list.remove(i);
        }Output:
        [-3, -2, -1][-2, 0, 2]
        *///:~
        //Repaired the problem that autoboxing carried
        for(int i=0; i<3; i++) {
            set.remove(i);
            list.remove((Integer) i);//or remove(Integer.valueOf(i))
        }
        System.out.println(set + "" + list);
    }

}/*Output:
[-3, -2, -1][-3, -2, -1]
*///:~

Item 42: Use varargs judiciously
Don’t retrofit every method that has a final array parameter; use varags only when a call really operates on a variable-length sequence of values. In summary, varargs methods are a convenient way to define method that require a variable number of arguments, but they should not be overused. They can produce confusing results if used inappropriately. And there are two ways you can handle varargs parameters. For example:

public class VarargsParameters {
    //The right way to use varargs to pass one or more arguments
    static int min(int firstArg, int... remainingArgs) {
        int min = firstArg;
        for (int arg : remainingArgs)
            if (arg < min)
                min = arg;
        return min;
    }
    /*
     *Suppose you've determined that 95 percent of the calls to a method have
     *three or fwewe parameters. Then declare five overloadings of the method,one each
     * with zero through three ordinary parameters, and a single varargs method for use 
     * when the number of arguments exceeds three:
     */
    public void foo() {}
    public void foo(int a1) {}
    public void foo(int a1, int a2) {}
    public void foo(int a1, int a2, int a3) {}
    public void foo(int a1, int a2, int a3, int... rest) {}
}///:~

Item 43: Return empty arrays or collections, not nulls
It is sometimes argued that a null return value is preferable to an empty array because it avoids the expense of allocating the array. This argument tails on two counts.
1).First, it is inadvisable to worry about performance at this level unless profiling has shown that the method in question is a real contributor to performance problems;
2).Second, it is possible to return the same zero-length array from every invocation that returns no items because zero-length arrays are immutable and immutable objects may be shared freely.
In a word, there is no reason ever to return null from an array- or collection-valued method instead of returning an empty array or collection.
Example:

public class EmptyArrays {
    //The right way to return an array from a collection
    private final List<Cheese> cheeseInStock = ...;
    private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
    /*
     *@return an array containing all of the cheese in the shop
     */
    public Cheese[] getCheese() {
        return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
    }

    //The right way to return a copy of a collection
    public List<Cheese> getCheeseList() {
        if(cheesesInStock.isEmpty())
            return Collections.emptyList();
        else
            return new ArrayList<Cheese>(cheesesInStock);
    }
}
…

Item 44: Write doc comments for all API elements
When you write Javadoc, you need to follow 4 hits:
1).To document your API properly, you must precede every exported class, interface, constructor, method, and field declaration with a doc comment.
2).The doc comment for a method should describe succinctly the contract between the method and its client.
3).It is no longer necessary to use the HTML or tags in doc comments: the Javadoc {@code} tag is preferable because it eliminates the need to escape HTML metacharacters.
4).No two members or constructors in a class or interface should have the same summary description.
How to write Javadoc for different aspects:
1).For methods and constructors, the summary description should be a full verb phrase(including any object) describing the action performed by the method.
2).For classes, interface, and fields, the summary description should be a noun phrase describing the thing represented by an instance of the class or intrface or by the field itself.
3).When documenting a generic type or method, be sure to document all type parameters.
4).When documenting an enum type, be sure to document the constants as well as the type and public methods.
5).When documenting an annotation type, be sure to document any members as welll as the type itself.
For example:

import java.util.*;
import java.lang.annotation.*;

/**
 *An class that save and get name 
 */
public class JavaDoc {

    private String[] names;//-A arrays that can save name

    /**
     *constructor for JavaDoc with initial the names field 
     */
    public JavaDoc(String[] names) {
        this.names = names;
    }

    /**
     * @param index the index of names
     * @return the name of names that index in names equal index parameter
     * @exception NullPointerExeption throw when parameter index is null
     */
    public String get(int index) {
        return names[index];
    }
}

/**
 *An object that maps keys to values. A map cannot contain
 *duplicate keys: each key can map to at most one value
 *
 *(Remainder omitted)
 *
 *@param <K> the type of keys maintained by this map
 *@param <V> the type of mapped values
 */
interface Map<K, V> {
    //...Remainder omitted
}

/**
 *An intrument section of a symphony orchestra
 */
enum OrchestraSection {
    /**Woodwinds, such as flute, clarinet, and oboe*/
    WOODWIND,
    /**Bras instrumants, such as french horn and trumpet*/
    BRASS;
}

/**
 *Indicates that the annotated method is a test method that
 *must throw the designated exception to succeed.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface ExceptionTest {
/**
 *The exception that the annotated test method must throw 
 *in order to pas. (The test is permitted to throw any
 *subtype of the type described by this class object)
 */
    Class<? extends Exception> value();
}

Seven:General Programming
Item 45: Minimize the scope of local variables
By minimizing the scope of local varibles, you increase the readability and maintainability of your code and reduce the likelihood of error. But how to do that? Follow the next 4 hits:
1).The most powerful technique for minimizing the scope of a local variable is to declare it where it is first used.
2).Nearly every local variable declaration should contain an initializer.
3). Prefer for loops to while loops.
4).If you combine two activities in the same method, local variables relevant to one activity may be in the scope of the code performing the other activity. To prevent this from happening, simply separate the method into two: one for each activity.
Example:

import java.util.*;

public class MinimizeScopeOfLocalVariable {

    public static void main(String[] args) {
        List<Integer> c = new ArrayList<Integer>();
        c.add(1);
        c.add(2);
        c.add(3);
        List<Integer> c2 = new ArrayList<Integer>();
        c.add(4);
        c.add(5);
        c.add(6);
        /**
         * Will bring cut-and-paste error.
         * Because the program error silently. 
         * the error can remain undetected for a long time 
         */
        Iterator<Integer> i = c.iterator();
        while (i.hasNext()) {
            System.out.print("[ i: "+i.next()+" ]");
        }
        Iterator<Integer> i2 = c2.iterator();
        while (i.hasNext()) {   //BUG!
            System.out.print("[ i2: "+i2.next()+" ]");
        }

        /**
         * Prefer for loops to while loops.
         */
        for (Iterator<Integer> i3 = c.iterator(); i3.hasNext();) {
            System.out.print("[ i3: "+i3.next()+" ]");
        }
        //Compile-time error - cannot find symbol i3.hasNext()
        for (Iterator<Integer> i4 = c2.iterator(); i4.hasNext();) {
            System.out.print("[ i4: "+i4.next()+" ]");
        }

        /**
         *Here is another loop idiom that minimizes 
         *the scope of local variables
         */
        for (int i5 = 0; i5 < c.size(); i5++) {
            System.out.print("[ i5: "+c.get(i5)+" ]");
        }

    }
}/*:Output:
[ i: 1  ][ i: 2  ][ i: 3  ][ i: 4  ][ i: 5  ][ i: 6  ]
[ i3: 1  ][ i3: 2  ][ i3: 3  ][ i3: 4  ][ i3: 5  ][ i3: 6  ]
[ i5: 1  ][ i5: 2  ][ i5: 3  ][ i5: 4  ][ i5: 5  ][ i5: 6  ]
*///:~

Item 46: Prefer for-each loops to traditional for loops
For-each loop can help you get rid of the clutter and the opportunity for error by hiding the iterator or index variable completely, which provides compelling advantages over the traditional for loop in clarity and bug prevention, with no performance penalty. You should use it wherever you can. Unfortunately, there are three common situations where you can’t use a for-each-loop:
1).Filtering–If you need to traverse a collection and remove selected elements, then you need to use an explicit iterator so that you can call its remove method
2).Transforming–If you need to traverse a list or array and replace some or all of the values of its elements, then you need the list iterator or array index in order to set the value of an element.
3). Parallel iterator—If you need to traverse multiple collections in parallel, then you need explicit control over the iterator or index variable, so that all iterators or index variables can be advanced in lockstep.
For example:

import java.util.*;

enum Suit { CLUB, DIAMOND, HEART, SPADE } 
enum Rank { ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
            NINE, TEN, JACK, QUEUE, KING }

public class ForEachLoop {

    public static void main(String[] args) {
        Collection<Suit> suits = Arrays.asList(Suit.values());
        Collection<Rank> ranks = Arrays.asList(Rank.values());
        System.out.println("Two iterator loops:");
        for(Iterator<Suit> i = suits.iterator(); i.hasNext(); ) {
            for(Iterator<Rank> j = ranks.iterator(); i.hasNext(); ) {
                System.out.print("["+ i.next() + ":" + j.next() + "]");
            }
            System.out.println();
        }
        System.out.println("Two for-each loops:");
        for(Suit suit : suits) {
            for(Rank rank : ranks) {
                System.out.print("["+ suit + ":" + rank + "]");
            }
            System.out.println();
        }
    }
}/*Output:
Two iterator loops:
[CLUB:ACE][DIAMOND:DEUCE][HEART:THREE][SPADE:FOUR]
Two for-each loops:
[CLUB:ACE][CLUB:DEUCE][CLUB:THREE][CLUB:FOUR][CLUB:FIVE][CLUB:SIX][CLUB:SEVEN][CLUB:EIGHT][CLUB:NINE][CLUB:TEN][CLUB:JACK][CLUB:QUEUE][CLUB:KING]
[DIAMOND:ACE][DIAMOND:DEUCE][DIAMOND:THREE][DIAMOND:FOUR][DIAMOND:FIVE][DIAMOND:SIX][DIAMOND:SEVEN][DIAMOND:EIGHT][DIAMOND:NINE][DIAMOND:TEN][DIAMOND:JACK][DIAMOND:QUEUE][DIAMOND:KING]
[HEART:ACE][HEART:DEUCE][HEART:THREE][HEART:FOUR][HEART:FIVE][HEART:SIX][HEART:SEVEN][HEART:EIGHT][HEART:NINE][HEART:TEN][HEART:JACK][HEART:QUEUE][HEART:KING]
[SPADE:ACE][SPADE:DEUCE][SPADE:THREE][SPADE:FOUR][SPADE:FIVE][SPADE:SIX][SPADE:SEVEN][SPADE:EIGHT][SPADE:NINE][SPADE:TEN][SPADE:JACK][SPADE:QUEUE][SPADE:KING]
*///:~

Item 47: Know and use the libraries
Advantages of using libraries:
1).By using a standard library, you take advantage of the knowledge of the experts who wrote it and the experience of those who used it before you.
2).You don’t have to waste your time writing ad hoc solutions to problems that are only marginally related to your work.
3).Their performance tends to improve over time, with no effort on your part.
Numerous features are added to the libraries in every major release, and it pays to keep abreast of these additions. Every programmer should be familiar with the contents of java.lang.util, and, to a lesser extent, java.io. The high-level parts of java.util.concurrent should also be part of every programmer’s basic toolkit.

Item 48: Avoid float and double if exact answers are required
In summary, don’t use float or double for any calculations that require an exact answer. Use BigDecimal if you want the system to keep track of the decimal point and you don’t mind the inconvenience and cost of not using a primitive type. Using BigDecimal has the added advantage that it gives you full control over rounding, letting you select from eight rounding modes whenever an oppration that entails rounding is performed. This comes in handy if you’re performing business calculations with legally mandated rounding behavior. If performance is of the essence, you don’t mind keeping track of the decimal point yourself, and the quantities aren’t too big, use int or long. If the quantities don’t exceed nine decimal digits, you can use int; if they don’t exceed eighteen digits, you can use long. If quantities might exceed eighteen digits, you must use BigDecimal.
Show you the code:
Float:

public class FloatUsed {
    //Broken - uses floating point for manetory calculation!
    public static void main(String[] args) {
        double funds = 1.00;
        int itemsBought = 0;
        for(double price = .10; funds >= price; price += .10) {
            funds -= price;
            itemsBought++;
        }
        System.out.println(itemsBought + "items bought.");
        System.out.println("Change: $" + funds);
    }
}/*Output:
3items bought.
Change: $0.3999999999999999
*///:~

BigDecimal:

import java.math.BigDecimal;

public class BigDecimalUsed {
    //Appropriate - uses BigDecimal point for manetory calculation!
    public static void main(String[] args) {
        final BigDecimal TEN_CENTS = new BigDecimal(".10");
        int itemsBought = 0;
        BigDecimal funds = new BigDecimal("1.00");
        for(BigDecimal price = TEN_CENTS; 
                funds.compareTo(price) >= 0; 
                price = price.add(TEN_CENTS)) {
            itemsBought++;
            funds = funds.subtract(price);
        }
        System.out.println(itemsBought + "items bought.");
        System.out.println("Change: $" + funds);
    }
}/*Output:
4items bought.
Change: $0.00
*///:~

int:

public class IntUsed {
    //Appropriate - uses int point monetary calculation
    public static void main(String[] args) {
        int itemsBought = 0;
        int funds = 100;
        for(int price = 10; funds >= price; price += 10) {
            itemsBought++;
            funds -= price;
        }
        System.out.println(itemsBought + " items bought.");
        System.out.println("Money left over: " + funds + " cents");
    }  
}/*Output:
4 items bought.
Money left over: 0 cents
*///:~

Item 49: Prefer primitive types to boxed primitives
Let’s find out the major differences between primitives and boxed primitives.
1).Primitives have only their values, whereas boxed primitives have identities distinct from their values;
2).Primitive types have only fully functional values, whereas each boxed primitive type has one nonfunctional value;
3).Primitives are generally more time-and space-efficient than boxed primitives;
When should you use boxed primitives?
1).As elements, keys, and values in collection;
2).As type parameters in parameterized types, because the language does not permit you to use primitives;
3).You must use boxed primitives when making reflective method invocations;
And you need to pay attention in these hits:
1).Applying the == operator to boxed primitives is almost always wrong;
2).When you mix primitives and boxed primitives in a single operation, the boxed primitive is auto-unboxed;
3).Autoboxing reduces the verbosity, but not the danger, of using boxed primitives;
4).When your program does unboxing, it can throw a NullPointerException;
For example:
1).

import java.util.Comparator;

public class PrimitiveType {

    public static void main(String[] args){
        // Broken comparator
        Comparator<Integer> IntegerOrder = new Comparator<Integer>() {
            public int compare(Integer first, Integer second) {
                // Compare two Integer object's instance(they're different)
                return first < second ? -1 : (first == second ? 0 :1);
            }  
        };
        Comparator<Integer> IntOrder = new Comparator<Integer>() {
            public int compare(Integer first, Integer second) {
                int f = first;// Auto-unboxing
                int s = second;// Auto-unboxing
                return f < s ? -1 : (f == s ? 0 :1) ;// No unboxing
            }
        };
        System.out.println("Integer :" + IntegerOrder.compare(new Integer(42), new Integer(42)));
        System.out.println("int :" + IntOrder.compare(new Integer(42), new Integer(42)));
    }   
}/*Output:
Integer :1
int :0
*///:~

2).

public class Unbelievable {
    static Integer i;

    public static void main(String[] args) {
        if(i == 42)
            /**
             * The problem is that i is an Integer, not an int,
             * and like all object reference fields, its initial
             * value is null.
             */
            System.out.println("Unbelievable");
    }
}/*Output:
Exception in thread "main" java.lang.NullPointerException
    at Unbelievable.main(Unbelievable.java:5)
*///:~

3).

public class BoxedSlow {
    /** Hideously slow program!
     * Variable is repeatedly boxed and unboxed,
     * causing the observed performance degradation.
     */
    public static void main(String[] args) {
        Long sum = 0L;
        for(long i=0; i < Integer.MAX_VALUE; i++) {
            sum += i;
        }
        System.out.println(sum);
    }
}///:~

In the first two programs, the consequences were outright failure; in the third, server performance problems.

Item 50: Avoid strings where other types are more appropriate
The item discusses a few things that you shouldn’t do with strings.
1).Strings are poor substitutes for other value types;
2).Strings are poor substitutes for enum types;
3).Strings are poor substitutes for aggregate types;
4).Strings are poor substitutes for capabilities;
In summary, avoid the natural tendency to represent objects as strings when better data types exist or can be written. Used inappropriately, strings are more cumbersome, less flexible, slower, and more error-prone than other types. Types for which strings are commonly misused include primitive types, enums, and aggregate types.
For example:

...
//Broken - inappropriate use of string as capability!
public class ThreadLocalByString {
    private ThreadLocalByString() {  } //Noninstantiable

    // Sets the current thread's value for the named variable.
    public static void set(String key, String value);

    // Returns the current thread's value for the name variable
    public static Object get(String key);
}

// Make this API typesafe by Generifying the class
final class ThreadLocalByGeneric<T> {
    public ThreadLocalByGeneric() {  }
    public void set(T value);
    public T get();
}
...

Item 51: Beware the performance of string concatenation
Using the string concatenation operator repeatedly to concatenate n string requires time quadratic in n. To achieve acceptable performance, use StringBuilder in place of a string. Just like “Thinking in Java” show in Strings chapter.
Look at code:

public class Concatenation {
    public static void main(String[] args) {
        String mango = "we are strings.";
        String[] s = mango.split(" "); 
        System.out.println(implicit(s));
        System.out.println(explicit(s));
    }

    public static String implicit(String[] fields) {
        String result = "";
        for(int i=0; i < fields.length; i++)
            result += fields[i];
        return result;
    }

    public static String explicit(String[] fields) {
        StringBuilder result = new StringBuilder();
        for(int i=0; i < fields.length; i++)
            result.append(fields[i]);
        return result.toString();
    }
}/*Output:
wearestrings.
wearestrings.
*///:~

Here’s the JVM bytecodes about implicit() and explicit():

public static java.lang.String implicit(java.lang.String[]);
    Code:
       0: ldc           #9                  // String 
       2: astore_1      
       3: iconst_0      
       4: istore_2      
       5: iload_2       
       6: aload_0       
       7: arraylength   
       8: if_icmpge     38
      11: new           #10                 // class java/lang/StringBuilder
      14: dup           
      15: invokespecial #11                 // Method java/lang/StringBuilder."<init>":()V
      18: aload_1       
      19: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      22: aload_0       
      23: iload_2       
      24: aaload        
      25: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: invokevirtual #13                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: astore_1      
      32: iinc          2, 1
      35: goto          5
      38: aload_1       
      39: areturn       

  public static java.lang.String explicit(java.lang.String[]);
    Code:
       0: new           #10                 // class java/lang/StringBuilder
       3: dup           
       4: invokespecial #11                 // Method java/lang/StringBuilder."<init>":()V
       7: astore_1      
       8: iconst_0      
       9: istore_2      
      10: iload_2       
      11: aload_0       
      12: arraylength   
      13: if_icmpge     30
      16: aload_1       
      17: aload_0       
      18: iload_2       
      19: aaload        
      20: invokevirtual #12                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: pop           
      24: iinc          2, 1
      27: goto          10
      30: aload_1       
      31: invokevirtual #13                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      34: areturn       

About implicit(), notice 5: and 35:, they are loops, and the StringBuilder construction happends inside this loop, which mean you’re going to get a new StringBuilder object every time you pass through the loop. These problem that implicit() brought can be solve in explicit(), which StringBuilder object was create once at first(notice 10: and 27: in explicit() bytecodes).

Item 52: Refer to objects by their interfaces
If appropriate interface types exist, then parameters, return values, variables, and fields should all be declared using interface types. If you get into the habit of using interfaces as types, your program will be much more flexible.
It is entirely appropriate to refer to an object by a class rather than an interface if no appropriate interface exists. Here’s the situation that happen:
1).If a concrete class has no associated interface, then you have no choice but to refer to it by its class whether or not it represents a value;
2).A second case in which there is no appropriate interface type is that of objects belonging to a framework whose fundamental types are classes rather than interfaces;
3).A final case in which there is no appropriate interface type is that of classes that implement an interface but provide extra methods not found in the interface;
In practice, it should be apparent whether a given object has an appropriate interface. If it does, your program will be more flexible if you use the interface to refer to the objects; if not, just use the least specific class in the class hierarchy that provides the required functionality.
For example:

import java.util.*;

public class ReferObjectByInterface {
    public static void main(String[] args) {
        // Good - uses interface as type
        List<Integer> subscribers = new Vector<Integer>();
        /**
         * If you decide that you want to switch implmentations, all
         * you have to do i change the class name in the constructor
         * List<Integer> subscribers = new ArrayList<Integer>();
         */
        // Bad - uses class as type
        Vector<Integer> subscribers2 = new Vector<Integer>();
    }
}///:~

Item 53: Prefer interface to reflection
Let’s look the disadvantages of reflection:
1).You lose all the benefits of compile-time type checking;
2).The code required to perform reflecttive access is clumsy and verbose;
3). Performance suffers;
So, you need to notice these rules:
1).Objects should not be accessed reflectively in normal applications at runtime;
2).You can obtain many of the benefits of reflection while incurring few of its costs by using it only in a very limited form;
3).Creating instances reflectively and access them normally via their interface or superclass;
In, summary, reflection is a powerful facility that is required for certain sophisticated system programming tasks, but it has many disadvantages. If you are writing a program that has to work with classes unknown at compile time, you should, if at all possible, use reflection only to instantiate objects, and access the objects using some interface or superclass that is known at compile time.
Like this:

import java.util.*;

public class Reflection {
    // Reflective instantiation with interface access
    public static void main(String[] args) {
        // Translate the class name into a Class object
        Class<?> c1 = null;
        try {
            c1 = Class.forName(args[0]);
        } catch(ClassNotFoundException e) {
            System.err.println("Class not found.");
            System.exit(1);
        }

        // Instantiate the class
        Set<String> s = null;
        try {
            s = (Set<String>) c1.newInstance();
        } catch(IllegalAccessException e) {
            System.err.println("Class not accessible.");
            System.exit(1);
        } catch(InstantiationException e) {
            System.err.println("Class not instantiable.");
            System.exit(1);
        }

        // Exercise the set
        s.addAll(Arrays.asList(args).subList(1, args.length));
        System.out.println(s);
    }
}///:~

Item 54: Use native methods judiciously
Historically, native methods have had three main uses:
1).They provided access to platform-specific facilities such as registries and file locks;
2).They provided access to libraries of legacy code, which could in turn provide access to legacy data;
3).Finally, native method were used to write performance-critical parts of applications in native languages for improved performance;
But, it’s rarely advisable to use native methods for improved performances for it disadvantages:
1).Native languages are not safe;
2).Native languages are platform dependent, applications using native methods are far less portable;
3).Applications using native code are far more difficult to debug;
4).A single bug in the native code can corrupt your entire application;

Item 55: Optimize judiciously
Keep that in your mind:
1).Strive to write good programs rather than fast ones;
2).Strive to avoid design decisions that limit performance;
3).Consider the performance consequences of your API design decisions;
4).It is a very bad idea to wrap an API to achieve good performances;
5).Measure performance before and after each attempted optimization;
When you’ve finished building the system, measure its performance. If it’s fast enough, you’re done. If not, locate the source of the problems with the aid of a profile and go to work optimizing the relevant parts of the system. The first step is to examine your choice of algorithm: no amount of low-level optimization can make up for a poor choice of algorithm. Repeat this process as necessary, measuring the performance after every change, until you’re satisfied.

Item 56: Adhere to generally accepted naming conventions
Loosely speaking, naming conventions fall into two categories: typographical and grammatical.
Typographical covering package, classes, interfaces, methods, fields, and type variables:
1).The name of package that will be used outside your organization should begin with your organization’s Internet domain name with the top-level domain begin. The remainder of a package should consist of one or more components describing the package. Components should be short, generally eight or fewer characters, for example, com.google.inject;
2).Class and interface names, including enum and annotation type names, should consist of one or more words, with the first letter or each word capitalized, for example, Timer, HttpServlet;
3).Method and field names follow the same typographical conventions as class and interface names, except that the first letter of a method or field name should be lowercase, for example,remove, ensureCapacity;
4).”constant fields”, whose names should consist of one or more uppercase words separated by the underscore character, for example, MIN_VALUE;
5).Local variable names have similar typographical naming conventions to member names, for example, i, j;
6).Type parameter names usually consist of a single letter. Most commonly it is one of these five, for example, T, E, K, V, X, T1, T2:
(1) T for an arbitrary type;
(2) E for the element type of a collection;
(3) K and V for the key and value types of a map;
(4) X for an exception;
(5) A sequence of arbitrary can be T, U, V, or T1, T2, T3;
However, grammatical are more flexible:
1).There are no grammatical naming conventions to speak of for package. Classes, including enum type, are generally named with a singular noun or noun phrase, for example, Timer, Collection or Comparator;
2).Interface are name with an adjective ending in able or ible, for example, Runnable, Iterable, Accessable;
3).Methods that return a boolean value usually have names that begin with the word is not, forexample, isEmpty, isDigit, isEnabled;
4).Methods that return a non-boolean function or attribute of the object on which they’re invoked are usually named with a noun, a noun phrase, or a verb phrase beginning with verb get, for example, getTime, getAttribute;
5).Methods that convert the type of an object, returning an independent object of a different type, are often called toType, for example, toString, toArray;
6).Methods that return a view whose type differs from that of the receiving object are often called asType, for example, asList;
7).Methods that return a primitive with the same value as the object on which they’re invoked are often called typeValue, for example, intValue;
8).Common names for static factories are valueOf, of, getInstance, newInstance, getType and newType;
In a word, the typographical conventions are straightforward and largely unambiguous; the grammatical conventions are more complex and looser.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值