I’m a nobody, nobody is perfect, therefore I’m perfect.

System Console Support — JDK 1.6

I’m sure some of you have found the need occasionally to use the “console” input/output support provided by the JDK via System.in and System.out — if nothing else just to implement an occasional more complicated command-line “scripty” app to be run in a Linux environment and piped input in or out from/to another program.

The problem so far has been the fact that while System.out is a PrintStream instance — System.in is an InputStream implementation! So while the output deals with characters, the input deals with bytes — and you have to start wrapping it up (through a few layers!) into a BufferedReader so you can read input line by line.

Luckily, JDK 1.6 introduces a nice function on the System class : console() — which does solve these problems.

Even more, the Console class actually offers a nice printf() function for the C nostalgics — which, as you would expect, acts exactly like printf() in C! The only thing that is lacking, if you ask me, is a scanf() equivalent — that can still be achieved via a Scanner instance, however, it obviously requires more coding. I’ll come back to the whole scanf() discussion though, for now let’s have a look at printf().

Prior to this, you had a few ways of printing something like “User {username} is {years} old”:

As to be expected with something like this, there is a readLine() method, which to be honest saves anyone who’s be dealing with console-based programs the whole spaghetti code of creating a BufferedReader etc — just so you can read everything the user types till they press ENTER. Even more, you can now show a prompt and read user input in one line — System.console().readLine() can be passed the same set of parameters as printf() does: it formats the output, presenting the user with the prompt then waits for user input.

I haven’t personally ever had to use this, but for those of you who need it, there is even a readPassword() function, which obviously doesn’t display the output 🙂

I’ve put together a (very) short piece of code to exemplify this — see below (also you can download the full source code at the bottom of this post):

StringBuilder name = new StringBuilder();
MutableInt age = new MutableAge();
System.console.scanf( "Username and age:", "%s%d", name, age );

Note that I’m suggesting using the likes of StringBuilder and MutableInt (you will need Apache Commons Lang for this) — since String is not mutable, and the parameters passing in Java is by value (so passing an int means we pass a copy of the value, not a reference to the original int variable, so we can’t modify that!). This, I think, would help everyone who does any Java/Groovy system scripting — as it saves a bit of coding around the whole Scanner interface, as you can see above.

One last thing about Console — and it’s a sad one to be honest: you might have noticed in the above code the following construct:

That is because according to the System.console() JavaDoc: Returns the unique Console object associated with the current Java virtual machine, if any. So there is no guarantee that there will be a Console instance in the system 🙁 You could think “ok, fair enough, this makes sense for server apps which run in a nohup environment and log everything etc”, and in those circumstances I would guess it’s acceptable not to have a Console instance. What I don’t see as acceptable, is the current set of IDE’s (Eclipse included — as much as I rate it) all return a null for System.console()! That, annoyingly, makes the testing of any console-based Java program awkward in Eclipse: rather than simply starting the code in debug, you have to put together a bit command-line, execute it in terminal, attach Eclipse to the process… and so on — eeeewwww! So Eclipse guys, if you’re reading this, please give us a Console implementation under JDK 1.6!

As per usual, would love to hear some comments — or drop me a line — in fact would love to hear when there is an IDE there which provides a Console implementation. And more to the point, would love to find out when Eclipse does that too!