Why we need the PrintStream class

Published in the Java Developer group
Hi! Today we'll talk about the PrintStream class and everything it can do.  Why we need the PrintStream class - 1Actually, you are already familiar with two methods of the PrintStream class. They are print() and println(), which you probably use every day :) Because the System.out variable is a PrintStream object, you are calling one of this class's methods when you call System.out.println().  The general purpose of the PrintStream class is to send information to some stream.  This class has several constructors. Here are some of the most commonly used:
  • PrintStream(OutputStream outputStream)
  • PrintStream(File outputFile) throws FileNotFoundException
  • PrintStream(String outputFileName) throws FileNotFoundException
For example, we can pass the name of the output file to the PrintStream constructor. Alternatively, we can pass a File object. Let's look at some examples to see how this works:

import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.PrintStream; 

public class Main { 

   public static void main(String arr[]) throws FileNotFoundException 
   { 
       PrintStream filePrintStream = new PrintStream(new File("C:\\Users\\Username\\Desktop\\test.txt")); 

       filePrintStream.println(222); 
       filePrintStream.println("Hello world"); 
       filePrintStream.println(false); 

   } 
}
This code will create a test.txt file on the desktop (if it doesn't already exist) and sequentially write our number, string, and boolean to it. Here are the file contents after we run the program:

222 
Hello world!
false
As we said above, you don't have to pass a File object. It's enough to simply pass the file path to the constructor:

import java.io.FileNotFoundException; 
import java.io.PrintStream; 

public class Main { 

   public static void main(String arr[]) throws FileNotFoundException 
   { 
       PrintStream filePrintStream = new PrintStream("C:\\Users\\Username\\Desktop\\test.txt"); 

       filePrintStream.println(222); 
       filePrintStream.println("Hello world"); 
       filePrintStream.println(false); 
   } 
}
This code does the same as the previous code. Another interesting method worth our attention is printf(), which produces output based on a format string. What is a "format string"? Let me give an example:

import java.io.IOException; 
import java.io.PrintStream; 

public class Main { 

   public static void main(String[] args) throws IOException { 

       PrintStream printStream = new PrintStream("C:\\Users\\Steve\\Desktop\\test.txt");

       printStream.println("Hello!"); 
       printStream.println("I'm a robot!"); 

       printStream.printf("My name is %s. I am %d!", "Amigo", 18); 

       printStream.close(); 
   } 
}
Here, instead of explicitly stating our robot's name and age in the string, we put placeholders for this information, represented by %s and %d. And we pass as arguments the data that will replace them. In our case, this is the string "Amigo" and the number 18. We could create another placeholder, say %b, and pass another argument. Why do we need this? Above all, for greater flexibility. If your program requires you to display a welcome message often, you would have to manually type out the necessary text for each new robot. You can't even make this text a constant, since everyone has different names and ages! But using this new method, you can isolate the greeting in a constant and, if necessary, simply change the arguments passed to the printf() method.

import java.io.IOException; 
import java.io.PrintStream; 

public class Main { 

   private static final String GREETINGS_MESSAGE = "My name is %s. I am %d!"; 

   public static void main(String[] args) throws IOException { 

       PrintStream printStream = new PrintStream("C:\\Users\\Steve\\Desktop\\test.txt"); 

       printStream.println("Hello!"); 
       printStream.println("We are robots!"); 


       printStream.printf(GREETINGS_MESSAGE, "Amigo", 18); 
       printStream.printf(GREETINGS_MESSAGE, "R2-D2", 35); 
       printStream.printf(GREETINGS_MESSAGE, "C-3PO", 35); 

       printStream.close(); 
   } 
} 

Replacing System.in

In this lesson, we will "fight the system" and learn how to replace the System.in variable in order to redirect system output to wherever we want. Why we need the PrintStream class - 2You might forget what System.in is, but no CodeGym student will ever forget this construct:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.in  (just like System.out) is a static variable of the System class. But unlike System.out, it references another class, namely InputStream. By default, System.in is a stream that reads data from a system device — the keyboard. However, just as with System.out, we can replace the keyboard as the data source. We can read data from wherever we want! Let's look at an example:

import java.io.*; 

public class Main { 

   public static void main(String[] args) throws IOException { 

       String greetings = "Hi! My name is Amigo!\nI'm learning Java on the CodeGym website.\nOne day I will become a cool programmer!\n"; 
       byte[] bytes = greetings.getBytes(); 

       InputStream inputStream = new ByteArrayInputStream(bytes); 

       System.setIn(inputStream); 

       BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 

       String str; 

       while ((str = reader.readLine())!= null) { 

           System.out.println(str); 
       } 

   } 
}
So what did we do? System.in is usually bound to the keyboard. But we don't want to read data from the keyboard: let's have the data be read from an ordinary string! We created a string and got it as a byte array. Why do we need bytes? The thing is that InputStream is an abstract class, so we can't create an instance of it directly. We have to choose one of its descendants. For example, we can choose ByteArrayInputStream. It is simple, and its name alone tells us how it works: its data source is a byte array. So we create a byte array and pass it to the constructor of our stream that will read the data. And now everything is ready! Now we just need to use the System.setIn() method to explicitly set the value of the in variable. With out, you will recall, it was also not possible to set the variable's value directly: we had to use the setOut() method. After we assign our InputStream to the System.in variable, we want to check whether we have achieved our purpose. Our old friend BufferedReader comes to our aid here. Normally, this code would have opened the console in IntelliJ IDEA and then read data you entered from the keyboard.

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 

       String str; 

       while ((str = reader.readLine())!= null) { 

           System.out.println(str); 
       }
But now when you run it, you will see that our string is simply displayed in the console. There is no reading from the keyboard. We replaced the data source. It is no longer the keyboard, but our string! It's that simple :) In today's lesson, we got to know a new class and explored a small new hack for working with I/O. Now it's time to return to the course and complete some tasks :) See you in the next lesson!

More reading:

Comments (17)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Aldo Luna Bueno Level 26, Peru
23 March 2022
Intersting. How could this input change be reversed?
Hoa Nguyen Level 28, Australia
17 February 2022
Such a clear explanation!! thank you!
Ryan Palmer Level 20, Philadelphia, United States
9 August 2021
This really cleared up a lot of confusion. I'd recommend reading this before some of the exercises - if you stumble upon it.
Andrei Level 41
18 January 2021
Very nice article, made things much clearer.
Chandan Thapa Level 22, Dubai, United Arab Emirates
30 December 2020
just a quick thought on the last topic - Replacing System.in - i get that we can modify the existing function in the class and it works as per we need. but whats the purpose of this? do we need to do this when we start working at our jobs and if yes then where are its applications? some clarity would be great!
Agent Smith Level 38
6 September 2020
No CodeGym student will ever forget this construct:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Indeed. :D
BlueJavaBanana Level 37
28 May 2020
I'm unsure what this means: Because the System.out variable is a PrintStream object, you are calling one of this class's methods when you call System.out.println().  Can anyone clear this up/explain in a different way?
Oregano Level 24, Warsaw, Poland
16 May 2020
"For example, we can choose ByteArrayOutputStream. It is simple, and its name alone tells us how it works: its data source is a byte array. Shouldn't it be ByteArrayInputStream?