12. common errors, a few puzzles. © o. nierstrasz p2 — common errors, a few puzzles 12.2 common...
TRANSCRIPT
12. Common Errors, a few Puzzles
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.2
Common Errors, a few Puzzles
Sources> Cay Horstmann, Computing Concepts with Java
Essentials, Wiley, 1998> The Java Report, April 1999
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.3
Roadmap
> Common errors …— Typical programming traps
> A few Java puzzles ...— The darker side of Java
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.4
Roadmap
> Common errors …— Typical programming traps
> A few Java puzzles ...— The darker side of Java
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.5
Trap 1
What does this print?
25.0 Don’t assume that floating point numbers are exact representations of mathematical values!
double f = 2e15 + 0.13;double g = 2e15 + 0.02;
println(100*(f-g));
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.6
static void test(String name, boolean bool) {println(name + ": " + (bool?"true":"false"));
}
Trap 2
When are two Strings equal?
== tests object identity;equals() tests object equality
String s1 = new String("This is a string");String s2 = new String("This is a string");test("String==", s1 == s2);test("String.equals", s1.equals(s2));
String==: falseString.equals: true
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.7
Trap 3
When are two Objects equal?
object==: falseobject.equals: false
The default implementation of equals() is ==, and should normally be overwritten
Object x = new Object();Object y = new Object();test("object==", x == y);test("object.equals", x.equals(y));
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.8
Trap 4
When are two Strings equal?
String==: trueString.equals: true
Literal strings with the same content refer to the same object!Always use equals() or compareTo() to compare strings.
String s3 = "This is a string";String s4 = "This is a string";test("String==", s3 == s4);test("String.equals", s3.equals(s4));
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.9
Trap 5
Is “now” really before “later”?
see you now
Date later = new Date(now.getTime());
Explicitly create a clone if you need one:
Calendar now = Calendar.getInstance();Calendar later = now;later.set(Calendar.HOUR_OF_DAY, 1 + now.get(Calendar.HOUR_OF_DAY));if (now.before(later)) {
println("see you later");} else {
println("see you now");}
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.10
Trap 6
nothing0 is even1 is negative
static void checkEven(int n) {boolean result = true;if (n>=0)
if ((n%2) == 0)println(n + " is even");
elseprintln(n + " is negative");
}
What is printed when we run these checks?
checkEven(-1);checkEven(0);checkEven(1);
Always use braces to group nested if { } else { } statements!
if (n>=0) {if ((n%2) == 0) {println(n + " is even");
} else {println(n + " is negative");
}}
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.11
Trap 7
The binomial coefficient is
Is this a correct implementation?
binomial(7,3) = 21 35
To avoid off-by-1 errors:1.Count the iterations — do
we always do k multiplications? (no)
2.Check boundary conditions — do we start with n/1 and finish with (n-k+1)/k? (no)
Off-by-1 errors are among the most common mistakes in implementing algorithms.
static int binomial(int n, int k) {int bc = 1;for (int i=1; i<k; i++) {
bc = bc * (n+1-i) / i;}return bc;
}
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.12
Trap 8
For which values does this function work correctly?
brokenFactorial(0) = 1brokenFactorial(5) = 120brokenFactorial(-1) = ... (doesn’t terminate)
Always use an inequality test to terminate a loop.
static int brokenFactorial(int n) {int result=1;for (int i=0; i!=n; i++ ) {
result = result*(i+1);}return result;
}
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.13
Some other common errors
Magic numbers> Never use magic numbers; declare constants instead.Forgetting to set a variable in some branch> If you have non-trivial control flow to set a variable, make sure it
starts off with a reasonable default value.Underestimating size of data sets> Don’t write programs with arbitrary built-in limits (like line-length);
they will break when you least expect it.Leaking encapsulation> Never return a private instance variable! (return a clone instead)
Bugs are always matter of invalid assumptions not holding
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.14
Roadmap
> Common errors …— Typical programming traps
> A few Java puzzles ...— The darker side of Java
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.15
Puzzle 1
A.p()Private methods are statically bound.
A b = new B();b.m();
class A {public void m() { this.p(); }private void p() { println("A.p()"); }
}class B extends A {
private void p() { println("B.p()"); }}
Are private methods inherited?
Which is called? A.p() or B.p()?
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.16
Static and Dynamic Types
Consider:
The static type of variable a is A — i.e., the statically declared class to which it belongs.The static type never changes.
The dynamic type of a is B — i.e., the class of the object currently bound to a.The dynamic type may change throughout the program.
Now the dynamic type is also A!
A a = new B();
a = new A();
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.17
Puzzle 2 (part I)
m(A,A)m(A,B)m(B,A)m(B,B)
The static type of arguments is always used to resolve overloaded method calls.
class A { }class B extends A { }void m(A a1, A a2) { println("m(A,A)"); };void m(A a1, B b1) { println("m(A,B)"); };void m(B b1, A a1) { println("m(B,A)"); };void m(B b1, B b2) { println("m(B,B)"); };B b = new B(); A a = b;
How are overloaded method calls resolved?
m(a, a);m(a, b);m(b, a);m(b, b);
Which is considered: the static or dynamic argument type?
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.18
Puzzle 2 (part II)
What happens if we comment out:
Will the examples still compile?If so, which methods are called?
m(a,a) won’t compilem(b,b) won’t compilePrints:
m(A,A)
m(A,A)
m(B,A)
m(B,B)
m(A,A)?m(B,B)?m(A,B)?
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.19
Puzzle 3
How do static and dynamic types interact?
A.m(A)A.m(A)A.m(A)B.m(B)
Static types determine which message is sent.Dynamic types determine which method is called.
a.m(a);a.m(b);b.m(a);b.m(b);
class A {void m(A a) { println("A.m(A)"); }
}class B extends A {
void m(B b) { println("B.m(B)"); } }B b = new B(); A a = b;
In which cases will B.m(B) be called?
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.20
Puzzle 4 (part I)
C.i = 0C.j = 0C.k = 0C.l = 0
First, default values are assigned ... then constructors are evaluated.
How do default values and constructors interact?class C {
int i = 100, j = 100, k = init(), l = 0;C() { i = 0; k = 0; }int init() { j = 0; l = 100; return 100; }
}
What gets printed? 0 or 100?
C c = new C();println("C.i = " + c.i);println("C.j = " + c.j);println("C.k = " + c.k);println("C.l = " + c.l);
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.21
Puzzle 4 (part II)
B.i = 0B.j = 0
First all super initialization is executed, then the subclass initialization
abstract class A {int j = 100;A() { init(100); j = 200; }abstract void init(int value);
}class B extends A {
int i = 0, j = 0;B() { super(); }void init(int value) { i = value; }
}
B b = new B();println("B.i = " + b.i);println("B.j = " + b.j);
What gets printed? 0, 100 or 200?
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.22
Puzzle 5
The finally clause always takes precedence!3
Does try or finally return?
class A {int m() {
try { return 1; }catch (Exception err) { return 2; }finally { return 3; }
}}
Prints 1, 2, or 3?
A a = new A();println(a.m());
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.23
What you should know!
When can you trust floating-point arithmetic? To which “if” does an “else” belong in a nested if
statement? How can you avoid off-by-1 errors? Why should you never use equality tests to terminate
loops? Are private methods inherited? What are the static and dynamic types of variables? How are they used to dispatch overloaded methods?
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.24
Can you answer these questions?
When is method dispatching ambiguous? Is it better to use default values or constructors to
initialize variables? If both a try clause and its finally clause throw an
exception, which exception is really thrown?
© O. Nierstrasz
P2 — Common Errors, a few Puzzles
12.25
License
> http://creativecommons.org/licenses/by-sa/2.5/
Attribution-ShareAlike 2.5You are free:• to copy, distribute, display, and perform the work• to make derivative works• to make commercial use of the work
Under the following conditions:
Attribution. You must attribute the work in the manner specified by the author or licensor.
Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one.
• For any reuse or distribution, you must make clear to others the license terms of this work.• Any of these conditions can be waived if you get permission from the copyright holder.
Your fair use and other rights are in no way affected by the above.