9

Possible Duplicate:
If/Else vs. Switch

I have two codes here, i just wanted to ask which of the two is better in terms of writability(ease of writing the codes) and in terms of readability (ease of understanding the codes).

switch-case:

import java.io.*;

public class Quarter{
    public static void main(String[] args){
        int day;
        String input="";

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Input a number from 1 to 3: ");

        try{
            input=in.readLine();
        }catch(IOException e){
            System.out.println("Error!");
        }
        day=Integer.parseInt(input);

        switch(day){
            case 1:
            case 2:
            case 3:
                System.out.println("1st Quarter");
                break;
            case 4:
            case 5:
            case 6:
                System.out.println("2nd Quarter");
                break;
            case 7:
            case 8:
            case 9:
            System.out.println("3rd Quarter");
            break;
            case 10:
            case 11:
            case 12:
                System.out.println("4th Quarter");
                break;
            default: System.out.println("Error!");
        }

    }
}

if-else:

import java.io.*;

public class Days{
    public static void main(String[] args){
        int day;
        String input="";

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Input a number from 1 to 12: ");

        try{
            input=in.readLine();
        }catch(IOException e){
            System.out.println("Error!");
        }
        day=Integer.parseInt(input);

        if(day>=1 && day<=3){
            System.out.println("1st Quarter");
        }else
        if(day>=4 && day<=6){
            System.out.println("2nd Quarter");
        }else
        if(day>=7 && day<=9){
            System.out.println("3rd Quarter");
        }else
        if(day>=10 && day<=12){
            System.out.println("4th Quarter");
        }else
            System.out.println("Error!");
    }
}
Community
  • 1
  • 1
Zhianc
  • 1,411
  • 3
  • 20
  • 37
  • Not quite a duplicate as that is for c# and this is java so java searchers would not find the original – mmmmmm Jul 28 '11 at 09:16
  • I've noticed quite a few questions asking the same thing, but for a different language. Maybe someone should make a community wiki question, and have an answer which covers the question for each language? – Wipqozn Jul 28 '11 at 10:53

7 Answers7

35

Neither, I'd do this one:

String[] out = {
    "1st Quarter",
    "2nd Quarter",
    "3rd Quarter",
    "4th Quarter"
};

if (1 <= day && day <= 12) {
    System.out.println(out[(day - 1) / 3]);
} else {
    System.out.println("Error!");
}
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
Lie Ryan
  • 62,238
  • 13
  • 100
  • 144
  • 2
    I agree, doing this is much cleaner than using `if` or `switch` blocks. – fireshadow52 Jul 28 '11 at 01:09
  • 4
    There are 12 months to put into 4 bins, so we should be dividing by 3. – Karl Knechtel Jul 28 '11 at 01:13
  • 7
    I support this answer, however to make it better: System.out.println((day>0 && day<13) ? out[(day-1)/3] : "Error!" ) ; – emory Jul 28 '11 at 01:13
  • 6
    Your code is great, but I can't +1 it on account of the fact that you didn't answer the switch/case vs. if/else question, which could have been merely theoretical in nature. This answer unfortunately isn't going to help him next time he faces a switch/case or if/else situation where doing something like this is not possible. – TimFoolery Jul 28 '11 at 04:09
  • 1
    @Michael: the next time he get into this situation, he'd have three choices: switch/case, if/else, or dictionary/array indexing. The switch/case or if/else situation is a false dichotomy. – Lie Ryan Jul 28 '11 at 04:42
  • Very easy to do in this case as all you are doing is outputting a string contained in the `out` array, but I don't see how this could be used if you were doing something like executing different chunks of code depending on what key(s) the user pressed, e.g. Escape->if (selection.length) {selection.clear();} else {textbox.clear}, Enter-> submission code, Ctrl+b->toggle bold, etc. – TimFoolery Jul 28 '11 at 04:56
  • 1
    @Michael: You can use a Dictionary/Hashtable/Map to map between the keys to function objects. However, given that Java's syntax for creating function objects are really clunky, if there is no requirement for being able to remap the key binding, I'd probably use a switch-case. – Lie Ryan Jul 28 '11 at 06:13
  • Alright... +1 then for the more abstract answer! – TimFoolery Jul 28 '11 at 06:19
  • The problem is that this solution is FAR less readable. I glanced at the switch/case statement and instantly knew what it was doing. This one took me a few seconds of doing mental arithmetic. The more thinking is necessary to understand your code, the more likely the next maintainer will break it. – Plutor Jul 28 '11 at 13:09
