Is there a way to make this switch statement smaller and more professional?

Tags: ,



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!

Answer

  1. 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();
    }
    
  2. 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();
    }
    
  3. 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();
    }
    
  4. 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();
    }
    
  5. 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();
    }
    


Source: stackoverflow