Java Reference
In-Depth Information
available()
methods as
java.io.InputStream
. In some cases, such as
BufferedIn
putStream
and
BufferedOutputStream
, these may be the only methods the filter has.
The filtering is purely internal and does not expose any new public interface. However,
in most cases, the filter stream adds public methods with additional purposes. Some‐
times these are intended to be used in addition to the usual
read()
and
write()
meth‐
ods, like the
unread()
method of
PushbackInputStream
. At other times, they almost
completely replace the original interface. For example, it's relatively rare to use the
write()
method of
PrintStream
instead of one of its
print()
and
println()
methods.
Chaining Filters Together
Filters are connected to streams by their constructors. For example, the following code
fragment buffers input from the file
data.txt
. First, a
FileInputStream
object
fin
is
created by passing the name of the file as an argument to the
FileInputStream
con‐
structor. Then, a
BufferedInputStream
object
bin
is created by passing
fin
as an ar‐
gument to the
BufferedInputStream
constructor:
FileInputStream
fin
=
new
FileInputStream
(
"data.txt"
);
BufferedInputStream
bin
=
new
BufferedInputStream
(
fin
);
From this point forward, it's possible to use the
read()
methods of both
fin
and
bin
to
read data from the file
data.txt
. However, intermixing calls to different streams con‐
nected to the same source may violate several implicit contracts of the filter streams.
Most of the time, you should only use the last filter in the chain to do the actual reading
or writing. One way to write your code so that it's at least harder to introduce this sort
of bug is to deliberately overwrite the reference to the underlying input stream. For
example:
InputStream
in
=
new
FileInputStream
(
"data.txt"
);
in
=
new
BufferedInputStream
(
in
);
After these two lines execute, there's no longer any way to access the underlying file
input stream, so you can't accidentally read from it and corrupt the buffer. This example
works because it's not necessary to distinguish between the methods of
InputStream
and those of
BufferedInputStream
given that
BufferedInputStream
is simply used
polymorphically as an instance of
InputStream
. In cases where it is necessary to use the
additional methods of the filter stream not declared in the superclass, you may be able
to construct one stream directly inside another. For example:
DataOutputStream
dout
=
new
DataOutputStream
(
new
BufferedOutputStream
(
new
FileOutputStream
(
"data.txt"
)));
Although these statements can get a little long, it's easy to split the statement across
several lines, like this:
DataOutputStream
dout
=
new
DataOutputStream
(
new
BufferedOutputStream
(