Docstoc

javapuzzles

Document Sample
javapuzzles Powered By Docstoc
					Java Programming
Puzzles

Sang Shin
sang.shin@sun.com
www.javapassion.com
Sun Microsystems, Inc.
Today's Presentation slides
and Source-code (in the form
     of NetBeans-ready
 Projects) are available from

www.javapassion.com
   (Check Feb. 7th, 2007)
Free Java Online Courses I Teach
• Java Programming
  > http://www.javapassion.com/javaintro
• Java EE Programming
  > http://www.javapassion.com/j2ee
• Ajax programming
  > http://www.javapassion.com/ajaxcodecamp/
• Web services programming
  > http://www.javapassion.com/webservices
• XML
  > http://www.javapassion.com/xml
How are we going to solve these
Puzzles?
•   Short Java program with curious behavior
•   What does it print? (multiple choice)
•   Verify result with NetBeans
•   The mystery revealed
•   How to fix the problem
•   Lessons learned
“All I Get is Static!”
Concepts Explored:
Overriding instance method,
Dynamic dispatch (Polymorphic
Behavior), Hiding static method
“All I Get is Static”
01   class Dog {
02       public static void bark() {
03           System.out.print("woof ");
04       }
05   }
06   class Basenji extends Dog {
07       public static void bark() { }
08   }
09   public class Bark {
10       public static void main(String args[]) {
11           Dog woofer = new Dog();
12           Dog nipper = new Basenji();
13           woofer.bark();
14           nipper.bark();
15       }
16   }
What Does It Print?
(a) woof
(b) woof woof
(c) It varies
What Does It Print?
(a) woof
(b) woof woof
(c) It varies

No dynamic dispatch (polymorphic behavior) on static
  methods
Another Look
01   class Dog {
02       public static void bark() {
03           System.out.print("woof ");
04       }
05   }
06   class Basenji extends Dog {
07       public static void bark() { }
08   }
09   public class Bark {
10       public static void main(String args[]) {
11           Dog woofer = new Dog();
12           Dog nipper = new Basenji();
13           woofer.bark();
14           nipper.bark();
15       }
16   }
How Do You Fix It?
• Remove static from the bark methods, thus
  making them instance methods
  > Instance methods are overridden not hidden – dynamic
    dispatch is enabled – polymorphic behavior
Lessons Learned
• Static methods can't be overridden
  > They can only be hidden
• Don’t hide static methods
  > No polymorphic behavior anyway

• Never invoke static methods on instances
  > Syntax-wide allowed, but looks confusing
  > Use Class.staticMethod()
     > Dog.bark()
  > Not instance.staticMethod()
     > nipper.bark()
“Not All Strings
are Equal!”
Concepts Explored:
“==” operator for Reference
objects, String literals,
equals() method
“Not All Strings are Equal”
public class EqualsTestString {

    public static void main(String[] args) {

        String str1 = "Passion!";
        String str2 = str1;
        System.out.println(str1 == str2);

        str2 = new String(str1);
        System.out.println(str1 == str2);
        System.out.println(str1.equals(str2));
    }
}
What Does It Print?
(a) true false true (in separate lines)
(b) true true true
(c) false false true
(d) false false false
What Does It Print?
(a) true false true
(b) true true true
(c) false false true
(d) false false false
Another Look
public class EqualsTestString {

    public static void main(String[] args) {
        String str1 = "Passion!";
        String str2 = str1;
        // str1 and str2 point to the same memory location
        System.out.println(str1 == str2); // true

        str2 = new String(str1);

        // str1 and str2 point to different memory locations
        System.out.println(str1 == str2); // false

        // equals() method of String class compares the
        // values of the strings
        System.out.println(str1.equals(str2)); //true
    }
}
Lessons Learned
• Use equals, not ==, for comparing string's values
“Animal Farm!”
Concepts explored:
Precedence between “+”
and “==” operators
“Animal Farm”
01 public class AnimalFarm {
02     public static void main(String[] args) {
03         final String pig = "length: 10";
04         final String dog = "length: "+ pig.length();
05         System.out.println("Animals are equal: "
06                            + pig == dog);
07     }
08 }
What Does It Print?
(a) Animals are equal: true
(b) Animals are equal: false
(c) It varies
(d) None of the above
What Does It Print?
(a) Animals are equal: true
(b) Animals are equal: false
(c) It varies
(d) None of the above: false


The + operator binds tighter than ==
 Another Look
01 public class AnimalFarm {
02     public static void main(String[] args) {
03         final String pig = "length: 10";
04         final String dog = "length: "+pig.length();
05         System.out.println("Animals are equal: "
06                            + pig == dog);
07     }
08 }




System.out.println(
    ("Animals are equal: " + pig) == dog);
How Do You Fix It?
01 public class AnimalFarm {
02     public static void main(String[] args) {
03         final String pig = "length: 10";
04         final String dog = "length: "+ pig.length();
05         System.out.println("Animals are equal: "
06                            + (pig == dog));
07     }
08 }




