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.

Ciekawostka

Jeżeli korzystasz ze środowiska programistycznego Eclipse, błędy, które wypisują się w konsoli IDEIDEIDE, 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 konstruktorzekonstruktorkonstruktorze 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:

Linia 1. Scanner sc znak równości new Scanner otwórz nawias okrągły System kropka in zamknij nawias okrągły średnik.

Jest to ogólny schemat tworzenia obiektów w języku Java.

Linia 1. NazwaKlasy nazwaObiektu znak równości new NazwaKlasy otwórz nawias okrągły zamknij nawias okrągły średnik.

Wpisujemy najpierw nazwę klasy, której instancję (obiekt) chcemy utworzyć, potem nazwę obiektu (nadaną przez nas), następnie operator przypisania =, słowo kluczowesł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:

Linia 1. public static void main otwórz nawias okrągły String otwórz nawias kwadratowy zamknij nawias kwadratowy args zamknij nawias okrągły otwórz nawias klamrowy. Linia 2. Scanner scanner znak równości new Scanner otwórz nawias okrągły System kropka in zamknij nawias okrągły średnik. Linia 3. zamknij nawias klamrowy.

Należy jednak pamiętać, że aby korzystać z klasy Scanner, musimy zaimportować odpowiedni pakiet języka Java, który zawiera klasę Scanner:

Linia 1. import java kropka util kropka Scanner średnik. Linia 3. public static void main otwórz nawias okrągły String otwórz nawias kwadratowy zamknij nawias kwadratowy args zamknij nawias okrągły otwórz nawias klamrowy. Linia 4. Scanner scanner znak równości new Scanner otwórz nawias okrągły System kropka in zamknij nawias okrągły średnik. Linia 5. zamknij nawias klamrowy.
Ciekawostka

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.

Ważne!

Należy zwracać uwagę na stosowanie małych i wielkich liter w kodzie programu.

Dla zainteresowanych

Strumienie są wbudowane w SDKSDKSDK 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:

Linia 1. import java kropka util kropka Scanner średnik.

musielibyśmy wpisać:

Linia 1. import java kropka util kropka asterysk średnik.

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.

Ważne!

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:

Linia 1. import java kropka util kropka Scanner średnik. Linia 3. public class UserInput otwórz nawias klamrowy. Linia 5. public static void main otwórz nawias okrągły String otwórz nawias kwadratowy zamknij nawias kwadratowy args zamknij nawias okrągły otwórz nawias klamrowy. Linia 6. Scanner scanner znak równości new Scanner otwórz nawias okrągły System kropka in zamknij nawias okrągły średnik. Linia 7. String imie znak równości scanner kropka next otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 9. System kropka out kropka println otwórz nawias okrągły imie zamknij nawias okrągły średnik. Linia 10. zamknij nawias klamrowy. Linia 11. zamknij nawias klamrowy.
Już wiesz

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

Linia 1. import java kropka util kropka Scanner średnik. Linia 3. public class UserInput otwórz nawias klamrowy. Linia 5. public static void main otwórz nawias okrągły String otwórz nawias kwadratowy zamknij nawias kwadratowy args zamknij nawias okrągły otwórz nawias klamrowy. Linia 6. Scanner scanner znak równości new Scanner otwórz nawias okrągły System kropka in zamknij nawias okrągły średnik. Linia 7. System kropka out kropka println otwórz nawias okrągły cudzysłów Jak się nazywasz znak zapytania cudzysłów zamknij nawias okrągły średnik. Linia 8. String imie znak równości scanner kropka next otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 10. System kropka out kropka println otwórz nawias okrągły imie zamknij nawias okrągły średnik. Linia 11. zamknij nawias klamrowy. Linia 12. zamknij nawias klamrowy.

Po uruchomieniu programu na standardowym wyjściu pojawi się:

Linia 1. Jak się nazywasz znak zapytania.

Następnie program oczekuje na wprowadzanie danych. Po wprowadzeniu:

Linia 1. Jak się nazywasz znak zapytania. Linia 2. Jan Kowalski.

zostanie wypisane:

Linia 1. Jak się nazywasz znak zapytania. Linia 2. Jan Kowalski. Linia 3. Jan.

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:

Linia 1. int imie znak równości scanner kropka nextInt otwórz nawias okrągły zamknij nawias okrągły średnik.
Dla zainteresowanych

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.

Ważne!

Kiedy tworzymy obiektu typu Scanner:

Linia 1. Scanner scan znak równości new Scanner otwórz nawias okrągły System kropka in zamknij nawias okrągły średnik.

Jednocześnie otwieramy strumień wejścia za pomocą System.in w argumencie.

Dlatego dobrym nawykiem jest używanie metody zamykającej strumień:

Linia 1. Scanner kropka close otwórz nawias okrągły zamknij nawias okrągły średnik.

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:

R1FUkj2mowqFT
Źródło: Contentplus.pl sp. z o.o., licencja: CC BY-SA 3.0.

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

