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!
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("It matters not how strait the gate,\n" +
"How charged with punishments the scroll,\n" +
"I am the master of my fate,\n" +
"I am the captain of my soul");
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:
It matters not how strait the gate,
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("It matters not how strait the gate,\n" +
"How charged with punishments the scroll,\n" +
"I am the master of my fate,\n" +
"I am the captain of my soul");
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:
It matters not how strait the gate,
How charged with punishments the scroll,
I am the master of my fate,
I am the captain of my soul
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("Enter a number:");
int number = sc.nextInt();
System.out.println("Thanks! You entered the number " + 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("Enter a number:");
int number = sc.nextInt();
System.out.println("Thanks! You entered the number " + number);
}
}
Spróbujmy wprowadzić ciąg „CodeGym” zamiast liczby: Wyświetlone zostanie:
Enter a number:
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("Enter a number:");
if (sc.hasNextInt()) {
int number = sc.nextInt();
System.out.println("Thanks! You entered the number " + number);
} else {
System.out.println("Sorry, but this is clearly not a number. Restart the program and try again!");
}
}
}
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.
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ć:
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner("On a withered branch'" +
"A crow has alighted.'" +
"Nightfall in autumn." +
"''***''" +
"Such a moon above,'" +
"Like a tree cut at the root:'" +
"he fresh cut is white." +
"''***''" +
"How the river floods!'" +
"A heron wanders on short legs,'" +
"Knee-deep in the water.");
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:
On a withered branch
A crow has alighted.
Nightfall in autumn.
***
Such a moon above,
Like a tree cut at the root:
The fresh cut is white.
***
How the river floods!
A heron wanders on short legs,
Knee-deep in the water.
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("Enter a number:");
int number = sc.nextInt();
System.out.println("Thanks! You entered the number " + number);
sc.close(); // Now we've done everything right!
}
}
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