"Hello, Amigo! Now I'll tell you about two interfaces: InputStream and OutputStream. They are declared as abstract classes, but if you dig deeper you can see that they are essentially interfaces. Almost all of their methods are abstract, except for a few insignificant methods. They are very much like the "bodyguard" we considered earlier."

These are very interesting interfaces. For now, I'm going to deliberately call them interfaces, so you understand why we need them. And then we'll talk about why they are actually abstract classes.

"Okay. So what are these interfaces?"

"I'll tell you without further ado."

Java has this interesting thing called a «stream». A stream is a very simple entity. And its simplicity is the key for a very powerful way to exchange data. There are two types of streams: streams for reading and streams for writing.

As you probably already guessed, you can write data to a stream for writing. It has a write method for this. You can read data from a stream for reading. It has a read() method for this.

InputStream is the interface for a stream that supports reading. It defines the following ability: «bytes can be read from me».

Similarly, OutputStream, an OutputStream is an interface for a stream that supports writing. It defines the following ability: «bytes can be written to me».

"That's it?"

"Pretty much. But the whole point is that Java has loads of classes that can work with InputStream and OutputStream. For example, you want to read a file from disk and display its contents on the screen. Nothing could be easier."

To read data from a file on disk, we have the special FileInputStream class, which implements the InputStream interface. Do you want to write this data to another file? For this, we have the FileOutputStream class, which implements the OutputStream interface. The following code shows what you need to do to copy data from one file to another.

Code
public static void main(String[] args) throws IOException
{
 InputStream inStream = new FileInputStream("c:/source.txt");
 OutputStream outStream = new FileOutputStream("c:/result.txt");

 while (inStream.available() > 0)
 {
  int data = inStream.read(); //read one byte from the input stream
  outStream.write(data); //write that byte to the other stream.
 }

 inStream.close(); //close the streams
 outStream.close();
}

Imagine that we've written a class and added the InputStream and OutputStream abilities to it.

If we properly implemented these interfaces, then instances of our class can now be saved to or read from a file. Simply by reading their contents using the read method. Or they can be loaded from a file by creating an object and using the write method to write the file contents.

"Maybe an example?"

"Sure."

Code Description
class MyClass
{
private ArrayList<Integer> list;
}
For simplicity, imagine that our class contains one object, an ArrayList that holds Integers.

Now we'll add read and write methods to it

Code Description
class MyClass
{
private ArrayList<Integer> list;
public void write(int data)
{
list.add(data);
}
public int read()
{
int first = list.get(0);
list.remove(0);
return first;
}

public int available()
{
return list.size();
}
}
Now our class implements the read method, which makes it possible to sequentially read the entire contents of list.

And the write method, which lets you write values to our list.

Of course, this isn't an implementation of the InputStream and OutputStream interfaces, but it's very similar.

"Yes, I understand. So how do you save the contents of such an object to a file?"

"Let me give you an example:"

Write a MyClass object to a file
public static void main(String[] args)
{
 MyClass myObject = new MyClass();
 OutputStream outStream = new FileOutputStream ("c:/my-object-data.txt");

 while (myObject.available() > 0)
 {
  int data = myObject.read(); //read one int from the input stream
  outStream.write(data); //write that int to the other stream.
 }

 outStream.close();
}
undefined
16
Task
Java Core, level 4, lesson 6
Locked
Chicken factory
Let's create an international chicken factory. We'll fill it with chickens from all over the world. Create a list that indicates each hen's nationality and we'll track how many eggs they lay each month. How do you do that? Using abstract classes and inheritance, of course.
Read a MyClass object from a file
public static void main(String[] args)
{
 InputStream inStream = new FileInputStream("c:/my-object-data.txt");
 MyClass myObject = new MyClass();

 while (inStream.available() > 0)
 {
  int data = inStream.read(); //read one int from the input stream
  myObject.write(data); //write that int to the other stream.
 }

 inStream.close(); //close the streams
}

"Holy moly! It really is very similar to working with InputStream/OutputStream. Streams are sweet!"

"And then some!"