I am working to make a Advent Calendar for Christmas and needed to use a switch statement. My biggest dilemma is the fact that each (daysAway) case opens a new class designed for that day in particular. I am working off of what Google and Stack overflow can provide. I was wondering if there was any other way to compact this?
public void onClick(View v) {
//Calculate the days between (date - 12/7/20)
LocalDate dateBefore = java.time.LocalDate.now();
LocalDate dateAfter = LocalDate.of(2020, Month.DECEMBER, 25);
int daysAway = (int) ChronoUnit.DAYS.between(dateBefore, dateAfter);
switch(daysAway){
case 24:
openDay1();
break;
case 23:
openDay2();
break;
case 22:
openDay3;
break;
case 21:
openDay4;
break;
case 20:
openDay5;
break;
case 19:
openDay6;
break;
case 18:
openDay7;
break;
case 17:
openDay8;
break;
case 16:
openDay9;
break;
case 15:
openDay10;
break;
case 14:
openDay11;
break;
case 13:
openDay12;
break;
case 12:
openDay13;
break;
case 11:
openDay14;
break;
case 10:
openDay15;
break;
case 9:
openDay16;
break;
case 8:
openDay17;
break;
case 7:
openDay18;
break;
case 6:
openDay19;
break;
case 5:
openDay20;
break;
case 4:
openDay21;
break;
case 3:
openDay22;
break;
case 2:
openDay23;
break;
case 1:
openDay24;
break;
case 0:
openChristmas;
break;
default:
notTime.start();
break;
}
}
I know it is a giant mess and that is what I am trying to fix! I appreciate any feedback you can give!
Advertisement
Answer
Use Java 14 switch expression syntax:
JavaScriptswitch (daysAway) {
case 24 -> openDay1();
case 23 -> openDay2();
case 22 -> openDay3();
case 21 -> openDay4();
// ...
case 4 -> openDay21();
case 3 -> openDay22();
case 2 -> openDay23();
case 1 -> openDay24();
case 0 -> openChristmas();
default -> notTime.start();
}
Since the code is very simple, just collapse it on one line:
JavaScriptswitch (daysAway) {
case 24: openDay1(); break;
case 23: openDay2(); break;
case 22: openDay3(); break;
case 21: openDay4(); break;
// ...
case 4: openDay21(); break;
case 3: openDay22(); break;
case 2: openDay23(); break;
case 1: openDay24(); break;
case 0: openChristmas(); break;
default: notTime.start();
}
Use an array of Java 8 method references (notice reversed order):
JavaScriptRunnable[] OPEN_METHODS = {
this::openChristmas,
this::openDay24,
this::openDay23,
this::openDay22,
this::openDay21,
// ...
this::openDay4,
this::openDay3,
this::openDay2,
this::openDay1
};
JavaScriptif (daysAway >= 0 && daysAway <= 24) {
OPEN_METHODS[daysAway].run();
} else {
notTime.start();
}
Since you said that “each (daysAway) case opens a new class designed for that day”, use an interface (e.g.
Runnable
) and an array of class literals:JavaScriptClass<?>[] OPEN_CLASSES = {
OpenChristmas.class,
OpenDay24.class,
OpenDay23.class,
OpenDay22.class,
OpenDay21.class,
// ...
OpenDay4.class,
OpenDay3.class,
OpenDay2.class,
OpenDay1.class
};
JavaScriptif (daysAway < 0 || daysAway > 24) {
notTime.start();
} else {
Runnable clazz;
try {
clazz = (Runnable) OPEN_CLASSES[daysAway].getConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new AssertionError("Oops: " + e, e);
}
clazz.run();
}
You can also build the class name dynamically (no array or
switch
statement):JavaScriptif (daysAway < 0 || daysAway > 24) {
notTime.start();
} else {
String className = (daysAway == 0 ? "OpenChristmas" : "OpenDay" + (25 - daysAway));
Runnable clazz;
try {
clazz = (Runnable) Class.forName(className).getConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new AssertionError("Oops: " + e, e);
}
clazz.run();
}