Как создать универсальный процесс, который выполняет чтение в файле, разделенном табуляцией, и возвращает из него общую карту

#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:

  1. Поместите этот метод в абстрактный класс Util. Используйте универсальные файлы.
  2. Делегируйте абстрактным методам логику для выполнения в строках 9 и 16-19.
  3. Определите эти абстрактные методы в использовании этого класса

Например:

 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 и заполнить некоторый объект коллекции данными. 🙂