Przeczytaj
Jak komunikuje się program komputerowy
Naszym zadaniem jest napisanie programu spełniającego funkcję kalkulatora. W jaki sposób będziemy wprowadzać do niego dane? Mamy dostęp do kodu źródłowego i to bezpośrednio w nim możemy edytować wartości zmiennych. Zauważmy, że program napisany w ten sposób, choć może być dobrym ćwiczeniem programistycznym, jest po prostu nieużyteczny. Każdorazowa zmiana danych, na których operujemy w programie, wymagałaby edycji kodu źródłowego, a poza tym nikt inny nie mógłby z niego korzystać.
Użytkownik może wprowadzać informacje do programu np. za pomocą klawiatury.
Nawet najprostszy program wyświetlający napis „Hello World” korzysta z operacji wyjściowej System.out
.
Obie wymienione operacje: pobierania i wypisywania danych, są wykonywane z użyciem strumieni.
Strumienie wejścia/wyjścia, czyli I/O
Programy napisane w języku Java komunikują się z nami za pomocą strumieni I/O (Input/Output). Wyróżniamy następujące strumienie:
System.in
– wejścia,System.out
– wyjścia,System.err
– szczególny rodzaj strumienia wyjścia służący do obsługi wszelkiego rodzaju wyjątków – błędów w programie.
Jeżeli korzystasz ze środowiska programistycznego Eclipse, błędy, które wypisują się w konsoli IDEIDE, są komunikowane za pomocą strumienia System.err
i czerwonej czcionki.
Strumienie są najczęściej podłączone do źródła, takiego jak np. baza danych, plik itp. My posłużymy się danymi wprowadzanymi przez użytkownika z klawiatury.
Obiekt Scanner
Stwórzmy zatem najprostszy strumień wejścia za pomocą obiektu klasy Scanner
, czyli klasy potrzebnej do odczytania danych wprowadzanych przez użytkownika.
W tym celu stworzymy klasę UserInput
z metodą główną main()
.
Aby utworzyć obiekt typu Scanner
, musimy stworzyć instancję, czyli egzemplarz klasy Scanner
wewnątrz naszej metody main()
. W konstruktorzekonstruktorze klasy Scanner
znajduje się System.in
. Jest to strumień wejścia, na którym będziemy operować.
Robimy to w następujący sposób:
Jest to ogólny schemat tworzenia obiektów w języku Java.
Wpisujemy najpierw nazwę klasy, której instancję (obiekt) chcemy utworzyć, potem nazwę obiektu (nadaną przez nas), następnie operator przypisania =, słowo kluczowesłowo kluczowe new
(służące do tworzenia obiektów) i ponownie nazwę klasy.
Jeśli obiektowi nadamy np. nazwę scanner
, całe wywołanie będzie wyglądać następująco:
Należy jednak pamiętać, że aby korzystać z klasy Scanner
, musimy zaimportować odpowiedni pakiet języka Java, który zawiera klasę Scanner
:
Jeżeli korzystasz ze środowiska programistycznego Eclipse i użyjesz klasy Scanner
bez importowania odpowiedniego pakietu, pojawi się błąd w postaci małej litery x na czerwonym tle w linijce, gdzie została użyta klasa Scanner
. Wtedy wystarczy kliknąć w ikonę żaróweczki obok litery x, a Eclipse podpowie, jak rozwiązać ten problem.
Należy zwracać uwagę na stosowanie małych i wielkich liter w kodzie programu.
Strumienie są wbudowane w SDKSDK języka Java i dostępne bez konieczności importu. Zauważmy, że użycie instrukcji System.in
nie spowodowało przerwania procesu kompilacji. Jednak wiele pakietów dostępnych w języku Java wymaga dodatkowego zaimportowania. Nie importujemy za każdym razem wszystkich, ponieważ znacząco spowolniłoby to pracę IDE, gdyby przy uruchomieniu najprostszej klasy program musiał przechodzić przez niezliczone pakiety i biblioteki dostępne w języku Java. W omawianej klasie zaimportowaliśmy jedynie klasę Scanner
z obszernego pakietu java.util
. Gdybyśmy jednak chcieli zaimportować cały pakiet util
, zamiast:
musielibyśmy wpisać:
Stworzyliśmy obiekt klasy Scanner
, na którym będzie teraz można wywoływać metody pozwalające na odczyt różnych typów danych.
W języku Java metody można wywoływać tylko na obiektach lub bezpośrednio na klasach. Na typach prymitywnych (takich jak int
czy double
) nie da się tego zrobić.
Użyjmy utworzonego wcześniej obiektu klasy Scanner
. Spróbujmy zapisać do łańcucha znaków String imie
tekst pobrany od użytkownika. Zrobimy to w następujący sposób:
W języku Java metody na obiektach wywołujemy za pomocą kropki.
Powyższy program pobierze ciąg znaków wprowadzony przez użytkownika, następnie zapisze go w zmiennej imie
, a za pomocą strumienia wyjściowego System.out
wypisze na ekran konsoli.
Metoda next()
odczytuje dane do napotkania pierwszego białego znaku (spacji), a zatem może odczytać jedno słowo.
Do powyższego programu można dopisać linię odpowiedzialną za interakcję z użytkownikiem – za pomocą metody println()
wypiszemy na standardowym wyjściu informację, co ma zrobić, jakie dane ma wprowadzić itp.:
Po uruchomieniu programu na standardowym wyjściu pojawi się:
Następnie program oczekuje na wprowadzanie danych. Po wprowadzeniu:
zostanie wypisane:
System wydrukował na ekran konsoli jedynie słowo „Jan”, ponieważ użyliśmy metody next()
, która odczytuje ciąg znaków do momentu pojawienia się spacji. Gdybyśmy chcieli odczytać całą linijkę, musielibyśmy użyć metody nextLine()
.
Metody obiektu Scanner
Klasa Scanner
oferuje nam szereg metod odczytu danych od użytkownika. W języku Java nie jest to jednak taki łatwy mechanizm. Pamiętaj, że Java jest językiem o silnym typowaniu. W związku z tym odczytuje dane jako jakiś konkretny typ.
Chcąc pobrać od użytkownika np. dane dotyczące jego wieku, można to zrobić w sposób identyczny jak zaprezentowany wcześniej i zapisać w zmiennej String
. Jednak wtedy wprowadzona wartość będzie ciągiem znaków, a więc nie będzie można na niej wykonywać żadnych działań matematycznych. W takim przypadku wiek podany przez użytkownika należy zapisać do zmiennej typu int
. Robimy to w następujący sposób:
Obiektu Scanner
możemy używać wielokrotnie w obrębie klasy, ponieważ w języku Java jest możliwość wielokrotnego używania obiektów. Nie należy tworzyć obiektów, kiedy nie ma takiej potrzeby.
Kiedy tworzymy obiektu typu Scanner
:
Jednocześnie otwieramy strumień wejścia za pomocą System.in
w argumencie.
Dlatego dobrym nawykiem jest używanie metody zamykającej strumień:
Wprawdzie może on się zamknąć sam, ale nie wiemy na pewno, czy tak się stanie. Strumienie działają na mechanizmach niskopoziomowych, takich jak jądro systemu, dlatego programując w języku Java, nie do końca mamy nad nimi kontrolę. Przy dostępie jedynie do danych wpisywanych przez użytkownika w konsoli prawdopodobnie nie będzie to problem, jednak w przypadku pracy z plikami czy dużą bazą danych mógłby wystąpić błąd typu Resource Leak, czyli wyciek zasobów.
Metoda useLocale
Może się zdarzyć, że przy wprowadzaniu danych typu double
(545.43243d) czy float
(6.75f) pojawi się błąd, który będzie trudny do zinterpretowania:
Metody takie jak nextInt()
czy nextFloat()
wymagają wprowadzenia liczb w odpowiednim formacie. W przypadku nextInt()
klasa Scanner
oczekuje ciągu cyfr, który zamieniony na liczbę znajdzie się w zakresie danych, które może przechowywać typ int
. Sytuacja komplikuje się dla metod nextFloat()
czy nextDouble()
– w zależności od ustawień regionalnych systemu operacyjnego użytkownika separatorem rozdzielającym część całkowitą liczby od części ułamkowej może być kropka lub przecinek.
Jeśli wpisaliśmy liczbę typu double
czy float
, używając kropki, a otrzymaliśmy powyższy błąd, to znaczy, że Scanner
nie umiał poprawnie zinterpretować liczby, co najprawdopodobniej ma związek z ustawieniami regionalnymi (locale
). Rozwiązaniem problemu jest wprowadzenie liczby z użyciem przecinka.
Jeżeli jednak chcesz wczytywać liczby w formacie anglojęzycznym, możesz użyć metody useLocale()
na obiekcie typu Scanner
, gdzie argumentem w nawiasach będzie obiekt Locale
oraz nazwa danego języka lub kraju bądź też inna metoda, np.:
Teraz Scanner
będzie wczytywał i interpretował dane zgodnie ze standardami języka angielskiego.
Klasę Locale
, podobnie jak Scanner
, będziemy musieli zaimportować z pakietu java.util;
Napisz program w języku Java do obliczenia wartości BMR, czyli Basal Metabolic Rate (po polsku PPM – podstawowa przemiana materii) dla kobiet, który na podstawie wprowadzonych danych będzie obliczał podstawowe zapotrzebowanie na kalorie użytkowniczki.
BMR liczymy, wykorzystując następujący wzór:
Specyfikacja problemu:
Dane:
imie
– ciąg znaków; imię użytkowniczkiwaga
– liczba zmiennoprzecinkowa dodatnia; waga użytkowniczki w kgwzrost
– liczba zmiennoprzecinkowa dodatnia; wzrost użytkowniczki w cm
Wynik:
Program prezentuje podstawowe zapotrzebowanie na kalorie użytkowniczki.
Implementację zacznijmy od stworzenia klasy CalcBMR
z metodą main()
.
Zaczynamy od utworzenia obiektu typu Scanner.
Za pomocą metody getDefault()
w parametrze metody useLocale()
wymuszamy domyślne ustawienia regionalne (dla Polski) – aby polski użytkownik, wpisując liczby, mógł intuicyjnie używać przecinka. Nasz kalkulator może wyglądać np. tak:
Przykładowa, interaktywna sesja z użytkowniczką może wyglądać następująco:
Wartość BMR nie jest jednak zbyt czytelna. Zastosujmy więc metodę z biblioteki dostępnej dla języka Java z klasy java.lang.Math
w celu zaokrąglenia wyniku do pełnej liczby. Będzie to metoda:
Wystarczy więc dopisać kilka znaków w ostatniej linijce kodu.
Po zmianach przykładowa, interaktywna sesja może wyglądać następująco:
Słownik
(ang. Integrated Development Environment); zintegrowane środowisko programistyczne; najczęściej zawiera edytor kodu źródłowego oraz wbudowany kompilator lub interpreter
specjalna metoda klasy, której wywołanie nastąpi przy inicjalizacji obiektu danej klasy
(ang. Software Development Kit); zestaw narzędzi dla programistów niezbędny w tworzeniu aplikacji korzystających z funkcjonalności danej biblioteki
słowo oznaczające polecenie, instrukcję, definicję lub deklarację w programie komputerowym; lista słów kluczowych jest zazwyczaj specyficzna dla konkretnego języka programowania; w języku Java przykładowe słowa kluczowe to: int
, for
, static
, public
, private
, class