Cześć!
Nasza dzisiejsza lekcja będzie wyjątkowa!
Dawniej proces wykonywania zadań i pisania programów był prosty: piszemy kod, uruchamiamy metodę main(), program robi to, co trzeba i gotowe.
Lecz czekają nas duże zmiany! Dziś dowiemy się, jak naprawdę współpracować z programem: nauczymy go, jak reagować na nasze działania!
Zanim zaczniemy analizować kod, czy kiedykolwiek mieliście do czynienia z urządzeniem takim jak skaner? Zapewne. Wnętrze skanera jest dość skomplikowane, ale podstawowa idea jego działania jest bardzo prosta: odczytuje on dane dostarczone przez użytkownika (takie jak paszport lub polisa ubezpieczeniowa) i zapisuje te informacje w pamięci (na przykład w postaci obrazu).
Dzisiaj stworzysz swój własny skaner! Oczywiście nie będzie w stanie obsługiwać dokumentów papierowych, ale tekst nie będzie dla niego problemem :)
To do dzieła!
Zasadniczo można komunikować się z obiektem Scanner i dowiedzieć się z wyprzedzeniem, jaki typ danych na ciebie czeka. Liczba, ciąg, a może coś innego? Liczba? I jakiego rodzaju? int, short, a może long?”
Ta elastyczność daje możliwość budowania logiki programu, która zależy od zachowania użytkownika. Powinniśmy zwrócić uwagę na jeszcze jedną ważną metodę: useDelimiter().
Do tej metody przekazywany jest ciąg. Ciąg zawiera znaki, których chcesz użyć jako separatorów lub ograniczników.
Załóżmy na przykład, że nagle zainteresowaliśmy się poezją japońską i postanowiliśmy użyć naszego skanera do przeczytania haiku napisanego przez wielkiego poetę Matsuo Bashō.
Nawet jeśli trzy różne wersety zostaną nam przekazane jako jeden niezręczny ciąg, możemy je łatwo rozdzielić i pięknie renderować:
Klasa Scanner w Javie
Przede wszystkim musimy zapoznać się z klasą java.util.Scanner. Jej funkcjonalność jest bardzo prosta. Podobnie jak prawdziwy skaner, odczytuje ona dane z określonego źródła przez użytkownika. Na przykład ciąg, plik, konsolę. Następnie rozpoznaje informacje i odpowiednio je przetwarza. Oto najprostszy przykład:
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner("Nieważne, kiedy zamkną bramę\n" +
"i zechcą karą pisma skruszyć,\n" +
"Ja jestem losu swego panem\n" +
"i kapitanem własnej duszy");
String s = scanner.nextLine();
System.out.println(s);
}
}
Utworzyliśmy obiekt skanera i określiliśmy jego źródło danych (ciąg tekstu). Metoda nextLine() uzyskuje dostęp do źródła danych (naszego tekstu z czterowierszem), znajduje następny nieprzeczytany wiersz (który w tym przypadku jest pierwszym wierszem) i zwraca go. Następnie wyświetlamy go na konsoli: Wyświetlone zostanie:
Nieważne, kiedy zamkną bramę
Możemy użyć metody nextLine() kilkukrotnie i wyświetlić cały fragment wiersza:
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner("Nieważne, kiedy zamkną bramę\n" +
"i zechcą karą pisma skruszyć,\n" +
"Ja jestem losu swego panem\n" +
"i kapitanem własnej duszy");
String s = scanner.nextLine();
System.out.println(s);
s = scanner.nextLine();
System.out.println(s);
s = scanner.nextLine();
System.out.println(s);
s = scanner.nextLine();
System.out.println(s);
}
}
Za każdym razem nasz skaner robi krok do przodu i odczytuje następny wiersz. Wyświetlane są dane wyjściowe programu:
Nieważne, kiedy zamkną bramę
i zechcą karą pisma skruszyć,
Ja jestem losu swego panem
i kapitanem własnej duszy
Jak już powiedzieliśmy, źródłem danych skanera nie musi być ciąg. Może nim być np. konsola. Kilka ekscytujących wiadomości dla ciebie: poprzednio wyświetlaliśmy tam tylko dane, ale teraz będziemy je odczytywać z klawiatury! Zobaczmy, co jeszcze potrafi klasa Scanner:
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Wprowadź liczbę:");
int number = sc.nextInt();
System.out.println("Dzięki! Udało ci się wprowadzić liczbę " + number);
}
}
Metoda nextInt() odczytuje i zwraca wprowadzoną liczbę. W naszym programie używamy jej do przypisania wartości zmiennej number. To już bardziej niczym prawdziwy skaner! Program prosi użytkownika o wprowadzenie dowolnej liczby. Po wykonaniu tych czynności program dziękuje użytkownikowi, wyświetla wynik i kończy pracę. Nadal jednak mamy poważny problem. Użytkownik może popełnić błąd i wprowadzić coś niewłaściwego. Oto przykład, w którym nasz obecny program przestaje działać:
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Wprowadź liczbę:");
int number = sc.nextInt();
System.out.println("Dzięki! Udało ci się wprowadzić liczbę " + number);
}
}
Spróbujmy wprowadzić ciąg „CodeGym” zamiast liczby: Wyświetlone zostanie:
Wprowadź liczbę:
CodeGym
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Scanner.java:864)
at java.util.Scanner.next(Scanner.java:1485)
at java.util.Scanner.nextInt(Scanner.java:2117)
at java.util.Scanner.nextInt(Scanner.java:2076)
at Main.main(Main.java:10) Process finished with exit code 1
Ups. Mamy poważne kłopoty -_- Aby uniknąć takich sytuacji, musimy wymyślić sposób weryfikacji danych wprowadzanych przez użytkownika. Na przykład jeśli użytkownik wprowadzi coś innego niż liczbę, dobrze byłoby wyświetlić ostrzeżenie, że wprowadzona informacja nie jest liczbą. Natomiast jeśli informacja jest w porządku, możemy ją potwierdzić. To jednak wymagałoby od nas „spojrzenia w przyszłość”, aby zobaczyć, co nas czeka. Czy Scanner to potrafi? A jak! I ma do tego mnóstwo metod: hasNextInt() — Ta metoda sprawdza, czy następny fragment danych wejściowych jest liczbą (zwraca odpowiednio true lub false). hasNextLine() — Ta metoda sprawdza, czy następny fragment danych wejściowych jest ciągiem. hasNextByte(), hasNextShort(), hasNextLong(), hasNextFloat(), hasNextDouble() — Wszystkie te metody wykonują podobną weryfikację dla pozostałych typów danych. Spróbujmy zmienić nasz program odczytywania liczb:
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Wprowadź liczbę:");
if (sc.hasNextInt()) {
int number = sc.nextInt();
System.out.println("Dzięki! Udało ci się wprowadzić liczbę " + number);
} else {
System.out.println("Przykro mi, ale to zdecydowanie nie jest liczba. Restartuj program i spróbuj ponownie!");
}
}
}
Teraz nasz program sprawdza, czy następny wprowadzony znak jest liczbą. I wyświetla potwierdzenie tylko wtedy, gdy tak jest. Jeśli dane wejściowe nie przejdą kontroli pomyślnie, program odnotowuje ten fakt i prosi użytkownika o ponowienie próby.

