Úvod
Čas nostalgie! Čo takto si urobiť v Jave program v duchu liet nultých, keď svetu stredoškolského vyučovania programovania ešte stále vládli Pascaly? Vezmete predsa java.io.Console
, metódu readLine()
a už sa tešíte na softvér:
Zadaj meno>
Jozko
Blahozelam, volas sa Jozko
Ale žiaľ, dotešíte sa. Prečo? Lebo Console
je pokazená.
Vo všeobecnosti máte na načítanie vstupu z konzoly tri možnosti:
java.io.Console
[od verzie 6]java.util.Scanner
[od verzie 5]- kombo
BufferedReader
aInputStreamReader
(obajava.io
)
Konzola v Console
…čo nefunguje
java.io.Console
je najlepšie riešenie: získate inštanciu zo System
a rovno máte k dispozícii metódu readLine()
. Okrem toho dostanete zopár ďalších metód: spakruky readPassword()
, ktorá načíta heslo, ale na konzolu ho vyhviezdičkuje.
Použitie je priamočiare:
import java.io.Console;
public class JavaIoConsoleTest {
public static void main(String[] args) {
Console console = System.console();
String line = console.readLine();
System.out.println(">" + line);
}
}
Ak ho však spustíte v Eclipse či NetBeanse, beda!
Exception in thread "main" java.lang.NullPointerException
at JavaIoConsoleTest.main(JavaIoConsoleTest.java:7)
Jednoduché riešenie v sebe nesie zádrheľ s veľkým “Z” — lebo kto číta dokumentáciu v takýchto jednoduchých prípadoch?
If the virtual machine is started automatically, for example by a background job scheduler, then it will typically not have a console. [..] If no console device is available then an invocation of that method will return null.
V preklade: virtuálny stroj nemusí mať asociovanú konzolu, a preto môže System.console()
vracať null
.
Taký Eclipse neráči asociovať konzolu a otrieska nás o hlavu výnimkou. Že či to dáva zmysel? Nedáva a to si myslí viacero ľudí — už od konca roku 2005 existuje v issue trackeri zadaná chyba. Volá sa 122429 a je stále nevyriešená.
Návrhy na riešenie sú kadejaké divoké, ale obvykle v sebe nesú nutnosť spustiť projekt mimo IDE, v debug režime a ladiť ho ako vzdialenú (remote) aplikáciu, čo je celkom strašné vúdú. (A bohužiaľ, ani Ant v tomto nepomôže, ten trpí rovnakým problémom).
Konzola v Scanner
-i
Scanner
je fakt užitočná trieda, ktorá dokáže scanovať z hocičoho — súboru, reťazca a samozrejme z konzoly. Stačí ho vytvoriť nad štandardným vstupom, System.in
a fungovať.
import java.util.Scanner;
public class JavaUtilScannerTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String line = scanner.nextLine();
System.out.println(">" + line);
}
}
Naozaj fungovať, lebo tu sa žiadne prekvapenia nedejú, funguje to bez problémov vo vnútri každého IDE. Samozrejme, musíte obetovať napr. metódu pre načítanie vyhviezdičkovaného hesla.
Konzola v starých Javách
Ak vás vietor zaveje do starej Javy a nemáte k dispozícii Scanner
, môžete použiť klasickú kombináciu BufferedReader
a InputStreamReader
a nad System.in
:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class BufferedReaderTest {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line = reader.readLine();
System.out.println(">" + line);
}
}
Premenná System.in
je totiž klasický prúd bajtov InputStream
, ktorý je nutné obaliť InputStreamReaderom
, čím získame prúd znakov. Buffrovanie poskytne možnosť načítavať zo vstupu po riadkoch. Významný rozdielom oproti Scanner
u je vyhadzovanie výnimky IOException
, kebyže sa niečo pri načítavaní znakov pobabralo.
Samozrejme, i toto funguje v IDE bez problémov, aj keď je to už historický prístup.
Záver
Cesta do pekla je dlaždená dobrými úmyslami — zdanlivo jednoduchá Console
je prakticky nepoužiteľná. Na druhej strane… koľkokrát vyvíjate čisto konzolové aplikácie, ktoré potrebujú načítavať vstup od používateľa? A koľkokrát chcete od neho heslo? Ak to naozaj treba, musíte to spúšťať mimo IDE. V opačnom prípade je Scanner
smerom istoty.