2025-05-17

將問題一分為二


第一種辦法是將問題一分為二。比較本身不會導致異常。比較的隻是字符串而已。通過標準路徑將文件轉換成字符串才會導致異常。如果將可能拋出異常的操作與不會拋出異常的操作分開,那麼問題就更容易處理瞭。也就是說,首先將所有文件對象轉換為字符串,然後通過字符串比較器(甚至可以通過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()方法;但是,也許更有效的方法是返回一個新的列表,而不是直接修改舊列表,以防在修改列表時拋出異常所帶來的損害。



 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *