#java #generics #abstract-class
#java #общие сведения #абстрактный класс
Вопрос:
Почти в каждом проекте, над которым я работаю, будет какой-то файл с разделителями табуляции, который мне нужно прочитать и вернуть из него карту поиска. Я обнаруживаю, что переписываю один и тот же метод снова и снова. Я хочу создать что-то более универсальное, чтобы мне не приходилось постоянно копировать и вставлять код. Из приведенного ниже кода я меняю только строку 9 и 16-19. Поэтому я меняю только Map<key, value>
и реализацию того, как я хочу вводить данные в карту. Есть ли способ создать из этого универсальный процесс, чтобы каждый раз, когда я хочу вызвать этот метод, все, что мне нужно, это предоставить свою реализацию того, как я хочу вводить данные в Map, и каким-то образом изменить Map на более универсальный тип.
1. public Map<String, PackageLog> readAllLogsIntoMap(File file){
2. if (!file.exists())
3. {
4. return new HashMap <String, PackageLog> ();
5. }
6. BufferedReader reader = null;
7. FileReader fileReader = null;
8. String data = null;
9. Map <String, PackageLog> resultMap = new HashMap <String, PackageLog> ();
10. try
11. {
12. fileReader = new FileReader(file);
13. reader = new BufferedReader(fileReader);
14. while ((data = reader.readLine()) != null)
15. {
16. PackageLog pl = new PackageLog(data);
17. if(!pl.getPdfName().equals("")){
18. resultMap.put(pl.getPdfName(), pl);
19. }
20. }
21. } catch(Exception e){
22.
23. }
24. finally
25. {
26. try{
27. if (reader != null) reader.close();
28. if (fileReader != null) fileReader.close();
29. }catch(IOException ioe){
30.
31. }
32. }
33. return resultMap;
34. }
Ответ №1:
- Поместите этот метод в абстрактный класс Util. Используйте универсальные файлы.
- Делегируйте абстрактным методам логику для выполнения в строках 9 и 16-19.
- Определите эти абстрактные методы в использовании этого класса
Например:
public abstract class ReaderUtil<K, V> {
protected abstract Map<K, V> newMap();
protected abstract void doThings(String data, Map<K, V> resultMap);
public Map<K, V> readAllLogsIntoMap(File file){
if (!file.exists()){
return newMap();
}
BufferedReader reader = null;
FileReader fileReader = null;
String data = null;
Map <K, V> resultMap = newMap();
try {
fileReader = new FileReader(file);
reader = new BufferedReader(fileReader);
while ((data = reader.readLine()) != null){
doThings(data, resultMap);
}
} catch(Exception e){
}
finally{
try{
if (reader != null) reader.close();
if (fileReader != null) fileReader.close();
} catch(IOException ioe){
}
}
return resultMap;
}
}
И возможное использование:
ReaderUtil<String, PackageLog> reader = new ReaderUtil<String, PackageLog>(){
protected Map<String, PackageLog> newMap() {
return new HashMap<String, PackageLog>();
}
protected void doThings(String data, Map<String, PackageLog> resultmap){
PackageLog pl = new PackageLog(data);
if(!pl.getPdfName().equals("")){
resultMap.put(pl.getPdfName(), pl);
}
}
};
Map<String, PackageLog> myMap = reader.readAllLogsIntoMap();
Примите во внимание, что newMap()
метод вам нужен только в том случае, если вы хотите предоставить разные реализации карты. Вы вполне могли бы это сделать new HashMap<K, V>()
внутри обобщенного класса.
Возможно, вы также захотите определить методы перехвата (переопределяемые, возможно, пустые методы) для обработки исключений.
Комментарии:
1. Это выглядит потрясающе. У меня к вам только один вопрос. Действительно ли нам нужен метод
newMap()
. Итак, когда мы проверяемif (!file.exists())
, можем ли мы простоreturn new HashMap <K, V> ();
? В этом что-то не так, Хави?2. ооо, я вижу, вы ответили на мой вопрос выше. Однако я не понимаю, что вы под этим подразумеваете
Take into account you only need the newMap() method if you want to provide different map implementations
. Можете ли вы уточнить?3. Действительно, как указано в ответе, это было бы необходимо только в том случае, если реализации могут захотеть предоставить разные реализации
Map
(HashMap
,TreeMap
и так далее). Даже в этом случае его можно было бы свести кprotected abstract Class getMapClass()
или даже к универсальному и выполнить создание экземпляра с помощью отражения.4. Код, который вы показали, отлично работает, возможно ли его обобщить до такой степени, что он также может возвращать список<> . Прямо сейчас он возвращает только Map<K, V> . Я могу превратить это в другой вопрос, если вы хотите.
Ответ №2:
Вы могли бы сделать следующее.
public interface LookupKey<K, T> {
K keyFor(T t );
}
public <K, T> Map<K, T> readAllLogsIntoMap(File file, Class<T> tClass, LookupKey<K, T> lookupKey) {
BufferedReader reader = null;
Map<K, T> resultMap = new LinkedHashMap<K, T>();
if (!file.exists())
return resultMap;
try {
Constructor<T> tConstructor = tClass.getConstructor(String.class);
reader = new BufferedReader(new FileReader(file));
String data;
while ((data = reader.readLine()) != null) {
T t = tConstructor.newInstance(data);
K key = lookupKey.keyFor(t);
if (key != null)
resultMap.put(key, t);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (reader != null) reader.close();
} catch (IOException ignored) {
}
}
return resultMap;
}
Комментарии:
1. @Peter: возможно ли вообще обобщить до такой степени, что он также может возвращать список<> . Прямо сейчас он возвращает только Map<K, V> . Я могу превратить это в другой вопрос, если вы хотите
Ответ №3:
Я думаю, что вам следует использовать анализатор CSV, напримерhttp://opencsv.sourceforge.net /
Ответ №4:
Гарри, учитывая, что Java не имеет хорошей поддержки типов типов, как, скажем, язык программирования D, вам нужно реорганизовать свой метод, чтобы иметь подпись типа: public Map<String, Object[]> csvToMap(File argFile, char argSeparator, Class[]) {}
. Затем вы должны вызвать его как: mymap = csvToMap("/tmp/some.log", ';', { Date.class, String.class, Double.class});
. Этот вызов может быть использован для анализа CSV-файла, содержащего строки типа 2011-11-23;Some Name;232.22
Комментарии:
1. На самом деле, я буду кодировать эту функцию для своей собственной библиотеки. Это будет полезно во всех случаях, когда все, что мне нужно, это проанализировать файл CSV и заполнить некоторый объект коллекции данными. 🙂