Linia 1. scanner kropka useLocale otwórz nawias okrągły Locale kropka ENGLISH zamknij nawias okrągły średnik.

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;

Linia 1. import java kropka util kropka Locale średnik.
Ćwiczenie 1

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żytkowniczki

  • waga – liczba zmiennoprzecinkowa dodatnia; waga użytkowniczki w kg

  • wzrost – 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:

Linia 1. import java kropka util kropka Scanner średnik. Linia 2. import java kropka util kropka Locale średnik. Linia 4. public class CalcBMR otwórz nawias klamrowy. Linia 6. public static void main otwórz nawias okrągły String otwórz nawias kwadratowy zamknij nawias kwadratowy args zamknij nawias okrągły otwórz nawias klamrowy. Linia 7. Scanner scanner znak równości new Scanner otwórz nawias okrągły System kropka in zamknij nawias okrągły średnik. Linia 8. scanner kropka useLocale otwórz nawias okrągły Locale kropka getDefault otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły średnik. Linia 10. System kropka out kropka println otwórz nawias okrągły cudzysłów Jak masz na imie znak zapytania cudzysłów zamknij nawias okrągły średnik. Linia 11. String imie znak równości scanner kropka next otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 13. System kropka out kropka println otwórz nawias okrągły cudzysłów Witaj cudzysłów plus imie plus cudzysłów przecinek podaj swoja wage kropka cudzysłów zamknij nawias okrągły średnik. Linia 14. float waga znak równości scanner kropka nextFloat otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 16. System kropka out kropka println otwórz nawias okrągły cudzysłów Podaj swój wzrost w centymetrach kropka cudzysłów zamknij nawias okrągły średnik. Linia 17. float wzrost znak równości scanner kropka nextFloat otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 19. System kropka out kropka println otwórz nawias okrągły cudzysłów Podaj swój wiek kropka cudzysłów zamknij nawias okrągły średnik. Linia 20. int wiek znak równości scanner kropka nextInt otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 22. double bmr znak równości 655 plus otwórz nawias okrągły 9 kropka 6 asterysk waga zamknij nawias okrągły plus otwórz nawias okrągły 1 kropka 7 asterysk wzrost zamknij nawias okrągły minus otwórz nawias okrągły 4 kropka 7 asterysk wiek zamknij nawias okrągły średnik. Linia 24. System kropka out kropka println otwórz nawias okrągły cudzysłów Twoje podstawowe zapotrzebowanie kaloryczne wynosi dwukropek cudzysłów plus bmr plus cudzysłów kcal kropka cudzysłów zamknij nawias okrągły średnik. Linia 26. scanner kropka close otwórz nawias okrągły zamknij nawias okrągły średnik. Linia 27. zamknij nawias klamrowy. Linia 28. zamknij nawias klamrowy.

Przykładowa, interaktywna sesja z użytkowniczką może wyglądać następująco:

Linia 1. Jak masz na imie znak zapytania. Linia 2. Milena. Linia 3. Witaj Milena przecinek podaj swoja wage kropka. Linia 4. 65. Linia 5. Podaj swój wzrost w centymetrach kropka. Linia 6. 174. Linia 7. Podaj swój wiek kropka. Linia 8. 27. Linia 9. Twoje podstawowe zapotrzebowanie kaloryczne wynosi dwukropek 1447 kropka 8999999999999 kcal kropka.

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:

Linia 1. round otwórz nawias okrągły zamknij nawias okrągły średnik.

Wystarczy więc dopisać kilka znaków w ostatniej linijce kodu.

Linia 1. System kropka out kropka println otwórz nawias okrągły cudzysłów Twoje podstawowe zapotrzebowanie kaloryczne wynosi dwukropek cudzysłów plus Math kropka round otwórz nawias okrągły bmr zamknij nawias okrągły plus cudzysłów kcal kropka cudzysłów zamknij nawias okrągły średnik.

Po zmianach przykładowa, interaktywna sesja może wyglądać następująco:

Linia 1. Jak masz na imie znak zapytania. Linia 2. Milena. Linia 3. Witaj Milena przecinek podaj swoja wage kropka. Linia 4. 65. Linia 5. Podaj swój wzrost w centymetrach kropka. Linia 6. 174. Linia 7. Podaj swój wiek kropka. Linia 8. 27. Linia 9. Twoje podstawowe zapotrzebowanie kaloryczne wynosi dwukropek 1448 kcal kropka.

Słownik

IDE
IDE

(ang. Integrated Development Environment); zintegrowane środowisko programistyczne; najczęściej zawiera edytor kodu źródłowego oraz wbudowany kompilator lub interpreter

konstruktor
konstruktor

specjalna metoda klasy, której wywołanie nastąpi przy inicjalizacji obiektu danej klasy

SDK
SDK

(ang. Software Development Kit); zestaw narzędzi dla programistów niezbędny w tworzeniu aplikacji korzystających z funkcjonalności danej biblioteki

słowo kluczowe
słowo kluczowe

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