Which is better? 26-Jul-16 Which is better? Assume s1 and s2 are Strings: A. if (s1 == s2) { ... } B. if (s1.equals(s2)) { ... } ? 2 Answer: B s1 == s2 tests whether s1 and s2 reference the same string; s1.equals(s2) tests whether they reference equal strings String s1 = "ABC"; String s2 = s1; String s3 = "ABC"; String s4 = "AB" + "C" All these strings are equal; but s4 is in a different memory location than the others, so the == test yields false 3 Which is better? Assume s1 is a String: A. if (s1.equals("OK")) { ... } B. if ("OK".equals(s1)) { ... } ? 4 Answer: B s1.equals("OK") sends a message to s1 asking if it is equal to "OK" "OK".equals(s1) sends a message to "OK" asking if it is equal to s1 This is legal, because "OK" is a String If s1 is null, then: s1.equals("OK") gives a NullPointerException "OK".equals(s1) gives false (Of course, in some circumstances you might prefer to get a NullPointerException) 5 Which is best? Assume int numbers[ ] = new int[100]; A. for (int i = 0; i < 100; i++) numbers[i] = i; B. for (int i = 0; i <= 99; i++) numbers[i] = i; C. for (int i = 0; i < ARRAY_SIZE; i++) numbers[i] = i; D. for (int i = 0; i < numbers.length; i++) numbers[i] = i; ? 6 Answer: D D is best: for (int i = 0; i < numbers.length; i++) C is OK: for (int i = 0; i < ARRAY_SIZE; i++) Changing ARRAY_SIZE will fix this loop if array size is changed B is poor: for (int i = 0; i < 100; i++) numbers.length changes automatically if array size is changed Uses a “magic number” Must track down and change each occurrence if array size is changed A is worst: for (int i = 0; i <= 99; i++) This has all the same problems as B B is more traditional and therefore less “surprising” The array size is 100, not 99, so it’s more obvious where the number came from You have to do some arithmetic to get 99 If you change the array size, a search for 100 won’t find the loop that uses 99 7 Which is better? Assume finished is a boolean variable: A. if (finished == true) {...} B. if (finished) {...} ? 8 Answer: B finished == true is redundant: If finished is true, then finished==true will be true If finished is false, then finished==true will be false The extra words don’t gain you anything finished==true might seem more readable to a beginner, but you quickly learn to read the shorter form Brevity in programming, as in writing, is a virtue You can avoid the possible mistake of saying if (finished = true) { ... } 9 Which is better? Assume foo, bar, and larger are integers A. if (foo > bar) larger = foo; else larger = bar; B. larger = foo > bar ? foo : bar; ? 10 Answer: neither For each of these, you have to look at the code carefully to make sure it is correct larger = Math.max(foo, bar); is easier to read and more obviously correct 11 Which is better? A. String s = "Hello"; B. String s = new String("Hello"); ? 12 Answer: A "Hello" is special syntax to implicitly construct a string String s = new String("Hello"); actually constructs two strings: "Hello" constructs the first string, then it is given as a parameter to an explicit constructor, which constructs the second string 13 Which is better? Suppose p is a JPanel with a BorderLayout and okButton is a JButton: A. p.add(okButton, BorderLayout.NORTH); B. p.add(okButton, "North"); Note: BorderLayout.NORTH == "North" ? 14 Answer: A p.add(okButton, BorderLayout.NORTH); is strongly recommended over the shorter form p.add(okButton, "North") -- but why? Answer: The former gives better error detection If you type p.add(okButton, "north"), there is no error, but it doesn’t do what you want If you type p.add(okButton, BorderLayout.North) you will get a syntax error, because BorderLayout has no such variable as North 15 Which is best? Suppose n is an int and s is a String: A. s = Integer.toString(n); B. s = String.valueOf(n); C. s = new Integer(n).toString(); D. s = n + ""; ? 16 Answer: D I prefer D (s = n + ""; ) because: It’s a common idiom, therefore easily recognized It’s short It works for any type 17 Which is best? Assume n is an integer: A. if (n < 0) n = 0; B. if (n < 0) n = 0; C. if (n < 0) { n = 0; } ? 18 Answer: C If, later on, you want to add a statement, it’s easy to make this mistake with B: if (n < 0) System.out.println("n was " + n); n = 0; You won’t make this mistake with A or C With C (using braces), you don’t have to change anything that’s already there However, A (all on one line) is often convenient 19 Which is better? Assume n is an integer: A. int factorial = 1; for (int i = 2; i < n; i++) { factorial *= n; } B. int factorial = 1; int i; for (i = 2; i < n; i++) { factorial *= n; } ? 20 Answer: A In most cases, you don’t care about the index of a for loop outside the loop You typically give it an initial value in the loop You typically already have its final value in some variable or by some simple computation If you don’t need a variable, you shouldn’t have that variable It doesn’t help anything, and it might get in the way 21 Which is better? A. int search(int[] array, int target) { for (int i = 0; i < array.length; i++) { if (array[i] == target) return i; } return -1; } B. int search(int[] array, int target) throws NotFoundException() { for (int i = 0; i < array.length; i++) { if (array[i] == target) return i; } return new NotFoundException(); } ? 22 Answer: A Exceptions should be used for exceptional cases, not for normal program control In almost all cases, not finding something in an array search is one of the expected outcomes 23 Which is better? A. private void combinations(int n, int t) throws InvalidArgumentException { if (t < 0 || t > n) { throw new InvalidArgumentException(); ... B. private void combinations(int n, int t) { assert t >= 0 && t <= n; ... ? 24 Answer: B The method is marked private, so you (the person writing this class) will be the only one using this method If you call it incorrectly, it’s a bug, not just an unexpected external event, and should be fixed, not tested for Besides, using an assert statement is a lot less work 25 Which is better? A. class Line { public Point start; public Point end; public double length; ... } B. class Line { public Point start; public Point end; public int length() {...}; ... } ? 26 Answer: B Two main reasons: The DRY principle says: Don’t repeat yourself The length variable makes the object vulnerable to inconsistent changes The length variable is a subtle kind of repetition; its value is determined by the start and end points Whenever you have the same information represented in two places, you have the extra requirement to keep them consistent If some external agency changed only the start or the end point, the length variable would become incorrect The length method would continue to give correct results If efficiency is a critical issue, use setters and getters 27 Which is better? You need to write a class which splits input lines into fields: A. class Split { public Split(InputStreamReader reader) // constructor public void readNextLine() throws IOException {...} public int numFields() {...} public String getField(int fieldNumber) {...} } B. class Split { public Split(String line) {...} //constructor public int numFields() {...} public String getField() {...} } ? 28 Answer: B The second Split class just splits lines; it isn’t concerned with where the lines come from The first version can only split lines that come from an input stream, and is therefore less versatile 29 Conclusions There are various ways to do things One way may be better than another because: It’s easier to read and understand It’s more familiar—the way things are usually done It’s less error prone, or provides better error detection It’s more efficient This is a good reason when the savings are dramatic enough to be noticable 30 The End 31