Лучший цикл Java? - PullRequest
       24

Лучший цикл Java?

4 голосов
/ 20 мая 2011

У меня есть кусок кода, чтобы прочитать InputStream и записать содержимое в OutputStream:

BufferedInputStream in = new BufferedInputStream(...);
FileOutputStream outStream = new FileOutputStream outStream(...);

int read = in.read(buffer, 0, bufferSize);
while (read != -1) {
    outStream.write(buffer, 0, read);
    read = in.read(buffer, 0, bufferSize);
}

Это работает, но мне не нравится, так как переменная readобъявляется вне цикла, а метод read() записывается дважды.Пересмотренная версия:

 for (int read = 0; read != -1; read = in.read(buffer, 0, bufferSize)) {
      outStream.write(buffer, 0, read);
 }

Выглядит лучше, но недостаточно хорошо, потому что первая итерация бесполезна (и может быть вредна) с read = 0.

У вас есть лучшее решение?

Ответы [ 4 ]

10 голосов
/ 20 мая 2011

Лично я нарушаю обычное правило «без побочных эффектов в состоянии» для такого рода вещей:

int bytesRead;
while ((bytesRead = in.read(buffer, 0, bufferSize)) != -1)
{
    outStream.write(buffer, 0, bytesRead);
}

РЕДАКТИРОВАТЬ: Как уже отмечалось, действительно включает объявление read вне цикла, но он вызывает read() только один раз.Я никогда не считал, что это является проблемой - хотя я обычно предпочитаю объявлять переменные с настолько малой областью видимости, насколько это возможно, это более общая вещь, связанная с чистотой.Если вы хотите еще больше ограничить область действия, вы можете поместить все это в фигурные скобки или извлечь ее в свой собственный метод, такой как подход Алана.Вот как я бы это реализовал:

public static void copyStream(InputStream input, OutputStream output)
    throws IOException {
  byte[] buffer = new byte[1024 * 16]; // Reasonable general size

  int bytesRead;
  while ((bytesRead = in.read(buffer, 0, buffer.length)) != -1) {
    outStream.write(buffer, 0, bytesRead);
  }
}

В качестве альтернативы вы можете указать длину буфера в качестве параметра.Обратите внимание, что теперь это может быть включено в служебную библиотеку, и вам больше не нужно писать код.

В качестве альтернативы, вы можете использовать тот факт, что он уже доступен в других служебных библиотеках, таких как Guava как ByteStreams.copy

3 голосов
/ 20 мая 2011

Это не блестяще, но с помощью простого блока вы можете остановить доступ к переменной read позже в методе:

BufferedInputStream in = new BufferedInputStream(...);
FileOutputStream outStream = new FileOutputStream outStream(...);

{
    int read = in.read(buffer, 0, bufferSize);
    while (read != -1)
    {
        outStream.write(buffer, 0, read);
        read = in.read(buffer, 0, bufferSize);
    }
}

// ...rest of your code

... но я согласен, я также частохотел цикл while, где проверяемое значение инициализируется внутри цикла.Насколько я знаю, это невозможно.

Еще один способ сделать это - использовать шаблон проектирования метода , чтобы вывести этот цикл в совершенно отдельный метод, то есть * 1009.*

public void yourMethod() {
    BufferedInputStream in = new BufferedInputStream(...);
    FileOutputStream outStream = new FileOutputStream outStream(...);

    this.writeToOutputStream(in, outStream);
}

private void writeToOutputStream(InputStream in, OutputStream outStream) {
    int read = in.read(buffer, 0, bufferSize);
    while (read != -1)
    {
        outStream.write(buffer, 0, read);
        read = in.read(buffer, 0, bufferSize);
    }
}
3 голосов
/ 20 мая 2011

Вы можете сделать это так:

BufferedInputStream in = new BufferedInputStream(...);
FileOutputStream outStream = new FileOutputStream outStream(...);

while (true) { // can i use for(;;) in Java ???
    int read = in.read(buffer, 0, bufferSize);
    if (read == -1) break;
    outStream.write(buffer, 0, read);
}

Он использует break, хотя. Некоторые люди говорят, что break плохой / не очень хороший стиль.

2 голосов
/ 20 мая 2011

Эта форма довольно обычна:

while ((read = in.read(buffer, 0, bufferSize)) != -1) {
  ...
}

, но не так хороша для ясности ИМО.

...