Stworzenie kalkulatora z użyciem instrukcji switch.

0

Witam,
mam za zadanie stworzyć prosty kalkulator z zastosowaniem instrukcji switch. Podczas testowania deklaracji liczb biorących udział w działaniu wszystko działało dobrze, jednak problem pojawił się przy wyborze typu działania (bez względu na wpisany w okno znak, pętla nie przestaje działać). Prawdopodobnie nie powinienem kończyć programu dopóki nie poradzę sobie z tym problemem, ale chciałem wrzucić tutaj jak według mnie powinna wyglądać całość (dodanie instrukcji switch i okna z wynikiem). Być może wyjdą jakieś dodatkowe błędy. Proszę o pomoc.

import java.util.Scanner;
import javax.swing.JOptionPane;

public class Kalkulator {
	
	public static void main(String[] args) {

		//deklaracja pierwszej liczby
		double pierwsza = 0;
		String n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
		if(n1 != null){
			Scanner scan = new Scanner(n1);
			pierwsza = scan.nextDouble();
		}
		
		//wybór działania
		char dzialanie = 'x';
		while(dzialanie != '+' || dzialanie != '-' || dzialanie != '*' || dzialanie != '/'){
			String znak = JOptionPane.showInputDialog("Wprowadź typ działania (+, -, *, /):");
			if(znak != null){
				Scanner scan = new Scanner(znak);
				dzialanie = scan.next().charAt(0);
			}
		}
		
		//deklaracja drugiej liczby
		double druga = 1;
		while(druga != 0){
			String n2 = JOptionPane.showInputDialog("Wprowadź drugą liczbę:");
			if(n2 != null){
				Scanner scan = new Scanner(n2);
				druga = scan.nextDouble();
			}
		}
		
		//obliczenia
		double wynik = 0;
		switch(dzialanie){
			case '+': wynik = pierwsza + druga; break;
			case '-': wynik = pierwsza + druga; break;
			case '*': wynik = pierwsza + druga; break;
			case '/': wynik = pierwsza + druga; break;
			default : System.out.println("błąd danych");
		}
		
		JOptionPane.showMessageDialog(null, "Wynik: " + wynik);
	}
}
0

Po co Ci kilka scannerów?

0

Szczerze mówiąc nie wiem jak można inaczej użyć scannera (dopiero zaczynam naukę javy), ale chyba się domyślam do czego dążysz. Czy chodzi o to, że trzeba go zainicjować tylko raz w pierwszym bloku (deklaracja pierwszej liczby) a później używać samych odwołań?

0

trzeba go zainicjować tylko raz w pierwszym bloku
Przed pierwszym blokiem.

a później używać samych odwołań?
Tak.

0

Po usunięciu tworzenia nowego scannera z bloków *wybór działania i *deklaracja drugiej liczby pojawia się komunikat: "scan cannot be resolved". Podejrzewam, że trzeba w jakiś sposób odwołać się do zmiennej znak i n2 w liniach poniżej usuniętych scannerów, jednak nie znam tej konstrukcji. Zawsze robiłem to jak w załączonym wyżej kodzie. Czy zredukowana liczba scannerów rozwiąże mój problem opisany w pierwszym poście?

0

Pokaż kod.

0

Zmiany zaznaczyłem komentarzem //usunięte

import java.util.Scanner;
import javax.swing.JOptionPane;

public class Kalkulator {
	
	public static void main(String[] args) {

		//deklaracja pierwszej liczby
		double pierwsza = 0;
		String n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
		if(n1 != null){
			Scanner scan = new Scanner(n1);
			pierwsza = scan.nextDouble();
		}
		
		//wybór działania
		char dzialanie = 'x';
		while(dzialanie != '+' || dzialanie != '-' || dzialanie != '*' || dzialanie != '/'){
			String znak = JOptionPane.showInputDialog("Wprowadź typ działania (+, -, *, /):");
			if(znak != null){
				//usunięte
				dzialanie = scan.next().charAt(0);
			}
		}
		
		//deklaracja drugiej liczby
		double druga = 1;
		while(druga != 0){
			String n2 = JOptionPane.showInputDialog("Wprowadź drugą liczbę:");
			if(n2 != null){
				//usunięte
				druga = scan.nextDouble();
			}
		}
		
		//obliczenia
		double wynik = 0;
		switch(dzialanie){
			case '+': wynik = pierwsza + druga; break;
			case '-': wynik = pierwsza + druga; break;
			case '*': wynik = pierwsza + druga; break;
			case '/': wynik = pierwsza + druga; break;
			default : System.out.println("błąd danych");
		}
		
		JOptionPane.showMessageDialog(null, "Wynik: " + wynik);
	}
}
0

