views:

167

answers:

5

I have the following class subclass of FilterInputStream with only one method overrided. However the performance of this class is so poor. It performs at 1/10 the speed of its superclass. I even took the same source code from InputStream of javasrc and used it in my subclass. Same performance hit. Is there something wrong with overriding classes?

public class NewLineStream extends FilterInputStream    {


public NewLineStream(InputStream in) {
 super(in);
}



public int read(byte[] b, int off, int len) throws IOException {  
 if (b == null) {
  throw new NullPointerException ();
 } else if ((off < 0) || (off > b.length) || (len < 0) ||
   ((off + len) > b.length) || ((off + len) < 0)) {
  throw new IndexOutOfBoundsException ();
 } else if (len == 0) {
  return 0;
 }

 int c = read();
 if (c == -1) {
  return -1;
 }
 b[off] = (byte)c;

 int i = 1;
 try {
  for (; i < len ; i++) {
   c = read();
   if (c == -1) {
    break;
   }
   if (b != null) {
    b[off + i] = (byte)c;
   }
  }
 } catch (IOException  ee) {
 }
 return i;
}

}

A: 

Yes, you read() one-by-one, if there is no underlying buffering going on, it will be really slow. Pass in a BufferedInputStream and it should speed up.

kd304
This doesn't make any sense, FilterInputStream's implementation is return in.read(b, off, len); where in is a InputStream, and InputStream's read implementation is same as mine. (I copied the source code)
erotsppa
InputStream is a base class with some default and for some cases inefficient implementation. It is used because of the 'use superclass/superinterface' idiom: InputStream in = new BufferedInputStream(new FileInputStream("a"));
kd304
+2  A: 

This method is reading byte-by-byte, I guess that's why it performs so poorly. FilterInputStreams usually are just wrapping other input streams, so if you're not going to do any filtering, just call read(byte[], int, int) on the wrapped stream.

Chochos
Don't reinvent the wheel unless you really need to. There's probably a stream class that does what you want.
mcandre
I'm not doing anything, because I'm trying to test the performance. Apparently not doing anything brings the performance down to 1/10
erotsppa
@erotsppa - You copied generic (essentially never used) code from the InputStream class that is woefully inefficient.
jsight
where can I get the actual implementation? I have a need to override read(), but without the source code for read(byte[]), I cannot do that.
erotsppa
What InputStream are you filtering? FileInputStream and ByteArrayInputStream implement the "int read(byte b[], int off, int len)" method as well as "read()" to optimise reading multiple bytes at once. Your filter forces all calls to use single-byte reads instead, which would potentially be slower (especially from Files). If you don't want to change your implementation, you could wrap the source InputStream with a a BufferedInputStream, which should improve performance somewhat. Also note that LineNumberInputStream's source looks like yours, so maybe BufferedInputStream is accceptable.
paulcm
A: 

Performance hits for overriding classes should be negligible for almost all purposes.

Perhaps the problem is in the InputStream you're decorating.

Robert Munteanu
A: 

Is there something wrong with overriding classes?

no, it doesn't.

However FilterInputStream is just a decorator around the InputStream that you pass using the contructor. I would wrap my input stream around a buffered's one, like a BufferedInputStream:

NewLineStream nws = new NewLineStream(new BufferedInputStream(in));
dfa
+1 from me. I can't explain it more detailed.
kd304
A: 

Most of the time when developers feel they have found a bug in the JDK or how Java works, its usually just a misunderstand on the part of the developer. Java is more than ten years and most common bugs have been solved already.

There more than few bad design decisions lying around which are perhaps too difficult to fix now but I cannot think of any which impacts performance or doesn't have a known work around.

Peter Lawrey