250 likes | 399 Views
Streams and File I/O in Java. Eric Allen Rice University. Streams and Lazy Evaluation. Java I/O is based on the notion of streams Streams are sequences of data (whose elements may be computed on demand) Streams originated from functional programming, as an alternative to mutation.
E N D
Streams and File I/O in Java Eric Allen Rice University
Streams and Lazy Evaluation • Java I/O is based on the notion of streams • Streams are sequences of data (whose elements may be computed on demand) • Streams originated from functional programming, as an alternative to mutation
A Very Simple Stream class OneStream extends IntStream { public int next() { return 1; } }
A Slightly More Complex Stream public class NatStream { private int current = 0; public int next() { return current++; } }
Streams And Computation • Streams can be composed and filtered to produce more complex streams • Let’s apply the Union, Composite, and Command Patterns to construct composable streams of ints…
abstract class IntStream { public abstract int next(); } class NatStream extends IntStream { private int current = 0; public int next() { return current++; } }
abstract class ComposableIntStream extends IntStream { private Operator op; private IntStream left; private IntStream right; public ComposableIntStream(Operator _op, IntStream _left, IntStream _right) { op = _op; left = _left; right = _right; } public int next() { return op.apply(left.next(), right.next()); } }
abstract class Operator { public abstract int apply(int left, int right); } // for example, class Adder extends Operator { public int apply(int left, int right) { return left + right; } } // and class Multiplier extends Operator { public int apply(int left, int right) { return left * right; } }
Now we can construct all sorts of nifty composable IntStreams: class EvenStream extends ComposableIntStream { public EvenStream() { super(new Adder(), new NatStream(), new NatStream()); } } class SquareStream extends ComposableIntStream { public SquareStream() { super(new Multiplier(), new NatStream(), new NatStream()); } }
Building the Natural Numbers class ZeroStream extends IntStream { public int next() { return 0; } } class AdderStream extends ComposableIntStream { public AdderStream(IntStream left, IntStream right) { super(new Adder(), left, right); } }
Building the Natural Numbers class AlternateNatStream extends IntStream { IntStream value = new ZeroStream(); public int next() { value = new AdderStream(new OneStream(), value); return value.next(); } }
In fact, streams can be used as a foundation for all of number theory! • Exercise (optional/not for credit): Extend IntStreams to include a stream of prime numbers • Hint: define the notion of filtered streams, as a subtype of ComposableIntStreams
Applications of Streams • Streams are natural models of many real-world systems: • Stock prices • Mouse/keyboard/monitor input • Radio signals • Human input to a program (DrJava interactions) • Contents of a file
Output Streams Model Systems That Take Input • Just as we can read from sources, we can write to destinations • Output streams take input as it’s computed
I/O Streams in Java • java.io.InputStream, java.io.OutputStream • Readers, writers are adapters to streams, to make certain sorts of I/O easier
Reading from a File > FileReader fReader = new FileReader(fn); > fReader.read() 97 > (char)fReader.read() b
Writing to a File > FileWriter fWriter = new FileWriter(fn); > fWriter.write()
Testing Writers • Readers/Writers can be composed using PipedReaders and PipedWriters PipedReader pReader = new PipedReader(); PipedWriter pWriter = new PipedWriter(pReader);
Testing Writers • By always writing to a Writer field (as opposed to hard-wired System.out, etc.), you can test your classes more easily • Pass in PipedWriters in your test cases and check what’s sent to a corresponding PipedReader
Stream Tokenization • Often we want to view elements of a stream as structures larger than the elements themselves
Stream Tokenization • Consider the syntactic components of a Java program: keywords, vars, etc. class C extends D implements E {…} • These elements are more complex than just characters
Stream Tokenization In such cases, we can place a Façade stream over the original s.t. the elements of the Façade are sequences of the original elements
Stream Tokenizer • Java provides a built-in StreamTokenizer class • Warning: The design of this class is ugly • Always put an Adapter class over it first (or write your own!) • This class is very powerful, but it’s biased toward parsing Java code
Using StreamTokenizer • > Reader r = new BufferedReader(new InputStreamReader(si)); > StreamTokenizer tokenizer = new StreamTokenizer(r); > tokenizer.nextToken() 42