Можно ли использовать while ((line = r.readLine ())! = Null) construct? [закрыто]
Я хочу реорганизовать следующий код, потому что мне не комфортно использовать назначение внутри оператора сравнения. Это похоже на довольно идиоматический C, но вы думаете, что это хорошая практика в Java?
private void demoA (BufferedReader reader) бросает IOException {
Строка = нуль;
while ((line = reader.readLine ())! = null) {
йоЗотеЬЫпд (линия);
}
}
Вот альтернатива.
private void demoB (BufferedReader reader) бросает IOException {
Строковая строка = reader.readLine ();
while (строка! = null) {
йоЗотеЬЫпд (линия);
line = reader.readLine ();
}
}
UPDATE: я наткнулся на аналогичный вопрос , заданный пару лет назад. Похоже, что мнения о том, хорошо ли это или нет, разделены. Тем не менее, Guava и Commons IO предоставляют альтернативные решения для этой проблемы. Если бы у меня была какая-либо из этих библиотек в текущем проекте, я бы, скорее всего, использовал их.
6 ответов
Присвоение внутри условия в этом случае в порядке, так как присваивание окружено дополнительной парой круглых скобок - сравнение, очевидно, ! = null
, нет никаких шансов, что мы хотим type line == reader.readLine ()
.
Однако цикл для
может быть здесь более изящным:
for (String line = reader.readLine (); line! = null; line = reader.readLine ()) {
йоЗотеЬЫпд (линия);
}
В качестве альтернативы мы могли бы сделать это, что также ограничивает область line
, как при использовании для
-loop, и дополнительно исключает ненужное повторение:
while (true) {
final Строка line = reader.readLine ();
if (line == null) break;
йоЗотеЬЫпд (линия);
}
Мне нравится это решение больше всего, потому что оно не мутирует никаких переменных.
Вы можете немного увеличить уровень абстракции кода с помощью итераторного шаблона и в то же время вы можете повторно использовать существующую библиотеку (с опытом авторов): Apache Commons IO LineIterator . Он заменил бы нулевую проверку на немного читаемый hasNext ()
/nextLine ()
.
Использование итератора скрывает ненужную деталь: читатель возвращает null
, когда данных больше нет. Метод hasNext ()
находится ближе к (английскому) языку, код легче читать. Вы все еще можете проверить детали внутри LineIterator
, если вам это нужно, но обычно читатели /сопровождающие более счастливы с более высоким уровнем обзора метода, который легче понять. ( Этот ответ и вопрос содержат выразительный пример.)
Пример метода:
private void demoC (BufferedReader reader) бросает IOException {
final LineIterator it = новый LineIterator (считыватель);
пытаться {
while (it.hasNext ()) {
Строка line = it.nextLine ();
//делаем что-то с линией
}
} в конце концов {
it.close ();
}
}
См. также: Эффективная Java, 2nd edition , Пункт 47: Знать и использовать библиотеки (Автор упоминает только встроенные библиотеки JDK, но я думаю, что рассуждения может быть правдой и для других библиотек.)
Вместо того, чтобы обернуть читателя в итераторе, вы можете также обернуть его в Iterable
, который затем вернет итератор.
Это позволит вам написать следующие
for (Строка: linesOf (reader)) {
//...
}
, который делает очень чистый код.
По-моему, demoA ()
в порядке, как есть.
Назначение в качестве побочного эффекта в рамках теста обычно неодобрительно, но это использование является отличным примером того, почему существует языковая функция. Он компактен, не повторяется, идиоматичен и эффективен. Используйте его и не чувствуйте себя виноватым в этом!
Пожалуйста, поймите, что
if (cond (var = expr))
обычно можно переписать как
var = expr;
if (cond (var)) ...
и
while (cond (var = expr))
может всегда переписываться как
for (var = expr; cond (var); var = expr)
, даже не затрагивая значение break;
или continue;
в цикле.
Таким образом, довольно редко возникает необходимость в назначении cramming в условия условных выражений.
Возможно, вы также можете сделать что-то подобное:
Files.lines (путь)
Он получает все строки из файла в виде потока, затем вы можете сортировать строку на основе вашей логики, а затем собирать ее в списке и записывать в выходной файл.
Этот ответ дает вам подход к функциональному программированию. Большая часть метода не требует пояснений.
Files.lines (Paths.get (путь)). map (- Ваша бизнес-логика--);
В паровом API доступны различные функции, которые облегчают вашу обработку.