Sunday 3 May 2015

How System.out.println is working in java

This java tutorial is written to explain what System.out.println is and how it works. It is love at first type. How many times have we used System.out.println till now? It is one of the most number of times compiled statement in the history of java. We shortly call it SOP.
Along with Java’s System.out.println(), at the end of this tutorial I have given a list of popular languages and their equivalent of it.
System-out-println-block-diagram

What is System.out.println

System.out.println is a Java statement that prints the argument passed, into the System.out which is generally stdout.
  • System – is a final class in java.lang package. As per javadoc, “…Among the facilities provided by the System class are standard input, standard output, and error output streams; access to externally defined properties and environment variables; a means of loading files and libraries; and a utility method for quickly copying a portion of an array
  • out – is a static member field of System class and is of type PrintStream. Its access specifiers are public final. This gets instantiated during startup and gets mapped with standard output console of the host. This stream is open by itself immediately after its instantiation and ready to accept data.
  • println – is a method of PrintStream class. println prints the argument passed to the standard console and a newline. There are multiple println methods with different arguments (overloading). Every println makes a call to print method and adds a newline. print calls write()and the story goes on like that.

Structure of System.out.println

Following is the skeletal structure of System.out.println in the JDK source. Through this code snippet the essential parts are highlighted and its given for better understanding.
System-out-println-class-diagram
public final class System {
    static PrintStream out;
    static PrintStream err;
    static InputStream in;
    ...
}

public class PrintStream extends FilterOutputStream {
    //out object is inherited from FilterOutputStream class
    public void println() {
    ...
}

Change out of System.out.println

‘out’ object can be customized. out gets initialized by java runtime environment at startup and it can be changed by developer during execution. Instead of standard output, in default cases when you run a program through command line, the output is printed in the same command window. We can change that behavior using setOut method as below. In the following example, I have redirected the output to a text file in the same directory.
public class ChangeOut {
 public static void main(String args[]) {
  try {
   System.setOut(new PrintStream(new FileOutputStream("log.txt")));
   System.out.println("Now the output is redirected!");
  } catch(Exception e) {}
 }
}

System.out.println vs loggers like Log4j

Log4J has mulitple levels for logging. If we are writing a real short program, just for experimental/learning purposes SOPs are fine. When we are developing a production quality software, we should be aware that a logging component should be used and System.out.println should be avoided. Why?
  • Flexibility: a logger like log4j provides different levels for logging. We can separate the log messages accordingly. For example, X messages should be printed only on PRODUCTION, Y messages should be printed on ERROR, etc.
  • Reconfigurability: in just one parameter change we can switch off all the logging statements.
  • Maintainability: imagine if we have hundreds of System.out.println littered all through the application, it would be difficult to maintain the program over a period.
  • Granularity: In an application, every single class can have a different logger and controlled accordingly.
  • Utility: Option for redirecting the message is limited in System.out, but in case of a logger you have appenders which provides numerous options. We can even create a custom output option and redirect it to that.
Having said all the above, we still use System.out.println for logging and debugging. Which should be strictly avoided. This is driven by (bad)habit.
I want to share how a habit became a convention. Its using ‘i’, ‘j’ as index in for-loop. In FORTRAN language, we need not declare integer variables. Variable names that start with i, j, k, l, m and n are integer variables. So, FORTRAN developers named for-loop index with i,j,k and that habit carried on to other languages.

System.out.println and Performance

There is a general notion that System.out.println are bad for performance. When we analyze deeply, the sequence of calls are like println -> print -> write() + newLine(). This sequence flow is an implementation of Sun/Oracle JDK. Both write() and newLine() contains a synchronized block. Synchronization has a little overhead, but more than that the cost of adding characters to the buffer and printing is high.
When we run a performance analysis, run multiple number of System.out.println and record the time, the execution duration increases proportionally. Performance degrades when we print more that 50 characters and print more than 50,000 lines.
It all depends on the scenario we use it. Whatever may be the case, do not use System.out.println for logging to stdout.

Static Import to Shorten System.out.println()

Sometimes we feel System.out.println is a long statement to print. static import may shorten it a bit but it is not recommended, because it results in poor readability. I am just using this situation to explain static import and avoid using it in the below scenario.
import static java.lang.System.out;

public class ShortSOP {
public static void main(String[] args) {
out.println("Hello, world");
}
}
In Eclipse you have programmed shortcuts like ctrl + spac to help you out.

System.err and System.in

As a related section, I wish to discuss about ‘err’ and ‘in’. ‘in’ is associated with InputStream. Opposite to ‘out’, ‘in’ is used to get input from standard console generally keyboard.
‘err’ is associated with PrintStream and prints the argument to the standard error output stream. When you use eclipse kind of IDE you can see the difference in ouput between ‘out’ and ‘err’.
public class InOutErr {
public static void main(String args[]) {
try {

BufferedReader reader = new BufferedReader(System.in);
String filename = reader.readLine();

  InputStream input = new FileInputStream(filename);
  System.out.println("File opened...");

} catch (IOException e){
  System.err.println("Where is that file?");
}
}
}

System.out.println Equivalent in other Languages

DBASE III+
? "Hello World"
C
 #include 
 #include 

 int main(void)
 {
  printf("Hello, world");
  return EXIT_SUCCESS;
 }
CPP
 #include 

 int main()
 {
  std::cout << "Hello, World." << std::endl;
 }
BASIC
10 PRINT "HELLO WORLD"
FORTRAN
 PROGRAM HELLOWORLD
 10 FORMAT (1X,11HHELLO WORLD)
 WRITE(6,10)
 END
COBOL
 IDENTIFICATION DIVISION.
 PROGRAM-ID. Hello.
 ENVIRONMENT DIVISION.
 DATA DIVISION.
 PROCEDURE DIVISION.
 Display 'Hello, World'.
 STOP RUN.
LISP
 (DEFUN HELLO-WORLD ()
 (PRINT (LIST 'HELLO 'WORLD)))
PROLOG
go :-
 writeln('Hello World').
System.out.println("Bye");

No comments:

Post a Comment