System.out.println(
    "Animals are equal: " + (pig == dog));
Lessons Learned
• Parenthesize when using string concatenation
  > Spacing can be deceptive; parentheses never lie
• Use equals, not ==, for comparing string's values
“Sum Fun!”
Concepts explored:
Initialization of static method
and static variables
“Sum Fun”
01 class Cache {
02     static { initIfNecessary(); } // Anonymous static method
03     private static int sum;
04     public static int getSum() {
05         initIfNecessary();
06         return sum;
07     }
08     private static boolean initialized = false;
09     private static synchronized void initIfNecessary() {
10         if (!initialized) {
11             for (int i = 0; i < 100; i++)
12                 sum += i;
13             initialized = true;
14         }
15     }
16     public static void main(String[] args) {
17         System.out.println(getSum());
18     }
19 }
What Does It Print?
(a) 4950
(b) 5050
(c) 9900
(d) None of the above
What Does It Print?
(a) 4950
(b) 5050
(c) 9900
(d) None of the above


Lazy initialization + eager initialization = a mess
Another Look
01 class Cache {
02     static { initIfNecessary(); }
03     private static int sum;
04     public static int getSum() {
05         initIfNecessary();
06         return sum;
07     }
08     private static boolean initialized = false;
09     private static synchronized void initIfNecessary() {
10         if (!initialized) {
11             for (int i = 0; i < 100; i++)
12                 sum += i;
13             initialized = true;
14         }
15     }
16     public static void main(String[] args) {
17         System.out.println(getSum());
18     }
19 }
How Do You Fix It?
01 class Cache {
02     private static final int SUM = computeSum();
03
04     private static int computeSum() {
05         int result = 0;
06         for (int i = 0; i < 100; i++)
07             result += i;
08         return result;
09     }
10
11     public static int getSum() {
12         return SUM;
13     }
14
15     public static void main(String[] args) {
16         System.out.println(getSum());
17     }
18 }
The Moral
• Use eager or lazy initialization, not both
• Think about class initialization
• Avoid complex class initialization sequences
Package Deal
Concept explored:
Access modifiers
“Package Deal”
01 package click;
02 public class CodeTalk {
03     public void doIt() { printMessage(); }
04     void printMessage() { System.out.println("Click"); }
05 }
___________________________________________________________

01   package hack;
02   import click.CodeTalk;
03   public class TypeIt {
04        private static class ClickIt extends CodeTalk {
05            void printMessage() { System.out.println("Hack"); }
06        }
07        public static void main(String[] args) {
08            new ClickIt().doIt();
09      }
10   }
What Does It Print?
(a) Click
(b) Hack
(c) Won’t compile
(d) None of the above
What Does It Print?
(a) Click
(b) Hack
(c) Won’t compile
(d) None of the above




There is no overriding in this program
Another Look
01 package click;
02 public class CodeTalk {
03     public void doIt() { printMessage(); }
04     void printMessage() { System.out.println("Click"); }
05 }
___________________________________________________________

01   package hack;
02   import click.CodeTalk;
03   public class TypeIt {
04       private static class ClickIt extends CodeTalk {
05           void printMessage() { System.out.println("Hack"); }
06       }
07       public static void main(String[] args) {
08           new ClickIt().doIt();
09       }
10   }
How Do You Fix It?
• If you want overriding
  • Make printMessage public or protected
  • Use @Override to ensure that you got overriding
Lessons Learned
• Package-private (default) methods can’t be
  overridden by methods outside their package
• If you can’t see it, you can’t override it
Java Program Structure:
The Access Modifiers
Tricky Assignment!
Concepts explored:
Behavior of postfix operator
“A Tricky Assignment”
01 public class Assignment {
02     public static void main(String[] a) throws Exception {
03         int tricky = 0;
04         for (int i = 0; i < 3; i++)
05             tricky += tricky++;
06         System.out.println(tricky);
07     }
08 }
What Does It Print?
(a) 0
(b) 3
(c) 14
(d) None of the above
What Does It Print?
(a) 0
(b) 3
(c) 14
(d) None of the above
Another Look
01 public class Assignment {
02     public static void main(String[] a) throws Exception {
03         int tricky = 0;
04         for (int i = 0; i < 3; i++)
05             tricky += tricky++;
06         System.out.println(tricky);
07     }
08 }
How Do You Fix It?
01 public class Assignment {
02     public static void main(String[] a) throws Exception {
03         int tricky = 0;
04         for (int i = 0; i < 3; i++) {
05             tricky++;
06             tricky += tricky; // or tricky *= 2;
07         }
08         System.out.println(tricky);
09     }
10 }
The Moral
•   Don’t depend on details of expression evaluation
•   Don’t assign to a variable twice in one expression
•   Postfix increment returns old value
•   Operands are evaluated left to right
Thrown For a Loop!
 “Thrown for a Loop”
