Опасайтесь сглаживания длинного списка <String> в String
Моя ситуация
- У меня есть метод, который создает
List<String>
- У меня есть другой метод, который требует
String
- Я хочу взять вывод из (1) и поместить его в (2)
Мой подход
У меня очень соблазн просто сгладить этот List<String>
в один большой String
, но мой здравый смысл покалывает. Поэтому, прежде чем я слепо сделал что-то вроде этого:
List<String> fileLines = Files.readAllLines(Paths.get(""));
String jsonString = "";
for (String s : fileLines) {
jsonString += s;
}
JSONObject jsonObject = new JSONObject(jsonString);
Я перестала думать и искать и спрашивать. Я обнаружил, что NetBeans предлагает следующее:
List<String> fileLines = Files.readAllLines(Paths.get(""));
String jsonString = fileLines.stream().map((s) -> s)
.reduce(accountsJsonString, String::concat);
JSONObject jsonObject = new JSONObject(jsonString);
но моя мать всегда предупреждала меня об использовании кода, который я не понимаю. Я думаю, что это все еще копирует все данные и помещает их вместе в одну большую строку, поэтому я не вижу никакой практической разницы между тем и тем, что я изначально придумал.
Мой вопрос
Есть ли что-то не так, просто приклеивая все строки вместе в одну большую строку, с точки зрения лучших практик? Есть ли способ достичь моей цели (используя java.nio
и org.json
in), считывая длинный файл JSON с диска и в память, которая не требует дублирования содержимого файла после его чтения?
Решение, которое я использовал
Этот ответ на первую (концептуальную) половину моего вопроса показывает, что было хуже, чем я понял. Я объединил эти два, чтобы ответить на вторую (практическую) половину моего вопроса следующим образом:
BufferedReader jsonReader = Files.newBufferedReader(Paths.get(...));
JSONObject jsonObject = new JSONObject(new JSONTokener(jsonReader));
Ответы
Ответ 1
Короткий ответ заключается в том, что вы хотите изменить способ чтения файла!
Код, который у вас есть на данный момент, проблематичен с точки зрения количества мертвых объектов String
, которые требуют сбора мусора (помните, что a String
является неизменным, поэтому он создает новый объект каждый раз, когда вы добавляете бит). Он также получил квадратное время выполнения в длине списка, потому что каждый раз, когда он добавляет что-то, он имеет более длинный и длинный String
, который он должен скопировать.
Я думаю, что функциональный стиль кода Java 8, который предлагает NetBeans, также будет квадратичным: он будет использовать этот concat
несколько раз в своей функции сокращения.
Другой вариант - использовать StringBuffer
или массив char
. С последним вы можете прокручивать список, определяющий общую длину, соответственно распределить массив, поместить вещи в массив и затем создать из него большой String
. Это даст вам нечто линейное по всей длине, а не квадратичное.
Ответ 2
Вместо использования этих методов для создания JSONObject (кажется, что это ваша конечная цель), почему бы не использовать методы, предназначенные для загрузки JSONObject в память.
Reader fromFile = new BufferedReader(new FileReader(myFile));
JSONTokener tokens = new JSONTokener(fromFile);
JSONObject myObject = new JSONObject(tokens);
fromFile.close();
Затем вы получаете библиотеку JSON, которую вы выбрали для выполнения этой работы:)
Это зависит от JSONTokener из той же самой библиотеки, которую вы указали.
Ответ 3
Почему бы не использовать readAllBytes
вместо этого? Мне кажется, что нет необходимости работать с отдельными линиями.
byte[] bytes = Files.readAllBytes(path);
String jsonString = new String(bytes, StandardCharsets.UTF_8);
Однако обратите внимание на предупреждение по этому методу:
Обратите внимание, что этот метод предназначен для простых случаев, когда удобно считывать все байты в массив байтов. Он не предназначен для чтения в больших файлах.
Итак, если вы работаете с большим файлом, вы, вероятно, должны использовать BufferedReader
:
BufferedReader reader = Files.newBufferedReader(path);
Ответ 4
Хорошо, для меня это лучший способ сделать это:
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
for(String line : Files.readAllLines(Paths.get(""))) {
pw.println(line);
}
String bigString = sw.toString();
Это захватывает разрывы строк и т.д.