#java #generics
Здравствуйте. Подскажите, как написать обобщённый метод чтения данных из файла. Например, в одном случае нужно считать строки, в другом - целые числа. Как написать метод типа такого: public staticList readFromFile(Path pathIn, TypeValue typeValue){...}; Корректен ли такой код: public static List readFromFile(Path pathIn, TypeValue typeValue){ try(Scanner in = new Scanner(pathIn)) { if (typeValue == TypeValue.typeInt) { List list = new ArrayList<>(); while (in.hasNextInt()) { list.add(in.nextInt()); } return list; } else { List list = Files.readAllLines(pathIn); return list; } } catch (IOException e){ return null; } } Здесь pathIn - путь к файлу с данными, typeValue - флаг для обозначения данных (Integer, String и т.д.). Смущает, что возвращается не параметризованный List. Как вообще решается задача чтения из файла, если формат данных может быть разным - Integer, Double, String и т.д.? Или следует писать для каждого типа данных свой код для чтения? Как-то громоздко тогда получается.
Ответы
Ответ 1
Функционал из Java 8 Stream & Lambda позволяет передавать в метод функциональный интерфейс, который будет применен к потоку данных: public void start() throws IOException { Path path = Paths.get("test"); ListresultStringList = readFile(path, Function.identity()); List resultIntList = readFile(path, Integer::parseInt); } public List readFile(Path path, Function func) throws IOException { return Files.lines(path) .map(func) .collect(Collectors.toList()); } } Ответ 2
Или следует писать для каждого типа данных свой код для чтения? Не самый плохой вариант: написать отдельные методы для каждого типа (в Scanner, например, так и сделали) . Как-то громоздко тогда получается. В Вашем варианте вместо нескольких коротких методов используется один, в котором в одном большом if будет код всех этих методов. Альтернатива Можно обернуть метод в интерфейс и применить полиморфизм: //интерфейс interface ListReader{ List read(String path); } //все общие функции вынесем в отдельный базовый класс abstract class BaseListReader implements ListReader { @Override public List read(String path) { try (Scanner in = new Scanner(path)) { List list = new ArrayList<>(); while (hasNext(in)) { list.add(next(in)); } return list; } catch (IOException e) { return null; } } abstract boolean hasNext(Scanner in) throws IOException; abstract T next(Scanner in) throws IOException; } class IntListReader extends BaseListReader { @Override boolean hasNext(Scanner in) throws IOException { return in.hasNextInt(); } @Override Integer next(Scanner in) throws IOException { return in.nextInt(); } } class StringListReader extends BaseListReader { @Override boolean hasNext(Scanner in) throws IOException { return in.hasNext(); } @Override String next(Scanner in) throws IOException { return in.nextLine(); } } Затем создать фабрику: //Метод для создания public ListReader createReader(Class clazz) { if (clazz == Integer.class) { return new IntListReader(); } else if (clazz == String.class) { return new StringListReader(); } throw new IllegalArgumentException("clazz"); } В такой реализации обработка разных типов будет отделена друг от друга и от классов-клиентов (публичным может быть только интерфейс ListReader). Это позволит протеститровать их отдельно от других классов приложения/использовать класы повторно. Насколько это оправдано нужно решать по ситуации. Если код будет использован один раз, требования к нему изменяться не будут и нет строгих требований к качеству (покрытие тестами, ограничение сложности методов), то может быть достаточно просто разбить на отдельные методы. Смущает, что возвращается не параметризованный List Эта проблема не решена (возвращается не параметризованный ListReader). Решение зависит от того как используется результат метода. Если полученный список обрабатывается как List
Комментариев нет:
Отправить комментарий