public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner("Na suchej gałęzi drzewa'" +
"Posępny siedzi kruk.'" +
"Już zmierzch jesieni." +
"''***''" +
"Jesienny księżyc,'" +
"Przypływ pieni się:'" +
"U samej bramy." +
"''***''" +
"Dźwięki milkną,'" +
"Kwiaty pachną,'" +
"Dzwon zadzwonił wieczorem.");
scan.useDelimiter("'");
while (scan.hasNext()) {
System.out.println(scan.next());
}
scan.close();
}
}
Jako separatora używamy "\n/*/*/*" (znaku nowej linii i trzech gwiazdek). W rezultacie otrzymujemy piękne dane wyjściowe w konsoli, tak jak w książkach:
Na suchej gałęzi drzewa
Posępny siedzi kruk.
Już zmierzch jesieni.
***
Jesienny księżyc,
Przypływ pieni się:
U samej bramy.
***
Dźwięki milkną,
Kwiaty pachną,
Dzwon zadzwonił wieczorem.
Ten przykład ma jeszcze jedną metodę, na którą musimy zwrócić uwagę koniecznie: close(). Jak każdy obiekt pracujący ze strumieniami we/wy, skaner musi zostać zamknięty po zakończeniu pracy, aby przestał zużywać zasoby komputera. Nigdy nie zapomnij o metodzie close()!
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Wprowadź liczbę:");
int number = sc.nextInt();
System.out.println("Dzięki! Udało ci się wprowadzić liczbę " + number);
sc.close(); // Teraz wszystko zrobiliśmy dobrze!
}
}
To wszystko! Jak widać, klasa Scanner jest dość łatwa w użyciu, zważając na to, jak bardzo jest pomocna! :)
GO TO FULL VERSION