Ako načítavať vstup od používateľa alebo bedáky nad java.io.Console

Ú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:

  1. java.io.Console [od verzie 6]
  2. java.util.Scanner [od verzie 5]
  3. kombo BufferedReader a InputStreamReader (oba java.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 InputStreamReadera 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 Scanneru 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.

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *