Gyakorlati alapok
A kényeskedés netovábbja: a többszörös feltételmegadás (szökőév)
Az előző fejezetben többszörös feltételmegadással bosszantottam a Tisztelt Olvasót. A szökőév kiszámításában ez fog most tetőzni, ugyanis a helyes végeredményhez 4 db feltétel egyidejű teljesülését kell beállítanunk.
Kis elméleti előzmény: a szökőév egy olyan speciális év, amely általában 4 évente +1 napot tartalmaz (február 24.). Erre azért van szükség, mert a csillagászati év és az 1582 óta működő Gergely-, másik nevén Gregorián-naptár között folyamatosan korrigálandó, időbeli eltérések vannak. A szökőév nem tévesztendő össze a szökőmásodpercekkel, amelyeket -ugyanilyen okból-, a csillagászati naphosszhoz szintén korrigálnak.
Először is ne ijedjünk meg, mert az igényt a Java alkotói is észrevették, ezért a szökőév kiszámításának algoritmusát már beépítették a java.util csomagba. Eléréséhez a csomagot (vagy annak részét) be kell importálnunk a projektbe (import java.util.*;):
import java.util.*;
public class Main {
public static void main(String[] args) {
int ev = 2000;
GregorianCalendar gc = new GregorianCalendar();
System.out.print(gc.isLeapYear(ev));
}
}
Végeredmény:
true
A szökőévet int típusként adjuk meg, mert a függvény (isLeapVear(int)) ezt kéri. A függvény visszatérési értéke kétféle lehet: igaz (true) vagy hamis (false). Igaz, ha a szám szökőév, másként hamis értéket ad vissza. A kiíráskor tudjuk ezt ellenőrizni.
Természetesen a naptárobjektum létrehozása után (GregorianCalendar gc = new GregorianCalendar()) nemcsak ezt az egy, hanem számos további, naptár és dátum jellegű metódust tudunk elérni; ezt egy külön fejezetben fogjuk megvizsgálni.
A szökőév kézi vizsgálatához a következő feltételek ismeretére van szükségünk:
-
nagyobb 1582-nél (ev > 1582),
-
osztható 4-gyel (ev % 4 == 0),
-
nem osztható 100-zal (ev % 100 != 0),
-
osztható 400-zal (ev % 400 == 0).
A feltétel megadásában azonban van 1 kis trükk. Mivel nincs olyan szám, amelyik ugyan osztható 400-zal, de NEM osztható 100-zal, ezért közöttük nem logikai ÉS (&&), hanem VAGY (||) műveletet kell alkalmaznunk:
if ((ev > 1582) && (ev % 4 == 0) && (ev % 100 != 0) || (ev % 400 == 0))
public class Main {
public static void main(String[] args) {
int ev = 2000;
if ((ev > 1582) && (ev % 4 == 0) && (ev % 100 != 0) || (ev
% 400 == 0)){
System.out.println ("Az év szökőév.");
}
else
System.out.println ("Az év NEM szökőév.");
}
}
Végeredmény:
Az év szökőév.
Most pedig írjunk egy olyan algoritmust, amely a gépi (beépített Java) és a saját (nevezzük kézinek) szökőévszámítást hasonlítja össze! A kód mindezt külön fogja elvégezni, ám az összehasonlításhoz egy flag-re, egy segédváltozóra is szükségünk van, ez a boolean szokoEv lesz. Értéke alapértelmezésben false, true értékre pedig akkor lesz állítva, ha kézi ellenőrzéskor az év szökőévnek bizonyul. Erre azért van szükség, mert a gépi függvény (gc.isLeapYear(ev)) szintén boolean értéket ad vissza, tehát nekünk ezt a 2 azonos típusú változót kell összehasonlítanunk:
if (gc.isLeapYear(ev) == szokoEv)
import java.util.*;
public class Main {
public static void main(String[] args) {
int ev = 1999;
boolean szokoEv = false;
if (ev > 1582 && ev % 4 == 0 && (ev %
100 != 0 || ev % 400 == 0)){
szokoEv =
true;
System.out.println ("Saját kód: az év szökőév.");
}
else
System.out.println ("Saját kód: az év NEM szökőév.");
GregorianCalendar gc = new GregorianCalendar();
if (gc.isLeapYear(ev)){
System.out.println ("Java-kód: az év
szökőév.");
}
else
System.out.println ("Java-kód: az év
NEM szökőév.");
if (gc.isLeapYear(ev) == szokoEv){
System.out.println ("Egyeznek az
eredmények.");
}
else
System.out.println ("Nem egyeznek az
eredmények.");
}
}
Végeredmény:
Saját kód: az év NEM szökőév.
Java-kód: az év NEM szökőév.
Egyeznek az eredmények.
Csakis akkor van probléma, ha nem egyeznek az eredmények és ez sajnos igen hamar be is következett...
...ugyanis a kód tesztelésekor megdöbbenve vettem észre, hogy a gépi függvény figyelmen kívül hagyja az 1582-es kezdődátumot; a gc.isLeapYear() néhány 1582 alatti dátum esetén -például 1200-, true értéket ad vissza!
Ezt a fogyatékosságot tehát korrigálni ahhoz, hogy a gépi és kézi összehasonlítás korrekt maradjon. Ekkor +1 segédváltozót kellett bevezetnem (boolean szokoEvGepi = false;), illetve gépi ellenőrzéskor a kérdéses +1 feltételt (if (gc.isLeapYear(ev) && ev > 1582)). Illetve -mivel megbizonyosodtunk arról, hogy a gépi függvény nem mindig ad korrekt eredményt-, a gépi és kézi összehasonlításkor már csak a saját kezelésű segédváltozók kerültek be a logikai döntésbe (if (szokoEvGepi == szokoEvKezi)):
import java.util.*;
public class Main {
public static void main(String[] args) {
int ev = 1200;
boolean szokoEvKezi = false;
boolean szokoEvGepi = false;
if (ev > 1582 && ev % 4 == 0 && (ev % 100 != 0 || ev % 400 ==
0)){
szokoEvKezi = true;
System.out.println ("Saját kód: az év
szökőév.");
}
else
System.out.println ("Saját kód: az év
NEM szökőév.");
GregorianCalendar gc = new GregorianCalendar();
if (gc.isLeapYear(ev) && ev > 1582){
szokoEvGepi = true;
System.out.println ("Java-kód: az év
szökőév.");
}
else
System.out.println ("Java-kód: az év
NEM szökőév.");
if (szokoEvGepi == szokoEvKezi){
System.out.println ("Egyeznek az
eredmények.");
}
else
System.out.println ("Nem egyeznek az
eredmények.");
}
}
Segédlet:
-
szökőévek - 1600, 1988, 1992, 1996, 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2400.
-
nem szökőévek - 1700, 1800, 1900, 2100, 2200, 2300.