==判等符合語義,且更高效;Item 3: 單例模式!
不管以哪種形式實(shí)現(xiàn)單例模式,它們的核心原理都是將構(gòu)造函數(shù)私有化,并且通過靜態(tài)方法獲取一個(gè)唯一的實(shí)例,在這個(gè)獲取的過程中你必須保證線程安全、反序列化導(dǎo)致重新生成實(shí)例對象等問題,該模式簡單,但使用率較高。
double-check-locking
private static volatile RestAdapter sRestAdapter = null;
public static RestAdapter provideRestAdapter() {
if (sRestAdapter == null) {
synchronized (RestProvider.class) {
if (sRestAdapter == null) {
sRestAdapter = new RestAdapter();
}
}
}
return sRestAdapter;
}
DCL可能會失效,因?yàn)橹噶钪嘏趴赡軐?dǎo)致同步解除后,對象初始化不完全就被其他線程獲取;使用volatile關(guān)鍵字修飾對象,或者使用static SingletonHolder來避免該問題(后者JLS推薦);
盡管Object不是抽象類,但是其定義的非final方法設(shè)計(jì)的時(shí)候都是希望被重寫的,finalize除外。
Collections.unmodifiableList(Arrays.asList(arr))Item 23: Don’t use raw types in new code
List<E>,真正使用的時(shí)候都是List<String>等,把E替換為實(shí)際的類型List<E>的raw type就是ListList與List<Object>的區(qū)別
前者不具備類型安全性,后者具備,例如以下代碼
// Uses raw type (List) - fails at runtime!
public static void main(String[] args) {
List<String> strings = new ArrayList<String>();
unsafeAdd(strings, new Integer(42));
String s = strings.get(0); // Compiler-generated cast
}
private static void unsafeAdd(List list, Object o) {
list.add(o);
}
不會報(bào)編譯錯(cuò)誤,但會給一個(gè)編譯警告:Test.java:10: warning: unchecked call to add(E) in raw type List list.add(o);,而運(yùn)行時(shí)則會發(fā)生錯(cuò)誤。
List<Object>,即unsageAdd參數(shù)改為List<Object> list, Object o,則會報(bào)編譯錯(cuò)誤:Test.java:5: unsafeAdd(List<Object>,Object) cannot be applied to (List<String>,Integer) unsafeAdd(strings, new Integer(42)); List的子類,但卻不是List<Object>的子類。 List<Object>,這個(gè)場景應(yīng)該使用List<String>,這里只是為了說明List和List<Object>是有區(qū)別的。List v.s. List<?>(unbounded wildcard types),當(dāng)不確定類型參數(shù),或者說類型參數(shù)不重要時(shí),也不應(yīng)該使用raw type,而應(yīng)該使用List<?>
任何參數(shù)化的List均是List<?>的子類,可以作為參數(shù)傳入接受List<?>的函數(shù),例如以下代碼均是合法的:
void func(List<?> list) {
...
}
func(new List<Object>());
func(new List<Integer>());
func(new List<String>());
List<?>的引用后,并不能向其中加入任何元素,讀取出來的元素也是Object類型,而不會被自動強(qiáng)轉(zhuǎn)為任何類型。List<?>的行為不能滿足需求,可以考慮使用模板方法,或者List<E extends XXX>(bounded wildcard types)List.class, String[].class, and int.class are all legal, but List<String>.class and List<?>.class are not.instanceof不支持泛型,以下用法是推薦的,但不應(yīng)該將o強(qiáng)轉(zhuǎn)為List
// Legitimate use of raw type - instanceof operator
if (o instanceof Set) { // Raw type
Set<?> m = (Set<?>) o; // Wildcard type
...
}ClassCastException,可以通過@SuppressWarnings("unchecked")消除警告,但不要直接忽略該警告@SuppressWarnings("unchecked")時(shí),應(yīng)該在注視內(nèi)證明確實(shí)不存在運(yùn)行時(shí)的ClassCastException;同時(shí)應(yīng)該盡量減小其作用的范圍,通常是應(yīng)該為一個(gè)賦值語句添加注解Item 25: Prefer lists to arrays
Sub是Super的子類,那么Sub[]也是Super[]的子類Type1和Type2,List<Type1>和List<Type2>之間沒有任何繼承關(guān)系考慮以下代碼
// Fails at runtime!
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in"; // Throws ArrayStoreException
// Won't compile!
List<Object> ol = new ArrayList<Long>(); // Incompatible types
ol.add("I don't fit in");
new List<E>[], new List<String>[], new E[];但是聲明是可以的,例如List<String>[] stringListsE, List<E>, List<String>,這些類型在運(yùn)行時(shí)的信息比編譯時(shí)的信息更少List<?>, Map<?, ?>generic array creation errorsvarargs一起使用時(shí),也會導(dǎo)致編譯警告// Generic method
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {
Set<E> result = new HashSet<>(s1);
result.addAll(s2);
return result;
}// Using a recursive type bound to express mutual comparability
public static <T extends Comparable<T>> T max(List<T> list) {...}Item 28: Use bounded wildcards to increase API flexibility
考慮以下代碼
public class Stack<E> {
public Stack();
public void push(E e);
public E pop();
public boolean isEmpty();
public void pushAll(Iterable<E> src);
public void popAll(Collection<E> dst);
}
Stack<Number> numberStack = new Stack<Number>();
Iterable<Integer> integers = ... ;
numberStack.pushAll(integers);
Stack<Number> numberStack = new Stack<Number>();
Collection<Object> objects = ... ;
numberStack.popAll(objects);
pushAll和popAll的調(diào)用均無法通過編譯,因?yàn)楸M管Integer是Number的子類,但Iterable<Integer>不是Iterable<Number>的子類,這是由泛型的invariant特性導(dǎo)致的,所以Iterable<Integer>不能傳入接受Iterable<Number>參數(shù)的函數(shù),popAll的使用同理
<? extends E>, <? super E>, PECS stands for producer-extends, consumer-super. 如果傳入的參數(shù)是要輸入給該類型數(shù)據(jù)的,則應(yīng)該使用extends,如果是要容納該類型數(shù)據(jù)的輸出,則應(yīng)該使用super有時(shí)候編譯器的類型推導(dǎo)在遇到bounded wildcards會無法完成,這時(shí)就需要顯示指定類型信息,例如:
public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2);
Set<Integer> integers = ... ;
Set<Double> doubles = ... ;
//Set<Number> numbers = union(integers, doubles); //compile error
Set<Number> numbers = Union.<Number>union(integers, doubles); //compile pass
Comparable<? super T> in preference to Comparable<T>. The same is true of comparators, so you should always use Comparator<? super T> in preference to Comparator<T>.<E> ... List<E>) v.s. unbounded wildcard(List<?>):if a type parameter appears only once in a method declaration, replace it with a wildcard.Item 29: Consider typesafe heterogeneous containers
List<T>,Map<K, V>,但有時(shí)可能需要一個(gè)容器,能放入任意類型的對象,但需要具備類型安全性,例如數(shù)據(jù)庫的一行,它的每一列都可能是任意類型的數(shù)據(jù)Class類從1.5就被泛型化了,所以使得這種需求可以實(shí)現(xiàn),例如:
// Typesafe heterogeneous container pattern - API
public class Favorites {
public <T> void putFavorite(Class<T> type, T instance);
public <T> T getFavorite(Class<T> type);
}Class對象被稱為type token,它傳入函數(shù),用來表述編譯時(shí)和運(yùn)行時(shí)的類型信息Favorites的實(shí)現(xiàn)也是很簡單的:
// Typesafe heterogeneous container pattern - implementation
public class Favorites {
private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
public <T> void putFavorite(Class<T> type, T instance) {
if (type == null)
throw new NullPointerException("Type is null");
favorites.put(type, instance);
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}
// Achieving runtime type safety with a dynamic cast
public <T> void putFavorite(Class<T> type, T instance) {
favorites.put(type, type.cast(instance));
}
這樣做的效果是使得想要破壞類型安全性的put使用者產(chǎn)生異常,而使用get的使用者則不會因?yàn)閻阂鈖ut使用者產(chǎn)生異常。這種做法也被java.util.Collections包中的一些方法使用,例如命名為checkedSet, checkedList, checkedMap的類。
List<String>,因?yàn)?code>List<String>.class是有語法錯(cuò)誤的,List<String>, List<Integer>都只有同一個(gè)class對象:List.class;另外String[].class是合法的。Favorites使用的類型參數(shù)是unbounded的,可以put任意類型,也可以使用bounded type token,使用bounded時(shí)可能需要把Class<?>轉(zhuǎn)換為Class<? extends Annotation>,直接用class.cast將會導(dǎo)致unchecked warning,可以通過class.asSubclass來進(jìn)行轉(zhuǎn)換,例子:
// Use of asSubclass to safely cast to a bounded type token
static Annotation getAnnotation(AnnotatedElement element, String annotationTypeName) {
Class<?> annotationType = null; // Unbounded type token
try {
annotationType = Class.forName(annotationTypeName);
} catch (Exception ex) {
throw new IllegalArgumentException(ex);
}
return element.getAnnotation(annotationType.asSubclass(Annotation.class));
}Item 30: Use enums instead of int constants
實(shí)現(xiàn)建議
// Enum type with constant-specific method implementations
public enum Operation {
PLUS { double apply(double x, double y){return x + y;} },
MINUS { double apply(double x, double y){return x - y;} },
TIMES { double apply(double x, double y){return x * y;} },
DIVIDE { double apply(double x, double y){return x / y;} };
abstract double apply(double x, double y);
}結(jié)合constant-specific data
// Enum type with constant-specific class bodies and data
public enum Operation {
PLUS("+") {
double apply(double x, double y) { return x + y; }
},
MINUS("-") {
double apply(double x, double y) { return x - y; }
},
TIMES("*") {
double apply(double x, double y) { return x * y; }
},
DIVIDE("/") {
double apply(double x, double y) { return x / y; }
};
private final String symbol;
Operation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
abstract double apply(double x, double y);
}
ordinal()方法獲取其在該enum類型中的位置,但該方法只應(yīng)該在實(shí)現(xiàn)EnumSet, EnumMap等類型的時(shí)候被使用,其他情形都不應(yīng)該被使用List<Integer>而不是ArrayList<Integer>Conllections.unmodifiableSet來封裝為immutable,但是代碼簡潔性與性能都將受到影響Item 33: Use EnumMap instead of ordinal indexing
使用數(shù)組也會導(dǎo)致程序可擴(kuò)展性下降,考慮以下兩種實(shí)現(xiàn)
// Using ordinal() to index array of arrays - DON'T DO THIS!
public enum Phase {
SOLID, LIQUID, GAS;
public enum Transition {
MELT, FREEZE, BOIL, CONDENSE, SUBLIME, DEPOSIT;
// Rows indexed by src-ordinal, cols by dst-ordinal
private static final Transition[][] TRANSITIONS = {
{ null, MELT, SUBLIME },
{ FREEZE, null, BOIL },
{ DEPOSIT, CONDENSE, null }
};
// Returns the phase transition from one phase to another
public static Transition from(Phase src, Phase dst) {
return TRANSITIONS[src.ordinal()][dst.ordinal()];
}
}
}
// Using a nested EnumMap to associate data with enum pairs
public enum Phase {
SOLID, LIQUID, GAS;
public enum Transition {
MELT(SOLID, LIQUID), FREEZE(LIQUID, SOLID),
BOIL(LIQUID, GAS), CONDENSE(GAS, LIQUID),
SUBLIME(SOLID, GAS), DEPOSIT(GAS, SOLID);
final Phase src;
final Phase dst;
Transition(Phase src, Phase dst) {
this.src = src;
this.dst = dst;
}
// Initialize the phase transition map
private static final Map<Phase, Map<Phase,Transition>> m =
new EnumMap<Phase, Map<Phase,Transition>>(Phase.class);
static {
for (Phase p : Phase.values())
m.put(p,new EnumMap<Phase,Transition>(Phase.class));
for (Transition trans : Transition.values())
m.get(trans.src).put(trans.dst, trans);
}
public static Transition from(Phase src, Phase dst) {
return m.get(src).get(dst);
}
}
}
當(dāng)需要增加Phase時(shí),前者需要謹(jǐn)慎地修改TRANSITIONS數(shù)組的內(nèi)容(這一步驟容易出錯(cuò)),而后者則只需要增加相應(yīng)Transition即可,from函數(shù)的邏輯完全不受影響。
<T extends Enum<T> & Operation> ... Class<T>,T類型是enum類型,且是Operation子類test開頭test開頭命名測例類,方法卻沒有,JUnit則不會運(yùn)行測例@Retention(RetentionPolicy.RUNTIME)能限定其保留時(shí)期@Target(ElementType.METHOD)能限定其應(yīng)用的程序元素@IntDef@Override會使得重寫的準(zhǔn)確性得到檢查Serializable