@Patryk27 wprowadził Cię w błąd. Scanner trzeba utworzyć przed pierwszym blokiem.

import java.util.Scanner;
import javax.swing.JOptionPane;
 
public class Kalkulator {
 
    public static void main(String[] args) {
 
        Scanner scan = new Scanner(n1);
        //deklaracja pierwszej liczby
        double pierwsza = 0;
        String n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
        if(n1 != null){

A przy okazji, zapewne będziesz źle dzielił. Dzielenie liczb typu int w Javie jest całkowite: 12/5 = 2.

case '/': wynik = ((double)pierwsza) / druga; break;
0

Dzięki @bogdans, poprawiłem dzielenie. Co do samego scannera to przy przeniesieniu go nad pierwszy blok wyświetlił się komunikat, że "n1 cannot resolved to a variable". Więc zmodyfikowałem ten blok w taki sposób (mam nadzieję, że nie pomieszałem za bardzo):

		String n1;
		Scanner scan = new Scanner(n1);
		//deklaracja pierwszej liczby
		double pierwsza = 0;
		n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
		if(n1 != null){
			pierwsza = scan.nextDouble();
		}

Niestety nadal nie mam pomysłów jak zmienić drugi i trzeci blok w taki sposób aby korzystały z tego samego scannera co blok pierwszy. Chciałbym się również dowiedzieć, czy uporządkowanie kwestii skannera rozwiąże problem opisany w pierwszym poście.

0

Dopiero teraz przeczytałem Twój kod. Przemyśl warunki, poniższy warunek jest zawsze spełniony.

while(dzialanie != '+' || dzialanie != '-' || dzialanie != '*' || dzialanie != '/')

więc pojawia sie nieskończona pętla.
Warunek

while(druga != 0)

"wymusza" wpisanie zera. Na pewno o to Ci chodziło?

0

Poprawiłem oba warunki zmieniając wszędzie znak na ==. Niestety teraz mój "program" zgłasza błąd po wpisaniu pierwszej liczby (pierwszy blok): java.util.InputMismatchException, chodzi o linię nr 14 czyli: pierwsza = scan.nextDouble();
Jeśli chodzi o scanner to nic innego nie wymyślę. Zmieniłem nazwy drugiego i trzeciego scannera żeby ze sobą nie kolidowały.

1
package test;
import java.util.Scanner;
import javax.swing.JOptionPane;
 
public class Kalkulator {
 
    public static void main(String[] args) {
    	
    	String n1;
        
        //deklaracja pierwszej liczby
        double pierwsza = 0;
        n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
       
        
        while(n1 != null && n1.isEmpty() ){
        	 n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
        }
        
        //cancel clicked
        if(n1 == null){
        	System.exit(0);
         }
        
        
        //parse to double
        try{
        	pierwsza = Double.parseDouble(n1);
        }catch (Exception e){
        	System.out.println(e.getMessage());
        }
        
        
       //-------------------------------------------------------
      //wybór działania
        String znak = "";
         while(znak != null && znak.isEmpty()){
        	 znak = JOptionPane.showInputDialog("Wprowadź typ działania (+, -, *, /):");
        	
        	 if(znak != null)
        		 if(!znak.isEmpty())
        		if (znak.equals("+") || znak.equals("-") || znak.equals("/") || znak.equals("*") ){
              break;
            }else{
           	 znak = "";
            }
        	 
        	
      }
         
         //cancel clicked
         if(znak == null){
         	System.exit(0);
          }
         
         
         //------------------------------------------------
         
       //deklaracja drugiej liczby
         double druga = 0;
         String n2 ="";
        
         
         while(n2 != null && n2.isEmpty() ){
         	 n2 = JOptionPane.showInputDialog("Wprowadź drugą liczbę:");
         }
         
         //cancel clicked
         if(n2 == null){
         	System.exit(0);
          }
         
         
         //parse to double
         try{
         	druga = Double.parseDouble(n2);
         }catch (Exception e){
         	System.out.println(e.getMessage());
         }
     
       

         //obliczenia
         double wynik = 0;
         switch(znak){
             case "+": wynik = pierwsza + druga; break;
             case "-": wynik = pierwsza - druga; break;
             case "*": wynik = pierwsza * druga; break;
             case "/": wynik = pierwsza / druga; break;
             default : System.out.println("błąd danych");
         }
  
         JOptionPane.showMessageDialog(null, "Wynik: " + wynik);
         
         
         
         
         
         
    }
}

Scanner nie jest potrzebny poniewaz uzywasz InputDialog.

0

Dziękuję wszystkim za pomoc

0

@Biały Lew, Scanner nie jest niezbędny, ale kod bez Scannera działa inaczej.

//(a) bez Scannera
pierwsza = Double.parseDouble(n1);
//(b) ze Scannerem
pierwsza = new Scanner(n1).nextDouble();

Różnice są dwie:

  • kody oczekują innych separatorów dziesiętnych, kod (a) oczekuje kropki, kod (b) przecinka
  • kody inaczej reagują na niektóre nieprawidłowości, jeśli użytkownik wpisze 25 78, to kod (a) rzuci wyjątkiem, a kod (b) przypisze pierwsza = 25.
0

Postanowiłem, że jednak chcę użyć scannera zamiast metody parseDouble(). Zmieniłem swój pierwotny kod tak, aby użyć tylko jednego scannera we wszystkich trzech blokach choć nie jestem pewien czy dobrze. Sugerując się kodem, który przesłał @Biały Lew, zrezygnowałem z typu char na rzecz String w bloku "wybór działania". Oczywiście nadal są błędy, których nie potrafię poprawić. Po uruchomieniu programu i wpisaniu pierwszej liczby nadal pojawia się błąd "java.util.InputMismatchException", który wskazuje na linijkę pierwszego użycia scannera:

pierwsza = scan.nextDouble();

Aktualny kod programu:
import java.util.Scanner;
import javax.swing.JOptionPane;

public class Kalkulator {

public static void main(String[] args) {
	
	String n1 = "a";
	Scanner scan = new Scanner(n1);
	
	//deklaracja pierwszej liczby
	double pierwsza = 0;
	
	while(n1 != null && n1 =="a"){
		n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
			pierwsza = scan.nextDouble();
	}
	
	//wybór działania
	String dzialanie = "";
	while(dzialanie.equals("+") || dzialanie.equals("-") || dzialanie.equals("*") || dzialanie.equals("/") ){
		n1 = JOptionPane.showInputDialog("Wprowadź typ działania (+, -, *, /):");
		if(n1 != null){
			dzialanie = scan.next();
		}
	}
	
	//deklaracja drugiej liczby
	double druga = 0;
	while(n1 != null && druga == 0){
		n1 = JOptionPane.showInputDialog("Wprowadź drugą liczbę:");
			druga = scan.nextDouble();
	}
	
	//obliczenia
	double wynik = 0;
	switch(dzialanie){
		case "+": wynik = pierwsza + druga; 			break;
		case "-": wynik = pierwsza + druga; 			break;
		case "*": wynik = pierwsza + druga; 			break;
		case "/": wynik = ((double)pierwsza) + druga;	break;
		default : System.out.println("błąd danych");
	}
	
	JOptionPane.showMessageDialog(null, "Wynik: " + wynik);
}

}

1

Jak już pisałem, nie czytałem początkowo Twojego kodu tylko sugerowałem się postem @Patryk27'a. Tworzenie wielu Scannerów jest zbyteczne gdy skanujesz klawiaturę, ale jest konieczne gdy skanujesz String. Musisz poinformować Scanner jaki String ma skanować. Natomiast zbyteczne jest tworzenie wielu zmiennych typu Scanner. Dwa rozwiązania:

//krótsze, bez deklarowania zmiennych
import java.util.Scanner;
import javax.swing.JOptionPane;
 
public class Kalkulator {
 
    public static void main(String[] args) {
 
        //deklaracja pierwszej liczby
        double pierwsza = 0;
        String n1="";
 
        while(n1.isEmpty()){
            n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
                pierwsza = new Scanner(n1).nextDouble();
        }
         ...
//dłuższe
import java.util.Scanner;
import javax.swing.JOptionPane;
 
public class Kalkulator {
 
    public static void main(String[] args) {
 
        Scanner scan = null;
        String n1 = "";
 
        //deklaracja pierwszej liczby
        double pierwsza = 0;
 
        while(n1.isEmpty()){
            scan = new Scanner(n1); 
            n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
                pierwsza = scan.nextDouble();
        }
        ...

Ten warunek:

while(dzialanie.equals("+") || dzialanie.equals("-") || dzialanie.equals("*") || dzialanie.equals("/") )

jest zły. Zamień na

while(!dzialanie.equals("+") && !dzialanie.equals("-") && !dzialanie.equals("*") && !dzialanie.equals("/") )
//lub
while(!dzialanie.isEmpty() || !"+-*/".contains(dzialanie))

Popraw tez obliczanie wyniku,aktualnie zawsze dodajesz. :P

0

Zmieniłem bloki z deklaracjami pierwszej i drugiej liczby zgodnie z tym co napisałeś @bogdans, mam nadzieję że o to chodziło. Podobnie chciałem zrobić z blokiem środkowym jednak z jakiegoś powodu jest on pomijany przez program, który żąda tylko podania dwóch liczb następnie wyświetlając wynik domyślny (0). Poprawiłem też switche, umknęło mi to przy tworzeniu kiedy kopiowałem pierwszą linijkę:) aktualny kod środkowych bloków(reszta poza znakami w switchu bez zmian):

    	 //deklaracja pierwszej liczby
        double pierwsza = 0;
        String n1="";
 
        while(n1.isEmpty()){
            n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
                pierwsza = new Scanner(n1).nextDouble();
        }
 
        //wybór działania
        String znak = "";
        String dzialanie = "";
        
        while(!dzialanie.isEmpty() || !"+-*/".contains(dzialanie) ){
            znak = JOptionPane.showInputDialog("Wprowadź typ działania (+, -, *, /):");
            	dzialanie = new Scanner(znak).next();
        }
 
        //deklaracja drugiej liczby
        double druga = 0;
        String n2="";
 
        while(n2.isEmpty()){
            n2 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź drugą liczbę:");
                druga = new Scanner(n2).nextDouble();
        }
0

Sorry, wkradła się literówka

while(dzialanie.isEmpty() || !"+-*/".contains(dzialanie))
0

Poprawiłem i działa :) Pokusiłem się o modyfikację przy switchu, żeby nie dzielić przez 0. Próbowałem też zmienić kod żeby wyświetlał stosowny komunikat jeśli w blokach deklaracji liczb będzie wpisane coś innego niż liczba i stworzyłem coś takiego (dla chcących się pośmiać) :) :

                if ( !(pierwsza>=0 || pierwsza<=0) ){
                	JOptionPane.showMessageDialog(null, "Podana wartość nie jest liczbą");
                }

Pisząc ten program chciałem w praktyce przećwiczyć to co już wiem z teorii. Okazało się że potrzebna była do tego znacznie większa wiedza niż moja. Do tego popełniłem masę błędów używając tych elementów których byłem pewien, że znam w wystarczającym stopniu :) Jeszcze raz dziękuję za pomoc. Poniżej poprawiony, działający kod:

import java.util.Scanner;
import javax.swing.JOptionPane;
 
public class Kalkulator {
 
    public static void main(String[] args) {
 
    	 //deklaracja pierwszej liczby
        double pierwsza = 0;
        String n1="";
 
        while(n1.isEmpty()){
            n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n Wprowadź pierwszą liczbę:");
                pierwsza = new Scanner(n1).nextDouble();
        }
 
        //wybór działania
        String znak = "";
        String dzialanie = "";
        
        while(znak.isEmpty() || !"+-*/".contains(dzialanie) ){
            znak = JOptionPane.showInputDialog("Wprowadź typ działania (+, -, *, /):");
            	dzialanie = new Scanner(znak).next();
        }
 
        //deklaracja drugiej liczby
        double druga = 1;
        String n2="";
 
        while(n2.isEmpty() ){
            n2 = JOptionPane.showInputDialog("Wprowadź drugą liczbę:");
                druga = new Scanner(n2).nextDouble();
        }
        
        //obliczenia
        double wynik = 0;
        
        if(znak == "/" || druga == 0){
        	JOptionPane.showMessageDialog(null, "Nie dzielimy przez 0!");
        }else{
        	switch(dzialanie){
        	case "+": wynik = pierwsza + druga;             break;
        	case "-": wynik = pierwsza - druga;             break;
        	case "*": wynik = pierwsza * druga;             break;
        	case "/": wynik = ((double)pierwsza) / druga;   break;
        	default : System.out.println("błąd danych");
        	}
        	
        	JOptionPane.showMessageDialog(null, "Wynik: " + wynik);
        }
    }
}
0

Działa, ale nie bardzo. Ten warunek

if(znak == "/" || druga == 0)

jest błędny, z dwóch powodów:

  • powód ważniejszy, źle porównujesz Stringi, powinno być
znak.equals("/")

twój warunek nigdy nie jest spełniony,

  • powód mało ważny (w tym programie), błędnie porównujesz liczbę do zera, ze względu na przybliżoną reprezentacje liczb zmiennoprzecinkowych, należy porównywać tak
Math.abs(druga) < jakaś_mała_liczba

Wkleiłem ze schowka takie dziwo 0,00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001i przeczytałem komunikat Nie dzielimy przez 0!.

0

Zmieniłem linię instrukcji warunkowej w bloku "obliczenia" zauważyłem też, że zamiast && miałem || w warunku.
Niestety nie udało mi się poprawić dzielenia przez bardzo małą liczbę.
Wprowadziłem za to zmiany w bloku pierwszym i trzecim, dzięki którym przy wpisaniu czegoś innego niż liczba program się nie wysypie. Przy okazji otarłem się o temat wyjątków.
Zauważyłem też, że wpisując ułamek dziesiętny muszę użyć przecinka a kropka jest traktowana jako błąd, co ciekawe wynik wyświetlany jest z kropką. Aktualny kod:

import java.util.InputMismatchException;
import java.util.Scanner;
import javax.swing.JOptionPane;
 
public class Kalkulator {
 
    public static void main(String[] args) {
 
    	 //deklaracja pierwszej liczby (BLOK 1)
        Double pierwsza = null;
        String n1="";
        
        while(pierwsza == null){
        	try{
        		n1 = JOptionPane.showInputDialog("Witaj w kalkulatorze! \n  Wprowadź pierwszą liczbę:");
                pierwsza = new Scanner(n1).nextDouble();
        	}
        	catch(InputMismatchException exc){
        		JOptionPane.showMessageDialog(null, "Wpisz liczbę!");
        	}
        }
 
        //wybór działania (BLOK 2)
        String znak = "";
        String dzialanie = "";
        
        while(znak.isEmpty() || !"+-*/".contains(dzialanie) ){
            znak = JOptionPane.showInputDialog("Wprowadź typ działania (+, -, *, /):");
            	dzialanie = new Scanner(znak).next();
        }
 
        //deklaracja drugiej liczby (BLOK 3)
        Double druga = null;
        String n2="";
 
        while(druga == null){
        	try{
        		n2 = JOptionPane.showInputDialog("Wprowadź drugą liczbę:");
                druga = new Scanner(n2).nextDouble();
        	}
        	catch(InputMismatchException exc){
        		JOptionPane.showMessageDialog(null, "Wpisz liczbę!");
        	}
        }
        
        //obliczenia
        double wynik = 0;
        
        if(znak.equals("/") && Math.abs(druga) == Math.abs(0) ){
        	JOptionPane.showMessageDialog(null, "Nie dzielimy przez 0!");
        }else{
        	switch(dzialanie){
        	case "+": wynik = pierwsza + druga;             break;
        	case "-": wynik = pierwsza - druga;             break;
        	case "*": wynik = pierwsza * druga;             break;
        	case "/": wynik = ( (double)pierwsza) / druga;  break;
        	default : System.out.println("błąd danych");
        	}
        	
        	JOptionPane.showMessageDialog(null, "Wynik: " + wynik);
        }
    }
}
1

Sformatuj wyjście, to będzie przecinek

JOptionPane.showMessageDialog(null, "Wynik: " + String.format("%20.10f",wynik).trim();

Nie traktuj liczby w poniższym kodzie zbyt poważnie

if(znak.equals("/") && Math.abs(druga) < Math.abs(0.0000000000000000000000000000000001) )
0

Zmieniłem i działa, nie rozumiem tylko dlaczego poniższy warunek działa w ten sposób. Logika podpowiada, że jeśli zmienna "druga" jest mniejsza od podanej liczby a co za tym idzie może być ujemna to warunek powinien zostać spełniony, a jednak sprawdziłem i można dzielić przez liczby ujemne.

if(znak.equals("/") && Math.abs(druga) < Math.abs(0.0000000000000000000000000000000001) )

Jeśli chodzi o resztę to chyba można uznać, że program jest gotowy. Dzięki

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