3

Which one would you prefer? It is your code.

I definitely prefer the switch-case, but if you have something combined or e.g. 'greater than' switch-case is not the right way to do it.

Another thing: I would write the switch case like the following, because I think it is better to read:

switch(day){
    case 1:
    case 2:
    case 3:
        System.out.println("1st Quarter");
        break;
...        
}

HTH, Andreas

Dante May Code
  • 11,177
  • 9
  • 49
  • 81
Andreas
  • 2,694
  • 2
  • 21
  • 33
3
  • Avoid the need for the logic to branch in the first place. Table lookup is often a useful technique. Arithmetic manipulation is also important - look for a pattern in the values you care about, and a function that transforms them into something simpler. Also consider polymorphism in more complex cases.

  • If you are handling all the exceptions the same way, then do it in the same place.

  • Scope variables tightly where possible.

  • Prompt for the input you actually want, FFS. :)

import java.io.*;

public class Quarter {
    public static void main(String[] args) {
        try {
            System.out.print("Input the month number (1 = January, 2 = February ... 12 = December): ");
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            int month = Integer.parseInt(in.readLine());
            int quarter = (month - 1) / 3;
            String[] quarters = new String[]{ "1st", "2nd", "3rd", "4th" };
            System.out.println(quarters[quarter] + " Quarter");
        } catch (Exception e) { // IOException for non-numeric, or AIOOBE for out of range
            System.out.println("Error!");
        }
    }
}
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
2

What about :

(day>=1 && day <=3) ? System.out.println("1st Quarter") :
  (day >= 4 && day <= 6) ? System.out.println("2nd Quarter") :
    (day >=7 && day <= 9) ? System.out.println("3rd Quarter") :
      (day >= 10 && day <= 12) ? System.out.println("4th Quarter") : System.out.println("Error1");

;)

You could also do this:

String val = (day>=1 && day <=3) ? "1st Quarter" :
      (day >= 4 && day <= 6) ? "2nd Quarter" :
        (day >=7 && day <= 9) ? "3rd Quarter" :
          (day >= 10 && day <= 12) ? "4th Quarter" : "Error1";
System.out.println(val);

I think either should work.

David Hoerster
  • 28,421
  • 8
  • 67
  • 102
2

It's not clear to me if the question is about solutions to the specific code example, or about the structure in general. So, some virtues of the if-else approach for consideration.

  • if-else is more common in code overall, because the number of datatypes accepted by switch is limited and switch itself is limited to compile time values. More familiar is better for readability for a broader audience.

  • The fundamental structure doesn't change if you find your requirements changing and you need to support a different datatype. I've had to change plenty of switches on enums to string compares in my time when someone added a requirement that the users be able to configure the options.

  • The need to use break; properly inside switches introduces opportunities for odd bugs that only show up in corner cases as the switches grow large and complicated.

Of course personally being an enterprise programmer I would have created a timeUnitSubDivisionResolvingVisitor ... :)

Affe
  • 47,174
  • 11
  • 83
  • 83
2
String[] suffix = new String[]{ "st", "nd", "rd", "th" };
System.out.println((1 <= day && day <= 12)?
    String.format("%d%s Quarter", (day-1)/3+1, suffix[(day-1)/3]):
    "Error!"
);
mdyang
  • 21
  • 2
1

just an alternative way of implementing it is through a Map. It will make it configurable especially is you're using Spring where you can have this Map variable setup in your bean.xml if you decide to.

Anyway here is the alternative:

Map<Integer, String> m = new HashMap<Integer, String>();
m.put(1, "1st Quarter");
m.put(2, "1st Quarter");
m.put(3, "1st Quarter");
m.put(4, "2nd Quarter");
m.put(5, "2nd Quarter");
m.put(6, "2nd Quarter");
m.put(7, "3rd Quarter");
m.put(8, "3rd Quarter");
m.put(9, "3rd Quarter");
m.put(10, "4th Quarter");
m.put(11, "4th Quarter");
m.put(12, "4th Quarter");

System.out.println(m.get(d));
Carlos Jaime C. De Leon
  • 2,476
  • 2
  • 37
  • 53