6

Following is the code from java.lang.System class (JDK version 1.6)

public final static PrintStream out = nullPrintStream(); //out is set to 'null'

private static PrintStream nullPrintStream() throws NullPointerException {
    if (currentTimeMillis() > 0) {
        return null;
    }
    throw new NullPointerException();
}

when we write System.out.println("Something"); in our code then why don't we get NullPointerException even when 'out' is set to 'null'

Anyhow out will be set via following setOut method in System class

public static void setOut(PrintStream out) {
     checkIO();
     setOut0(out);
 }

Theyn why JLS needs nullPrintStream method ?

AmitG
  • 10,365
  • 5
  • 31
  • 52
  • `if (currentTimeMillis() > 0) { return null; }` => that's really odd.. In JDK 7, it is simply: `public final static PrintStream out = null;`. – assylias Mar 22 '13 at 08:51
  • 1
    @assylias It's all there to placate the earlier versions of javac/JIT compilers. Without that `if` the compiler could realize it always returns `null` and compile `out` as a compile-time constant, with all the bad consequences. – Marko Topolnik Mar 22 '13 at 08:56
  • This means that once enough time has passed to make the value of `currentTimeMillis()` overflow the maximum value for a `long`, all applications running with virtual machines older than Java 7, will fail with an error: `java.lang.ExceptionInInitializerError Caused by java.lang.NullPointerException at java.lang.System.nullPrintStream(Unknown Source)` or similar. – gparyani Aug 14 '13 at 22:21
  • See also http://stackoverflow.com/questions/5951464/java-final-system-out-system-in-and-system-err – Raedwald Oct 04 '13 at 07:25

3 Answers3

8

Take a look at the private static void initializeSystemClass() - this method is called to start things up, it calls setOut0() which is a native method. This ties the Stream into where it's supposed to be.

So even though the field may look public static final it actually isn't, the native code changes it.

EDIT

OP asks Then why JLS needs nullPrintStream method?

This is to do with the java compiler - it will "inline" static final fields if they are assigned to something constant at compile time, like null. The compiler will actually replace each reference to the field with the constant.

This would break the initialisation as objects would no longer hold a reference to the Stream but to null. Assigning the stream to the return of a method prevents the inlining.

Some might call it a dirty hack. To misquote Bismarck "The JDK is like sausages, it's best not to see it being made".

Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
  • Although as commented above, in Java 7 it has been rectified - so it has to do with older compilers as indicated by Marko. – assylias Mar 22 '13 at 09:14
  • They could have defined `public final static PrintStream out = null;`. Help to understand "lnline" static final field. – AmitG Mar 22 '13 at 09:38
  • 2
    @AmitG take a look at [this](http://stackoverflow.com/questions/5173372/java-static-final-values-replaced-in-code-when-compiling) and [this](http://docs.oracle.com/javase/specs/jls/se7/html/jls-13.html#jls-13.4.9). If you define something as a compile time constant the (Java 6) compiler would use that information to optimise code - it would replace any references with the literal. So anything that said `System.out` would be replaced with `null` by the compiler as it assumes that `System.out` cannot change being as it is set to `null` and it is `final`. – Boris the Spider Mar 22 '13 at 09:56
  • +1 for a beautiful explanation. If I could - I would give +2 for the quote at the end :) – Nir Alfasi Aug 14 '13 at 21:53
2

This is just how the System.out class is intialised.

There is also a method:

 private static native void setOut0(PrintStream out);

Which is called in the following method:

private static void initializeSystemClass() {
cowls
  • 24,013
  • 8
  • 48
  • 78
2

System.in, out, and err are managed by the JVM from native code. This whole magic with nullPrintStream() was there to keep javac from inlining these fields. Since java 7 it looks like

public final static PrintStream out = null;
Denis Tulskiy
  • 19,012
  • 6
  • 50
  • 68