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:
switch (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:
switch (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):
Runnable[] OPEN_METHODS = { this::openChristmas, this::openDay24, this::openDay23, this::openDay22, this::openDay21, // ... this::openDay4, this::openDay3, this::openDay2, this::openDay1 };
if (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:Class<?>[] OPEN_CLASSES = { OpenChristmas.class, OpenDay24.class, OpenDay23.class, OpenDay22.class, OpenDay21.class, // ... OpenDay4.class, OpenDay3.class, OpenDay2.class, OpenDay1.class };
if (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):if (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(); }