Ĺadny brzuch
Plik JavTest2.java
import java.util.*; public class JavTest2 { public static void main(String[] args) { Scanner in = new Scanner(System.in); System.out.println("==========JavTest2============"); System.out.println("+++Osoba.java"); System.out.println(); Osoba[] ludzie = new Osoba[3]; //pobranie danych for(int i = 0; i < ludzie.length; i++) { System.out.print("Podaj imie:\t\t\t"); String im = in.nextLine(); System.out.print("Podaj nazwisko:\t\t\t"); String naz = in.nextLine(); System.out.print("Podaj zawod:\t\t\t"); String zaw = in.nextLine(); System.out.print("Podaj wiek:\t\t\t"); int wie = in.nextInt(); System.out.print("Podaj rok (data ur.):\t\t"); int ro = in.nextInt(); System.out.print("Podaj miesiąc (data ur.):\t"); int mies = in.nextInt(); System.out.print("Podaj dzień (data ur.):\t\t"); int dzie = in.nextInt(); ludzie[i] = new Osoba(im, naz, wie, zaw, ro, mies, dzie); System.out.println(); } System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++"); for(int i = 0; i < ludzie.length; i++) { System.out.println(ludzie[i]); } } }
Plik Osoba.java
/* * Klasa opisująca osobę */ import java.util.*; public class Osoba { public Osoba(String aimie, String anazwisko, int awiek, String azawod, int rok, int miesiac, int dzien) { this.imie = aimie; this.nazwisko = anazwisko; this.wiek = awiek; this.zawod = azawod; GregorianCalendar kalendarz = new GregorianCalendar(rok, miesiac - 1, dzien); this.urodzony = kalendarz.getTime(); } public String toString() { return getClass().getName() + "[nazwisko="+nazwisko+",imie="+imie+ ",wiek="+wiek+",urodzon(y/a)="+urodzony+",zawód="+zawod+"]" ; } public String getImie() { return imie; } public String getNazwisko() { return nazwisko; } public int getWiek() { return wiek; } public Date getUrodzon() { return urodzony; } public String getZawod() { return zawod; } private String imie; private String nazwisko; private int wiek; private Date urodzony; private String zawod; }
Problem polega na tym, że kiedy pętla robi drugi obieg nie można podać imienia!!!!
aprogle@aprogle-desktop:~/java$ java JavTest2 ==========JavTest2============ +++Osoba.java Podaj imie: qwe Podaj nazwisko: qwe Podaj zawod: qwe Podaj wiek: 23 Podaj rok (data ur.): 12 Podaj miesiąc (data ur.): 12 Podaj dzień (data ur.): 12 Podaj imie: Podaj nazwisko: ^Caprogle@aprogle-desktop:~/java$
Na czym polega błąd??
Jest to związane z pewną właściwością (błędem?) klasy Scanner (patrz też: http://coding.derkei...1/msg01478.html)
Rozwiązanie jest takie, aby na koniec pętli, po wypisaniu na konsolę linii przerwy, odczytać jeszcze raz z in:
... System.out.println(); in.nextLine(); }
Dzięki Rutterkin, program działa teraz prawidłowo :)
Na czym polega błąd??
Błąd polega na tym że w pliku JavTest2.java przy drugim wykonaniu pętli przed:
in.nextLine()
występuje:
in.nextInt()
Postaram się to jaśniej wytłumaczyć. Przeanalizujmy znaki, które wprowadziłeś z klawiatury podczas wykonania swojego programu i przeanalizujmy położenie wskaźnika Scanner.
Oto dane, które wprowadziłeś:
qwe\r\n
qwe\r\n
qwe\r\n
23\r\n
12\r\n
12\r\n
12\r\n
Teraz przeanalizujmy jakie dane pobiera Scanner.
Oto te dane:
qwe\r\n
qwe\r\n
qwe\r\n
23
12
12
12
drugie wykonanie pętli:
\r\n
Pytanie brzmi: Czym to jest spowodowane?
Metoda nextLine() skanuje dane aż nastąpi kod "\r\n" i to co się znajduje od początku do końca sekwencji "\r\n" jest pobierane przez skaner. Oczywiście kod "\n\r" również jest pobierany przez tę metodę.
Metoda nextInt() pobiera następny token i pobrane dane zamienia na int. Jeśli wśród pobranych danych znajdą się specjalne znaki jak "\r\n", to nie są one brane pod uwagę przy zamianie na int. Jeśli nie da się pobranych danych zamienić na int, to wyrzucany jest wyjątek.
Skoro już tyle wiemy, to teraz zastanówmy się jak to się dzieje, że program zachowuje się w ten sposób?
Spójrz do góry na dane pobierane przez skaner.
Przeanalizujmy teraz wykonanie programu (to co Ty podałeś, to co Skaner pobrał):
Podaj imie: qwe\r\n qwe\r\n
Podaj nazwisko: qwe\r\n qwe\r\n
Podaj zawod: qwe\r\n qwe\r\n
Podaj wiek: 23\r\n 23
Podałeś: 23\r\n, natomiast skaner pobrał: 23, wartość: \r\n nie znika, kursor skanera znajduje się przed tą wartością
Podaj rok (data ur.): 12\r\n 12
Skaner odczytał: \r\n12, wartość \r\n pominął i wartość 12 zamienił na int, skaner znajduje się przed kolejnym \r\n
Podaj miesiąc (data ur.): 12\r\n 12
To samo co wyżej
Podaj dzień (data ur.): 12\r\n 12
Jeszcze raz powtórzę:
Skaner odczytał: \r\n12, wartość \r\n pominął i wartość 12 zamienił na int, skaner znajduje się przed kolejnym \r\n
Teraz mamy kolejne wykonanie pętli:
Podaj imie: \r\n
Skaner znajdował się przed \r\n, a więc stwierdził, że dotarł do końca linii, odczytał tę wartość i umieścił w zmiennej
Podaj nazwisko: ....
W efekcie mamy coś takiego:
Podaj imie: Podaj nazwisko:
Kolejne pytanie brzmi: Jakie jest rozwiązanie tego problemu?
Rozwiązaniem tego problemu może być zaprzestanie pobierania znaków "\r\n\". Jak to zrobić? Rozwiązanie jest proste - zamiast metody nextLine() używaj metody next(). Metoda nextLine() pobiera całą wartość wraz ze znakami "\r\n", a metoda next() ignoruje te znaki, tak samo jak metoda nextInt(). Inaczej mówiąc, używając metody nextLine() pobierasz "qwe\r\n", a używając metody next() pobierasz tylko "qwe".
Problem będzie jeśli będziesz chciał pobierać dane typu string oddzielone na przykład spacjami. Wtedy rozwiązaniem może być użycie nextLine() i dodanie dodatkowego in.nextLine() po next() lub nextInt() i przed tym właściwym nextLine() pobierającym dane oddzielone spacją.
zanotowane.pl doc.pisz.pl pdf.pisz.pl zsf.htw.pl
import java.util.*; public class JavTest2 { public static void main(String[] args) { Scanner in = new Scanner(System.in); System.out.println("==========JavTest2============"); System.out.println("+++Osoba.java"); System.out.println(); Osoba[] ludzie = new Osoba[3]; //pobranie danych for(int i = 0; i < ludzie.length; i++) { System.out.print("Podaj imie:\t\t\t"); String im = in.nextLine(); System.out.print("Podaj nazwisko:\t\t\t"); String naz = in.nextLine(); System.out.print("Podaj zawod:\t\t\t"); String zaw = in.nextLine(); System.out.print("Podaj wiek:\t\t\t"); int wie = in.nextInt(); System.out.print("Podaj rok (data ur.):\t\t"); int ro = in.nextInt(); System.out.print("Podaj miesiąc (data ur.):\t"); int mies = in.nextInt(); System.out.print("Podaj dzień (data ur.):\t\t"); int dzie = in.nextInt(); ludzie[i] = new Osoba(im, naz, wie, zaw, ro, mies, dzie); System.out.println(); } System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++"); for(int i = 0; i < ludzie.length; i++) { System.out.println(ludzie[i]); } } }
Plik Osoba.java
/* * Klasa opisująca osobę */ import java.util.*; public class Osoba { public Osoba(String aimie, String anazwisko, int awiek, String azawod, int rok, int miesiac, int dzien) { this.imie = aimie; this.nazwisko = anazwisko; this.wiek = awiek; this.zawod = azawod; GregorianCalendar kalendarz = new GregorianCalendar(rok, miesiac - 1, dzien); this.urodzony = kalendarz.getTime(); } public String toString() { return getClass().getName() + "[nazwisko="+nazwisko+",imie="+imie+ ",wiek="+wiek+",urodzon(y/a)="+urodzony+",zawód="+zawod+"]" ; } public String getImie() { return imie; } public String getNazwisko() { return nazwisko; } public int getWiek() { return wiek; } public Date getUrodzon() { return urodzony; } public String getZawod() { return zawod; } private String imie; private String nazwisko; private int wiek; private Date urodzony; private String zawod; }
Problem polega na tym, że kiedy pętla robi drugi obieg nie można podać imienia!!!!
aprogle@aprogle-desktop:~/java$ java JavTest2 ==========JavTest2============ +++Osoba.java Podaj imie: qwe Podaj nazwisko: qwe Podaj zawod: qwe Podaj wiek: 23 Podaj rok (data ur.): 12 Podaj miesiąc (data ur.): 12 Podaj dzień (data ur.): 12 Podaj imie: Podaj nazwisko: ^Caprogle@aprogle-desktop:~/java$
Na czym polega błąd??
Jest to związane z pewną właściwością (błędem?) klasy Scanner (patrz też: http://coding.derkei...1/msg01478.html)
Rozwiązanie jest takie, aby na koniec pętli, po wypisaniu na konsolę linii przerwy, odczytać jeszcze raz z in:
... System.out.println(); in.nextLine(); }
Dzięki Rutterkin, program działa teraz prawidłowo :)
Na czym polega błąd??
Błąd polega na tym że w pliku JavTest2.java przy drugim wykonaniu pętli przed:
in.nextLine()
występuje:
in.nextInt()
Postaram się to jaśniej wytłumaczyć. Przeanalizujmy znaki, które wprowadziłeś z klawiatury podczas wykonania swojego programu i przeanalizujmy położenie wskaźnika Scanner.
Oto dane, które wprowadziłeś:
qwe\r\n
qwe\r\n
qwe\r\n
23\r\n
12\r\n
12\r\n
12\r\n
Teraz przeanalizujmy jakie dane pobiera Scanner.
Oto te dane:
qwe\r\n
qwe\r\n
qwe\r\n
23
12
12
12
drugie wykonanie pętli:
\r\n
Pytanie brzmi: Czym to jest spowodowane?
Metoda nextLine() skanuje dane aż nastąpi kod "\r\n" i to co się znajduje od początku do końca sekwencji "\r\n" jest pobierane przez skaner. Oczywiście kod "\n\r" również jest pobierany przez tę metodę.
Metoda nextInt() pobiera następny token i pobrane dane zamienia na int. Jeśli wśród pobranych danych znajdą się specjalne znaki jak "\r\n", to nie są one brane pod uwagę przy zamianie na int. Jeśli nie da się pobranych danych zamienić na int, to wyrzucany jest wyjątek.
Skoro już tyle wiemy, to teraz zastanówmy się jak to się dzieje, że program zachowuje się w ten sposób?
Spójrz do góry na dane pobierane przez skaner.
Przeanalizujmy teraz wykonanie programu (to co Ty podałeś, to co Skaner pobrał):
Podaj imie: qwe\r\n qwe\r\n
Podaj nazwisko: qwe\r\n qwe\r\n
Podaj zawod: qwe\r\n qwe\r\n
Podaj wiek: 23\r\n 23
Podałeś: 23\r\n, natomiast skaner pobrał: 23, wartość: \r\n nie znika, kursor skanera znajduje się przed tą wartością
Podaj rok (data ur.): 12\r\n 12
Skaner odczytał: \r\n12, wartość \r\n pominął i wartość 12 zamienił na int, skaner znajduje się przed kolejnym \r\n
Podaj miesiąc (data ur.): 12\r\n 12
To samo co wyżej
Podaj dzień (data ur.): 12\r\n 12
Jeszcze raz powtórzę:
Skaner odczytał: \r\n12, wartość \r\n pominął i wartość 12 zamienił na int, skaner znajduje się przed kolejnym \r\n
Teraz mamy kolejne wykonanie pętli:
Podaj imie: \r\n
Skaner znajdował się przed \r\n, a więc stwierdził, że dotarł do końca linii, odczytał tę wartość i umieścił w zmiennej
Podaj nazwisko: ....
W efekcie mamy coś takiego:
Podaj imie: Podaj nazwisko:
Kolejne pytanie brzmi: Jakie jest rozwiązanie tego problemu?
Rozwiązaniem tego problemu może być zaprzestanie pobierania znaków "\r\n\". Jak to zrobić? Rozwiązanie jest proste - zamiast metody nextLine() używaj metody next(). Metoda nextLine() pobiera całą wartość wraz ze znakami "\r\n", a metoda next() ignoruje te znaki, tak samo jak metoda nextInt(). Inaczej mówiąc, używając metody nextLine() pobierasz "qwe\r\n", a używając metody next() pobierasz tylko "qwe".
Problem będzie jeśli będziesz chciał pobierać dane typu string oddzielone na przykład spacjami. Wtedy rozwiązaniem może być użycie nextLine() i dodanie dodatkowego in.nextLine() po next() lub nextInt() i przed tym właściwym nextLine() pobierającym dane oddzielone spacją.