简体   繁体   中英

Single line using write and read of streams Java

I saw like this, always :

int count = line.read(buffer, 0, buffer.length);
if (count > 0) {
  out.write(buffer, 0, count);
}

Other example

byte[] buffer = new byte[1024]; // Adjust if you want
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
  output.write(buffer, 0, bytesRead);
}

other...

  int numRead;
  while ( (numRead = is.read(buf) ) >= 0) {
      os.write(buf, 0, numRead);
  }

I never saw something like this:

  while (true) {
    try {
      output.write(BytesArray, 0, input.read(BytesArray, 0, BytesArray.length)); //Single line for read and write!!!!
    } catch (IOException e) {
        System.out.println("I can't write!");
        break;
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("I can't read!");
        break;
    }
  }

What's the problem to use a OuputStream Writing somethig readed by InputStream recently read?

Is there some problem?

EDIT InputStream.read works precisely when OutputStream.write works, and fails when the other also fails; in the same way OutputStream.write works when InputStream.read so does and stops when the other also fails to do so.

When InputStream.read(...) fails (or can not read more) this method returns -1 ; but, when OutputStream.write(...) fails (or can not write more) this method throws an IOException exception.

I personally believe that: when OutputStream.write(...) can't write should to return "-1"exactly the same way the InputStream.read(...) does when can not read.

QUESTION: believe you that InputStream.read(...) and OutputStream.write(...) they should be handled in the same manner (both returns -1 )?

NOTE: I know this method for OutputStream: public void write(...)

Using exception handling to perform control flow - when it is unnecessary because of the API - is bad practice.

If your reason for wanting to do so is so that you can write statements on one line, you should evaluate the reasons why you think it is better to write the statements on one line. My phone has a large enough screen on it to display all four examples above at the same time - and I don't code on my phone - so I can't imagine a situation where writing something on a single line "because I can write it on a single line" is a compelling-enough reason.

Also, consider whether the fact that you are able to write some of the statements on a single line really makes the code shorter overall:

while (true) {
  try {
    output.write(buffer, 0, input.read(buffer, 0, buffer.length);
  } catch (ArrayIndexOutOfBoundsException e) {
    break;
  }
}

(I am ignoring the IOException here, as you have in the first 3 examples - it needs to be handled however you write the code, so it is irrelevant to the difference between the 4 versions in terms of quantity of code).

Compare this to the equivalent code from approach 2 (the closest equivalent):

int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
  output.write(buffer, 0, bytesRead);
}

Which is a lot more concise.

But, as I have alluded to above, brevity of code is not really a measure of quality of code, so in and of itself, this is not a reason to dismiss the proposed version just yet. However, there are more fundamental reasons why it is not a good approach...


In the proposed code, there are two expected types of exception: IOException and ArrayIndexOutOfBoundsException . These are exceptions of a fundamentally different nature:

  • The IOException is expected to result from a read or write failing (which is an actual exceptional condition, and thus is an appropriate use of an exception).

    IOException is a checked exception. Checked exceptions must be handled (it is a compile-time error not to). They are designed to indicate recoverable conditions and conditions which are beyond the control of the API. For instance, if you are writing to the disk or network, you have no control over whether the disk is being filled up by another process, or if the contractors digging up the road are about to cut your fiber connection. Checked exceptions indicate "this might succeed if you try again later" (when the disk isn't as full, or the contractors have fixed the fiber)

  • The ArrayIndexOutOfBoundsException is expected to result from reaching the end of the input stream (which is not an exceptional condition, since pretty much all streams end, and thus is not an appropriate use of an exception, nor is it a necessary use of an exception, since it is detectable via the return values of read).

    ArrayIndexOutOfBoundsException is an unchecked exception, which results from a programming error - using the API in a way which it is not intended to be used. Unchecked exceptions do not need to be handled (it is not a compile-time error if you don't) because they are designed to indicate mostly unrecoverable conditions, like programming errors. For instance, if you try running some code with a particular input and it throws an unchecked exception because of a programming bug, it will throw the same unchecked exception later because it's running the same code.

As such, whilst you can catch and recover from unchecked exceptions, that is not what they were designed for (which is why you don't have to). It is easier to write the code so that the exception doesn't occur in the first place.

And that's easy in this case: the Javadoc for OutputStream says:

If off is negative, or len is negative, or off+len is greater than the length of the array b , then an IndexOutOfBoundsException is thrown.

So, meet these conditions, and you don't have to worry about it happening.

(And you'd need to have been catching IndexOutOfBoundsException instead of ArrayIndexOutOfBoundsException anyway, because some implementations of OutputStream may not throw the latter.)

But there is a deeper reason why you shouldn't rely upon catching unchecked exceptions for your control flow: you might not be detecting the condition you think you are .

An unchecked exception of any type can be thrown from anywhere in the call chain of a particular call - you might expect that it is occurring because OutputStream.write doesn't like a negative len parameter, but it can actually be called by anything else in OutputStream.write - or in InputStream.read - or in any of the other methods that they call transitively - you can't tell for sure (without inspecting the stack trace; however, the details of what you should inspect the stack trace for are implementation-specific, and thus it would take a lot of effort to make this robust enough).

If you treat this exception as meaning you've reached the end of the stream, you might actually be masking some other problem in the code that you want to know about.

So, the best thing to do is to write your code so that it does not rely upon catching a specific unchecked exception. Where it is documented that it will throw such an exception under specific circumstances, avoid those circumstances .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM