Gyakorlati alapok II.
A 4 alapművelet
Az egyik előző, a Számkétszerezés című fejezet már bevezette azt az implementációs megoldást, amellyel közelíthetünk egy közepes bonyolultságú, konzolos "számolgatógép" elkészítéséhez. Ebben a fejezetben nézzük meg a 4 alapművelet egyre bonyolultabb implementációját, természetesen már külön függvényekben.
Az 1. körös megoldásban a 4 alapművelet kapcsolgatását nem Smith, hanem Switch bácsi, a többszörös elágazások szakértője végzi el nekünk. Sőt, rossz bemeneti műveleti jel esetén (char muveletiJel) még hibaüzenetet is biztosít:
default: System.out.prdoubleln("Rossz műveleti jel!"); break;
A külső alapmuveletek függvény egyetlen kimeneti értéke természetesen double típusú eredmeny lesz, de ne felejtsük el, hogy ezt nemcsak átadnunk, hanem át is kell vennünk. E célból egy ugyanilyen funkciójú és lehetőleg típusú változót kell deklarálnunk a main()-ben, illetve ajánlott, hogy vele a függvény bemeneti értékei is azonos típusúak legyenek (double elsoSzam, double masodikSzam). Ezután már képesek vagyunk átvenni a függvény kimeneti értékét:
double eredmeny = alapmuveletek(2, 10, '-');
public class
Main {
static double alapmuveletek(double elsoSzam, double masodikSzam, char muveletiJel){
double eredmeny = 0;
switch(muveletiJel){
case('+'): eredmeny = elsoSzam + masodikSzam; break;
case('-'): eredmeny = elsoSzam - masodikSzam; break;
case('*'): eredmeny = elsoSzam * masodikSzam; break;
case('/'): eredmeny = elsoSzam / masodikSzam; break;
default: System.out.println("Rossz műveleti jel!"); break;
}
return eredmeny;
}
public static void main(String[] args) {
double eredmeny = alapmuveletek(2, 10, '-');
System.out.println(eredmeny);
}
}
Végeredmény:
-8.0
Természetesen a Javán belül jócskán vannak olyan függvények, amelyek automatikusan képesek átvenni más függvények kimeneti értékeit (ezt nevezzük függvény-túlterhelésnek - method overloading, overloaded methods); talán a legtipikusabb ilyen függvény a System.out.println(), amelynek bemeneti paramétermezőjébe pakolva függvényünket meg tudja jeleníteni annak kimeneti értékét:
System.out.println(alapmuveletek(2, 10, '-'));
public class
Main {
static double alapmuveletek(double elsoSzam, double masodikSzam, char muveletiJel){
double eredmeny = 0;
switch(muveletiJel){
case('+'): eredmeny = elsoSzam + masodikSzam; break;
case('-'): eredmeny = elsoSzam - masodikSzam; break;
case('*'): eredmeny = elsoSzam * masodikSzam; break;
case('/'): eredmeny = elsoSzam / masodikSzam; break;
default: System.out.println("Rossz műveleti jel!"); break;
}
return eredmeny;
}
public static void main(String[] args) {
System.out.println(alapmuveletek(2,
10, '-'));
}
}
Végeredmény:
-8.0
Az objektumorientált szemlélet következő lépéseként tovább bonthatjuk szét a funkcionalitást. Ekkor (majdnem) minden művelet külön metódust kap:
public class
Main {
static double osszeadas(double elsoSzam, double masodikSzam){
return elsoSzam + masodikSzam;
}
static double kivonas(double elsoSzam, double masodikSzam){
return elsoSzam - masodikSzam;
}
static double szorzas(double elsoSzam, double masodikSzam){
return elsoSzam * masodikSzam;
}
static double osztas(double elsoSzam, double masodikSzam){
return elsoSzam / masodikSzam;
}
public static void main(String[] args) {
double elsoSzam = 2;
double masodikSzam = 10;
double eredmeny = 0;
char muveletiJel = '+';
switch(muveletiJel){
case('+'):
eredmeny = osszeadas(elsoSzam, masodikSzam); break;
case('-'):
eredmeny = kivonas(elsoSzam, masodikSzam); break;
case('*'):
eredmeny = szorzas(elsoSzam, masodikSzam); break;
case('/'):
eredmeny = osztas(elsoSzam, masodikSzam); break;
default:
System.out.println("Rossz műveleti jel!"); break;
}
System.out.println(eredmeny);
}
}
Végeredmény:
12.0
Még mindig nagyon fapados a kódunk, de alapszemléletét tekintve már egészen objektumorientált-közeli (aminek persze vannak további, itt még nem alkalmazott kritériumai is). Az elvet továbbpörgetve a switch részt is bele tudjuk illeszteni egy külön metódusba, mondjuk kiertekeles néven:
public
class Main {
static double osszeadas(double elsoSzam, double masodikSzam){
return elsoSzam + masodikSzam;
}
static double kivonas(double elsoSzam, double masodikSzam){
return elsoSzam - masodikSzam;
}
static double szorzas(double elsoSzam, double masodikSzam){
return elsoSzam * masodikSzam;
}
static double osztas(double elsoSzam, double masodikSzam){
return elsoSzam / masodikSzam;
}
static double kiertekeles(double elsoSzam, double masodikSzam, char muveletiJel){
double eredmeny = 0;
switch(muveletiJel){
case('+'): eredmeny = osszeadas(elsoSzam, masodikSzam); break;
case('-'): eredmeny = kivonas(elsoSzam, masodikSzam); break;
case('*'): eredmeny = szorzas(elsoSzam, masodikSzam); break;
case('/'): eredmeny = osztas(elsoSzam, masodikSzam); break;
default: System.out.println("Rossz műveleti jel!"); break;
}
return eredmeny;
}
public static void main(String[] args) {
double elsoSzam = 2;
double masodikSzam = 10;
char muveletiJel = '-';
System.out.println(kiertekeles(elsoSzam, masodikSzam, muveletiJel));
}
}
Végeredmény:
-8.0
A program eddigi leggyengébb pontja az adatbevitel. Adatbekéréssel már több helyen foglalkoztunk: már csak olyan függvényeket kell implementálnunk, amelyek a bemeneti adatok bevitelét könnyítik meg, esetleg automatizálják, természetesen külön metódusként:
import java.util.Scanner;
public class Main {
static double osszeadas(double elsoSzam, double masodikSzam){
return elsoSzam + masodikSzam;
}
static double kivonas(double elsoSzam, double masodikSzam){
return elsoSzam - masodikSzam;
}
static double szorzas(double elsoSzam, double masodikSzam){
return elsoSzam * masodikSzam;
}
static double osztas(double elsoSzam, double masodikSzam){
return elsoSzam / masodikSzam;
}
static String[] adatBekeres(){
Scanner in = new Scanner (System.in);
String[] bemenetiAdatTomb = new String[3];
System.out.println ("Kérem adja meg az 1. számot!");
bemenetiAdatTomb[0] = in.nextLine();
double szam = Double.parseDouble(bemenetiAdatTomb[0]);
while (szam <= 0){
System.out.println("Kérem, hogy csak
pozitív egész számot adjon meg!");
bemenetiAdatTomb[0] = in.nextLine();
szam =
Double.parseDouble(bemenetiAdatTomb[0]);
}
System.out.println ("Kérem adja meg a műveleti jelet!");
bemenetiAdatTomb[1] = in.nextLine();
while (!bemenetiAdatTomb[1].equals("+") &&
!bemenetiAdatTomb[1].equals("-")
&& !bemenetiAdatTomb[1].equals("*") && !bemenetiAdatTomb[1].equals("/")){
System.out.println("Kérem, hogy csak + - * / jeleket adjon
meg!");
bemenetiAdatTomb[1] = in.nextLine();
}
System.out.println ("Kérem adja meg a 2. számot!");
bemenetiAdatTomb[2] = in.nextLine();
szam = Double.parseDouble(bemenetiAdatTomb[2]);
while (szam <= 0){
System.out.println("Kérem, hogy csak
pozitív egész számot adjon meg!");
bemenetiAdatTomb[2] = in.nextLine();
szam =
Double.parseDouble(bemenetiAdatTomb[2]);
}
return bemenetiAdatTomb;
}
static double kiertekeles(double elsoSzam, double masodikSzam, String
muveletiJel){
double eredmeny = 0;
switch(muveletiJel){
case("+"): eredmeny =
osszeadas(elsoSzam, masodikSzam); break;
case("-"): eredmeny =
kivonas(elsoSzam, masodikSzam); break;
case("*"): eredmeny =
szorzas(elsoSzam, masodikSzam); break;
case("/"): eredmeny = osztas(elsoSzam,
masodikSzam); break;
}
return eredmeny;
}
public static void main(String[] args) {
String[] bemenetiAdatTomb = new String[3];
bemenetiAdatTomb = adatBekeres();
double elsoSzam = Double.parseDouble(bemenetiAdatTomb[0]);
double masodikSzam = Double.parseDouble(bemenetiAdatTomb[2]);
String muveletiJel = bemenetiAdatTomb[1];
System.out.println(kiertekeles(elsoSzam, masodikSzam,
muveletiJel));
}
}
Végeredmény:
Kérem adja
meg az 1. számot!
0
Kérem, hogy csak pozitív egész számot adjon meg!
120
Kérem adja meg a műveleti jelet!
g
Kérem, hogy csak + - * / jeleket adjon meg!
/
Kérem adja meg a 2. számot!
45
2.6666666666666665
Az adatbekérés ugyan első körben meg lett oldva...
static String[] adatBekeres(){
Scanner in = new Scanner (System.in);
String[] bemenetiAdatTomb = new String[3];
System.out.println ("Kérem adja meg az 1. számot!");
bemenetiAdatTomb[0] = in.nextLine();
double szam = Double.parseDouble(bemenetiAdatTomb[0]);
while (szam <= 0){
System.out.println("Kérem, hogy csak
pozitív egész számot adjon meg!");
bemenetiAdatTomb[0] = in.nextLine();
szam =
Double.parseDouble(bemenetiAdatTomb[0]);
}
System.out.println ("Kérem adja meg a műveleti jelet!");
bemenetiAdatTomb[1] = in.nextLine();
while (!bemenetiAdatTomb[1].equals("+") &&
!bemenetiAdatTomb[1].equals("-")
&& !bemenetiAdatTomb[1].equals("*") && !bemenetiAdatTomb[1].equals("/")){
System.out.println("Kérem, hogy csak + - * / jeleket adjon
meg!");
bemenetiAdatTomb[1] = in.nextLine();
}
System.out.println ("Kérem adja meg a 2. számot!");
bemenetiAdatTomb[2] = in.nextLine();
szam = Double.parseDouble(bemenetiAdatTomb[2]);
while (szam <= 0){
System.out.println("Kérem, hogy csak
pozitív egész számot adjon meg!");
bemenetiAdatTomb[2] = in.nextLine();
szam =
Double.parseDouble(bemenetiAdatTomb[2]);
}
return bemenetiAdatTomb;
}
...sőt működőképes, de több probléma is van vele:
-
bár a műveleti jel ellenőrzése korrekt, de a számoké nem. A számellenőrzés alapszintű, így csak azt ellenőrzi, hogy 0-nál kisebb szám ne kerüljön be, így rossz karakter begépelésekor (például 23 helyett s) rendszerszintű hibaüzenetet kapunk, úgynevezett kivétel /exception/ keletkezik:
Exception in thread "main" java.lang.NumberFormatException: For input string: "w"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:492)
at java.lang.Integer.parseInt(Integer.java:527)
at Main.main(Main.java:8) -
2 db számot ellenőrzünk, de azonos kóddal, ez viszont "sérti" az objektumorientált szemléletet, mert kódduplázódásunk van.
A megoldás: mindent külön metódusba kell tennünk és tovább kell fejlesztünk a számellenőrzést.
import java.util.Scanner;
public class Main {
static double osszeadas(double elsoSzam, double masodikSzam){
return elsoSzam + masodikSzam;
}
static double kivonas(double elsoSzam, double masodikSzam){
return elsoSzam - masodikSzam;
}
static double szorzas(double elsoSzam, double masodikSzam){
return elsoSzam * masodikSzam;
}
static double osztas(double elsoSzam, double masodikSzam){
return elsoSzam / masodikSzam;
}
static String[] adatBekeres(){
Scanner in = new Scanner (System.in);
String[] bemenetiAdatTomb = new String[3];
boolean rosszAdat = false;
System.out.println ("Kérem adja meg az 1. számot!");
do{
bemenetiAdatTomb[0] = in.nextLine();
rosszAdat =
ellenorzesSzam(bemenetiAdatTomb[0]);
}while (rosszAdat == true);
rosszAdat = false;
System.out.println ("Kérem adja meg a műveleti jelet!");
bemenetiAdatTomb[1] = in.nextLine();
while (!bemenetiAdatTomb[1].equals("+") &&
!bemenetiAdatTomb[1].equals("-")
&& !bemenetiAdatTomb[1].equals("*") && !bemenetiAdatTomb[1].equals("/")){
System.out.println("Kérem, hogy csak + - * / jeleket adjon meg!");
bemenetiAdatTomb[1] = in.nextLine();
}
System.out.println ("Kérem adja meg a 2. számot!");
do{
bemenetiAdatTomb[2] = in.nextLine();
rosszAdat =
ellenorzesSzam(bemenetiAdatTomb[2]);
}while (rosszAdat == true);
return bemenetiAdatTomb;
}
static boolean ellenorzesSzam(String bemenetiAdat){
boolean rosszAdat = false;
char karakter = bemenetiAdat.charAt(0);
if(karakter == '0'){
rosszAdat = true;
}
for(int i = 0; i < bemenetiAdat.length(); i++){
karakter = bemenetiAdat.charAt(i);
if(karakter
!= '0'
&& karakter != '1'
&& karakter != '2'
&& karakter != '3'
&& karakter != '4'
&& karakter != '5'
&& karakter != '6'
&& karakter != '7'
&& karakter != '8'
&& karakter != '9'){
rosszAdat = true;
break;
}
}
if(rosszAdat == true){
System.out.println("Kérem, hogy csak pozitív egész számot adjon meg!");
}
return rosszAdat;
}
static double kiertekeles(double elsoSzam, double masodikSzam, String
muveletiJel){
double eredmeny = 0;
switch(muveletiJel){
case("+"): eredmeny =
osszeadas(elsoSzam, masodikSzam); break;
case("-"): eredmeny =
kivonas(elsoSzam, masodikSzam); break;
case("*"): eredmeny =
szorzas(elsoSzam, masodikSzam); break;
case("/"): eredmeny = osztas(elsoSzam,
masodikSzam); break;
}
return eredmeny;
}
public static void main(String[] args) {
String[] bemenetiAdatTomb = new String[3];
bemenetiAdatTomb = adatBekeres();
double elsoSzam = Double.parseDouble(bemenetiAdatTomb[0]);
double masodikSzam = Double.parseDouble(bemenetiAdatTomb[2]);
String muveletiJel = bemenetiAdatTomb[1];
System.out.println(kiertekeles(elsoSzam, masodikSzam,
muveletiJel));
}
}
Végeredmény:
Kérem adja
meg az 1. számot!
w
Kérem, hogy csak pozitív egész számot adjon meg!
q
Kérem, hogy csak pozitív egész számot adjon meg!
0
Kérem, hogy csak pozitív egész számot adjon meg!
120
Kérem adja meg a műveleti jelet!
s
Kérem, hogy csak + - * / jeleket adjon meg!
-
Kérem adja meg a 2. számot!
0
Kérem, hogy csak pozitív egész számot adjon meg!
a
Kérem, hogy csak pozitív egész számot adjon meg!
33
87.0
A különálló számellenőrző függvénynek...
static boolean ellenorzesSzam(String bemenetiAdat){
boolean rosszAdat = false;
char karakter = bemenetiAdat.charAt(0);
if(karakter == '0'){
rosszAdat = true;
}
for(int i = 0; i < bemenetiAdat.length(); i++){
karakter = bemenetiAdat.charAt(i);
if(karakter
!= '0'
&& karakter != '1'
&& karakter != '2'
&& karakter != '3'
&& karakter != '4'
&& karakter != '5'
&& karakter != '6'
&& karakter != '7'
&& karakter != '8'
&& karakter != '9'){
rosszAdat = true;
break;
}
}
if(rosszAdat == true){
System.out.println("Kérem, hogy csak pozitív egész számot adjon meg!");
}
return rosszAdat;
}
...a következő feltételeket kell teljesítenie:
-
a szám 1. digitén (Digit vagy helyiérték? című fejezet) nem állhat 0,
-
a 2. szám nem lehet 0, hogy elkerüljük a nullával való osztást,
-
bármelyik digiten csakis a következő karakterek bármelyike állhat: 0 1 2 3 4 5 6 7 8 9 (kivéve 0 az 1. digiten),
-
az ellenőrzéshez nem szükséges típuskonverzió (String-ből double),
-
oldja meg a hibaüzenetet is,
-
a függvény kimeneti típusa lehet egyszerű boolean, amely jelzi, hogy jó-e a bevitt bemeneti adat (tipikusan ilyenek vagy ehhez hasonlóak az isValid függvények).
A sikeres implementáció után ugyanezt megtehetjük a műveleti jel ellenőrzésével is, persze műveleti jel-specifikusan:
static
boolean ellenorzesMuveletiJel(String bemenetiAdat){
boolean rosszAdat = false;
char karakter = bemenetiAdat.charAt(0);
if((karakter != '+' && karakter !=
'-' && karakter != '*' && karakter != '/')){
rosszAdat = true;
}
if(rosszAdat == true){
System.out.println("Kérem, hogy csak
+ - * / jeleket adjon meg!");
}
return rosszAdat;
}
Zárásképpen nézzük meg a teljes kódot. Egyúttal az eredménykiírást egy kissé megszépítjük, hogy jobban olvashatóvá váljon:
import java.util.Scanner;
public class Main {
static double osszeadas(double elsoSzam, double masodikSzam){
return elsoSzam + masodikSzam;
}
static double kivonas(double elsoSzam, double masodikSzam){
return elsoSzam - masodikSzam;
}
static double szorzas(double elsoSzam, double masodikSzam){
return elsoSzam * masodikSzam;
}
static double osztas(double elsoSzam, double masodikSzam){
return elsoSzam / masodikSzam;
}
static String[] adatBekeres(){
Scanner in = new Scanner (System.in);
String[] bemenetiAdatTomb = new String[3];
boolean rosszAdat = false;
System.out.println ("Kérem adja meg az 1. számot!");
do{
bemenetiAdatTomb[0] = in.nextLine();
rosszAdat =
ellenorzesSzam(bemenetiAdatTomb[0]);
}while (rosszAdat == true);
rosszAdat = false;
System.out.println ("Kérem adja meg a műveleti jelet!");
do{
bemenetiAdatTomb[1] = in.nextLine();
rosszAdat =
ellenorzesMuveletiJel(bemenetiAdatTomb[1]);
}while (rosszAdat == true);
rosszAdat = false;
System.out.println ("Kérem adja meg a 2. számot!");
do{
bemenetiAdatTomb[2] = in.nextLine();
rosszAdat =
ellenorzesSzam(bemenetiAdatTomb[2]);
}while (rosszAdat == true);
return bemenetiAdatTomb;
}
static boolean ellenorzesSzam(String bemenetiAdat){
boolean rosszAdat = false;
char karakter = bemenetiAdat.charAt(0);
if(karakter == '0'){
rosszAdat = true;
}
for(int i = 0; i < bemenetiAdat.length(); i++){
karakter = bemenetiAdat.charAt(i);
if(karakter != '0'
&& karakter
!= '1'
&& karakter
!= '2'
&& karakter
!= '3'
&& karakter
!= '4'
&& karakter
!= '5'
&& karakter
!= '6'
&& karakter
!= '7'
&& karakter
!= '8'
&& karakter
!= '9'){
rosszAdat =
true;
break;
}
}
if(rosszAdat == true){
System.out.println("Kérem, hogy csak
pozitív egész számot adjon meg!");
}
return rosszAdat;
}
static boolean ellenorzesMuveletiJel(String bemenetiAdat){
boolean rosszAdat = false;
char karakter = bemenetiAdat.charAt(0);
if((karakter != '+' && karakter != '-' && karakter != '*' &&
karakter != '/')){
rosszAdat = true;
}
if(rosszAdat == true){
System.out.println("Kérem, hogy csak
+ - * / jeleket adjon meg!");
}
return rosszAdat;
}
static double kiertekeles(double elsoSzam, double masodikSzam, String
muveletiJel){
double eredmeny = 0;
switch(muveletiJel){
case("+"): eredmeny =
osszeadas(elsoSzam, masodikSzam); break;
case("-"): eredmeny =
kivonas(elsoSzam, masodikSzam); break;
case("*"): eredmeny =
szorzas(elsoSzam, masodikSzam); break;
case("/"): eredmeny = osztas(elsoSzam,
masodikSzam); break;
}
return eredmeny;
}
public static void main(String[] args) {
String[] bemenetiAdatTomb = new String[3];
bemenetiAdatTomb = adatBekeres();
double elsoSzam = Double.parseDouble(bemenetiAdatTomb[0]);
double masodikSzam = Double.parseDouble(bemenetiAdatTomb[2]);
String muveletiJel = bemenetiAdatTomb[1];
System.out.println(elsoSzam + " " + muveletiJel + " " +
masodikSzam + " = " +
kiertekeles(elsoSzam, masodikSzam, muveletiJel));
}
}
Végeredmény:
Kérem adja
meg az 1. számot!
w
Kérem, hogy csak pozitív egész számot adjon meg!
qwert
Kérem, hogy csak pozitív egész számot adjon meg!
0
Kérem, hogy csak pozitív egész számot adjon meg!
120
Kérem adja meg a műveleti jelet!
sde
Kérem, hogy csak + - * / jeleket adjon meg!
b
Kérem, hogy csak + - * / jeleket adjon meg!
/
Kérem adja meg a 2. számot!
0
Kérem, hogy csak pozitív egész számot adjon meg!
hj
Kérem, hogy csak pozitív egész számot adjon meg!
23
120.0 / 23.0 = 5.217391304347826
Természetesen minél bonyolultabb egy programozás-technikai probléma, annál többféleképpen lehetséges megoldani. A fenti megoldás csak egy lehetőség a rengeteg további közül.