01 public class Loop {
02     public static void main(String[] args) {
03         int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1,    2 },
04                        { 1, 2, 3 }, { 1, 2, 3, 4 }, {   1 } };
05         int successCount = 0;
06         try {
07             int i = 0;
08             while (true) {
09                 if (thirdElementIsThree(tests[i++]))
10                     successCount++;
11             }
12         } catch (ArrayIndexOutOfBoundsException e) {    }
13         System.out.println(successCount);
14     }
15     private static boolean thirdElementIsThree(int[]    a) {
16         return a.length >= 3 & a[2] == 3;
17     }
18 }
What Does It Print?
(a) 0
(b) 1
(c) 2
(d) None of the above
What Does It Print?
(a) 0
(b) 1
(c) 2
(d) None of the above



Not only is the program repulsive, but it has a bug
Another Look
01 public class Loop {
02     public static void main(String[] args) {
03         int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1,    2 },
04                        { 1, 2, 3 }, { 1, 2, 3, 4 }, {   1 } };
05         int successCount = 0;
06         try {
07             int i = 0;
08             while (true) {
09                 if (thirdElementIsThree(tests[i++]))
10                     successCount++;
11             }
12         } catch (ArrayIndexOutOfBoundsException e) {    }
13         System.out.println(successCount);
14     }
15     private static boolean thirdElementIsThree(int[]    a) {
16         return a.length >= 3 & a[2] == 3;
17     }
18 }
How Do You Fix It?
01 public class Loop {
02     public static void main(String[] args) {
03         int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1, 2 },
04                      { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 } };
05         int successCount = 0;
06         for (int[] test : tests)
07             if (thirdElementIsThree(test))
08                 successCount++;
09         System.out.println(successCount);
10     }
11
12     private static boolean thirdElementIsThree(int[] a) {
13         return a.length >= 3 && a[2] == 3;
14     }
15 }
Lessons Learned
• Use exceptions only for exceptional conditions
  > Never use exceptions for normal control flow
• Beware the logical AND and OR operators
  > Document all intentional uses of & and | on boolean
Lazy Initialization!
8. “Lazy Initialization”
01 public class Lazy {
02     private static boolean initialized = false;
03     static {
04         Thread t = new Thread(new Runnable() {
05              public void run() {
06                  initialized = true;
07              }
08         });
09         t. start();
10         try {
11              t.join();
12         } catch (InterruptedException e) {
13              throw new AssertionError(e);
14         }
15     }
16     public static void main(String[] args) {
17         System.out.println(initialized);
18     }
19 }
What Does It Print?
(a) true
(b) false
(c) It varies
(d) None of the above
What Does It Print?
(a) true
(b) false
(c) It varies
(d) None of the above: it deadlocks



Intuition: You wouldn’t believe us if we told you.
Another Look
01 public class Lazy {
02     private static boolean initialized = false;
03     static {
04         Thread t = new Thread(new Runnable() {
05              public void run() {
06                  initialized = true; // Deadlocks here!
07              }
08         });
09         t. start();
10         try {
11              t.join();
12         } catch (InterruptedException e) {
13              throw new AssertionError(e);
14         }
15     }
16     public static void main(String[] args) {
17         System.out.println(initialized);
18     }
19 }
How Do You Fix It?
• Don’t use background threads in class initialization
  > If it hurts when you go like that, don’t go like that!
The Moral
• Never use background threads in class initialization
• Keep class initialization simple
• Don’t code like my sister
The Joy of Hex!
“The Joy of Hex”
01 public class JoyOfHex {
02     public static void main(String[] args) {
03         System.out.println(
04             Long.toHexString(0x100000000L + 0xcafebabe));
05     }
06 }
What Does It Print?
(a) cafebabe
(b) 1cafebabe
(c) ffffffffcafebabe
(d) Throws an exception
What Does It Print?
(a) cafebabe
(b) 1cafebabe
(c) ffffffffcafebabe
(d) Throws an exception


0xcafebabe is a negative number
Another Look
01 public class JoyOfHex {
02      public static void main(String[] args) {
03          System.out.println(
04              Long.toHexString(0x100000000L +
   0xcafebabe));
05      }
06 }



           1 1 1 1 1 1 1

       0xffffffffcafebabeL
     + 0x0000000100000000L
       0x00000000cafebabeL
How Do You Fix It?
01 public class JoyOfHex {
02     public static void main(String[] args) {
03         System.out.println(
04             Long.toHexString(0x100000000L + 0xcafebabeL));
05     }
06 }
The Moral
• Decimal literals are all positive; not so for hex
  > Negative decimal constants have minus sign
  > Hex literals are negative if the high-order bit is set
• Widening conversion can cause sign extension
• Mixed-mode arithmetic is tricky—avoid it
Java Programming
Puzzles

Sang Shin
sang.shin@sun.com
www.javapassion.com
Sun Microsystems, Inc.

				
DOCUMENT INFO
Shared By:
Stats:
views:71
posted:2/26/2010
language:English
pages:68
sreekanth reddy sreekanth reddy Software Engineer englishmoviedl.blogspot.com
About i am peaceful and kind person