將問題一分為二
第一種辦法是將問題一分為二。比較本身不會導致異常。比較的隻是字符串而已。通過標準路徑將文件轉換成字符串才會導致異常。如果將可能拋出異常的操作與不會拋出異常的操作分開,那麼問題就更容易處理瞭。也就是說,首先將所有文件對象轉換為字符串,然後通過字符串比較器(甚至可以通過java.lang.String的自然排序)對字符串排序,最後使用排序後的字符串列表對原始的文件列表排序。這種方法不太直接,但是優點是在列表被改變之前就拋出IOException。如果出現異常,它隻會出現在預先設計好的地方,不會造成損害,調用代碼可以指定如何處理異常。清單4對此作瞭演示:
清單4.先讀取,然後排序 importjava.io.File; importjava.io.IOException; importjava.util.ArrayList; importjava.util.Collections; importjava.util.HashMap; publicclassFileComparator{ privatestaticArrayList<String>getCanonicalPaths(ArrayList<File>files) throwsIOException{ ArrayList<String>paths=newArrayList<String>(); for(Filefile:files)paths.add(file.getCanonicalPath()); returnpaths; } publicstaticvoidmain(String[]args)throwsIOException{ ArrayList<File>files=newArrayList<File>(); for(Stringarg:args){ files.add(newFile(arg)); } ArrayList<String>paths=getCanonicalPaths(files); //tomaintaintheoriginalmapping HashMap<String,File>map=newHashMap<String,File>(); inti=0; for(Stringpath:paths){ map.put(path,files.get(i)); i++; } Collections.sort(paths); files.clear(); for(Stringpath:paths){ files.add(map.get(path)); } } } 清單4並沒有消除出現I/O錯誤的可能性。這一點無法做到,因為這裡的代碼無力提供這樣的功能。但是,可以將這個問題交給更合適的地方來處理。
避免問題
前面提到的方法有點復雜,所以我建議另一種方法:不使用內置的compare()函數或Collections.sort()。使用這樣的函數也許比較方便,但是不適合當前情況。Comparable和Comparator是為確定的、可預測的比較操作而設計的。一旦I/O不再符合這種情況,很可能常用的算法和接口變得不適用。即使勉強可以使用,其效率也極其低下。
例如,假設不是按標準路徑來比較文件,而是按內容來比較文件。對於所比較的兩個文件,每個比較操作都需要讀文件的內容—甚至可能是完整的內容。這樣一來,高效的算法會想要盡量減少讀的次數,並且可能會想緩存每次讀的結果—或者,如果文件較大,則可能緩存每個文件的hashcode—而不是每次比較時重新讀每個文件。同樣,您會想到首先填充一個比較鍵列表,然後進行排序,而不是進行內聯排序。可以想象定義一個單獨的、並行的IOComparator接口,該接口拋出必要的異常,如清單5所示:
清單5.獨立的IOComparator接口 importjava.io.IOException; publicinterfaceIOComparator<T>{ intcompare(To1,To2)throwsIOException; } 然後基於這個類定義一個單獨的、相近實用程序樹,由它對集合的臨時副本進行必要的操作,從而允許拋出異常,同時又不會使數據結構處於可能受損害的、中間的狀態。例如,清單6提供瞭一個基本的冒泡排序:
清單6.用冒泡算法對文件排序 importjava.io.IOException; importjava.util.ArrayList; importjava.util.List; publicclassIOSorter{ publicstatic<T>voidsort(List<T>list,IOComparator<?superT>comparator) throwsIOException{ List<T>temp=newArrayList<T>(list.size()); temp.addAll(list); bubblesort(temp,comparator); //copybacktooriginallistnowthatnoexceptionshavebeenthrown list.clear(); list.addAll(temp); } //ofcourseyoucanreplacethiswithabetteralgorithmsuchasquicksort privatestatic<T>voidbubblesort(List<T>list,IOComparator<?superT>comparator) throwsIOException{ for(inti=1;i<list.size();i++){ for(intj=0;j<list.size()-i;j++){ if(comparator.compare(list.get(j),list.get(j+1))>0){ swap(list,j); } } } } privatestatic<T>voidswap(List<T>list,intj){ Ttemp=list.get(j); list.set(j,list.get(j+1)); list.set(j+1,temp); } } 這不是唯一的方法。為瞭清晰,清單6有意模仿已有的Collections.sort()方法;但是,也許更有效的方法是返回一個新的列表,而不是直接修改舊列表,以防在修改列表時拋出異常所帶來的損害。