Problem z wejściem typu "String"

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

 String jednostkaPromienia = in.nextLine();

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

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());
	}
}
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ć.

    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.

 System.out.println("Podaj jednostkę długości promienia koła (cm, mm, km)");
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 ?

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.

 ...

String data = in.nextLine();

int a = Integer.parseInt(data);
1

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

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();

0

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

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

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

Scanner in = new Scanner(new CloseShieldInputStream(System.in));
//operacje 
in.close();
//System.in nadal dostępny
0

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

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

 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.

1 użytkowników online, w tym zalogowanych: 0, gości: 1