Problem z wejściem typu "String"

Problem z wejściem typu "String"
Puszka
  • Rejestracja:ponad 8 lat
  • Ostatnio:ponad 6 lat
  • Postów:15
0

Poniżej podałem kod programu mającego za zadanie obliczyć pole i obwód koła używając parametrów (długości i jednostki) wprowadzanych z klawiatury. Problem pojawił się w momencie gdy chcę aby użytkownik wprowadził jednostkę długości promienia. Program działa tak jakby ignorował linijkę:

Kopiuj
 String jednostkaPromienia = in.nextLine();

Proszę o ewentualne podpowiedzi dotyczące zmiany kodu źródłowego, poprawek czy udogodnień.

Kopiuj
import java.util.Scanner;

class koło
{
	private double promień;
	
	public koło(double r,String j)
	{
		promień=r;
		if(j.equals("km"))
		{
			promień=promień*1000;
		}
		else if(j.equals("cm"))
		{
			promień=promień/100;
		}
		else if(j.equals("mm"))
		{
			promień=promień/1000;
		}
	}
	public double obliczObwódKoła()
	{
		return 2*Math.PI*promień;
	}
	public double obliczPoleKoła()
	{
		return Math.PI*promień*promień;
	}
	public double getPromień()
	{
		return promień;
	}
}

public class KlasaKoło
{
	public static void main(String[] args)
	{
	Scanner in = new Scanner(System.in);
	System.out.println("Podaj długość promienia koła");
	double promieńKoła= in.nextDouble();
	System.out.println("Podaj jednoskę długości promienia koła");
	String jednostkaPromienia = in.nextLine();
	
	koło koło = new koło(promieńKoła, jednostkaPromienia);
	System.out.println("Długość promienia to "+koło.getPromień()+" m");
	System.out.println("Pole wyosi "+koło.obliczPoleKoła());
	System.out.println("Obwód wyosi "+koło.obliczObwódKoła());
	}
}
edytowany 3x, ostatnio: Puszka
Puszka
Rzeczywiście, powinienem zrobić to przed postowaniem czegokolwiek. Dzięki za przestrogę.
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
1

Metoda nextDouble czyta tylko liczbę, pozostawia w buforze klawiatury całą resztę wpisaną przez użytkownika. Ta reszta nigdy nie jest pusta - zawiera co najmniej ENTER. Kolejne wywołanie nextLine nie czeka na nowe dane, czyta to co jest w buforze. Musisz ten bufor wyczyścić.

Kopiuj
    double promieńKoła= in.nextDouble();
    in.nextLine();
    System.out.println("Podaj jednoskę długości promienia koła");
    String jednostkaPromienia = in.nextLine(); 

Ja bym podpowiedział użytkownikowi jakie jednostki obsługuje program.

Kopiuj
 System.out.println("Podaj jednostkę długości promienia koła (cm, mm, km)");

To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
edytowany 1x, ostatnio: bogdans
Puszka
Dziękuje i życzę udanego sylwestra!
Puszka
  • Rejestracja:ponad 8 lat
  • Ostatnio:ponad 6 lat
  • Postów:15
0

I jeszcze jedno pytanie
Dzieje się tak tylko przy wykorzystaniu metody nextDouble. Czy w przypadku innych np : nextInt czy nextFloat też trzeba wyczyścić bufor ?

edytowany 3x, ostatnio: Puszka
R1
  • Rejestracja:około 10 lat
  • Ostatnio:około 5 lat
  • Postów:208
1

z innymi metodami typu nextInt itp dzieje się tak samo.

ja osobiście wole wczytywać wszystko do String a następnie to konwertować np.

Kopiuj
 ...

String data = in.nextLine();

int a = Integer.parseInt(data);
edytowany 1x, ostatnio: rafal20-1988
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
1

Przy każdej różnej od nextLine. Każda z nich czyta tyle ile potrzebuje, resztę (a w niej ENTER) zostawia w buforze.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
P7
  • Rejestracja:ponad 9 lat
  • Ostatnio:dzień
  • Lokalizacja:Warszawa
  • Postów:89
0

można też wczytać drugą zmienną metodą next() zamiast nextLine() i po kłopocie :) - nie potrzebna Ci cała linia tylko ta jedna wartość, dobrym nawykiem jest też zamykanie zasobów: in.close();

edytowany 3x, ostatnio: flowCRANE
bogdans
Ty tak poważnie proponujesz zamykanie Scannera czytającego z klawiatury? Wiesz, że wtedy zamykasz klawiaturę.
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

Nie ucz złych nawyków. Scannera czytającego z klawiatury nie potrzeba zamykać, co więcej jego zamykanie jest potencjalnie niebezpieczne.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
P7
  • Rejestracja:ponad 9 lat
  • Ostatnio:dzień
  • Lokalizacja:Warszawa
  • Postów:89
0

no ok, tylko nie bardzo wiem po co mi ten skaner jeszcze w tym wypadku - przecież kończymy program, pobraliśmy dane, wypisaliśmy wynik , finito.

  • nawet IDE będzie krzyczeć "resource leak" , jak go nie zamkniesz
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

IDE krzyczy bo jest głupie i nie rozróżnia co jest "skanowane". Skoro pobrałeś dane i kończysz program, to nie ma znaczenia czy zamkniesz skaner. A jeśli nie kończysz, to możesz próbować odczytać nowe dane i lepiej żeby skaner nie został zamknięty.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
P7
  • Rejestracja:ponad 9 lat
  • Ostatnio:dzień
  • Lokalizacja:Warszawa
  • Postów:89
0

Myślę, że wszystko sprowadza się do odpowiedzi na pytanie czy dany zasób będzie jeszcze potrzebny czy nie, jeśli nie imo można i należy zamykać, w naszym przypadku faktycznie nie trzeba jawnie - zrobi to VM.
Masz rację , że zamykając scanner zamykasz też stream z którego ten scanner czyta - czasami będzie to ok, czasem nie , wszystko zależy od powyższego.

Jest możliwy sposób obejścia tego problemu dzięki klasie CloseShieldInputStream , która zabezpiecza przed zamknięciem streama, przy np. przypadkowym zamknięciu scannera

https://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/input/CloseShieldInputStream.html

Kopiuj
Scanner in = new Scanner(new CloseShieldInputStream(System.in));
//operacje 
in.close();
//System.in nadal dostępny
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

Dyskusja toczy się w dziale * Newbie.* Jesteś pewien, że początkujący powinni zaczynać od ściągania zewnętrznych bibliotek i wpisywania tajemniczego

Kopiuj
Scanner in = new Scanner(new CloseShieldInputStream(System.in)); 

Moim zdaniem, dużo lepiej jest, by początkujący programista, który nie wie, że zamknięcie scannera zamyka strumień nie zamykał scannera. Rozsądne zamykanie (i otwieranie) scannera wymaga pewnego doświadczenia. Na forum pojawiały się już kody typu

Kopiuj
 while(condition){
     readSomething();
     ...
}
...
readSomething(){
    Scanner scanner = new Scanner(System.in);
    ...
    scanner.close(); //bo IDE tak podpowiedziało
}

połączone z pytaniem czemu nie działa.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
edytowany 1x, ostatnio: bogdans
Burdzi0
@bogdans: Niebezpieczeństwo zamykania streamu z System.in dotyczy tylko Scannera? Jeśli tak to z czego wynika dana specyfika tego streamu? Mógłbyś podrzucić jakieś dane, jak do tej pory znalazłem tylko ten link

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.