1> Wrapper
1) Boxing, ==, and equals()
public class WrapperTest { @Test public void integerEqualsTest() { assertFalse(new Integer(127) == new Integer(127)); assertTrue((new Integer(127)).equals(new Integer(127))); Integer i = 127; Integer j = 127; assertTrue(i == j); assertTrue(i.equals(j)); i = 128; j = 128; assertFalse(i == j); assertTrue(i.equals(j)); } @Test public void booleanEqualsTest() { assertFalse(new Boolean("true") == new Boolean("true")); assertTrue((new Boolean("true")).equals(new Boolean("true"))); Boolean a = true; Boolean b = true; assertTrue(a == b); } }
* Boolean
* Byte
* Character from '\u0000' to '\u007f' (7f is 127 in decimal)
* Short and Integer from -128 to +127
2) Pay attention to null
@Test public void nullTest() { Person p = new Person(); assertNull(p.age); } public static class Person { Integer age; }
2> Wrapper with Overloading
1) In every case, when an exact match isn't found, the JVM uses the method with the smallest argument that is wider than the parameter.
public class WrapperTest2 { @Test public void integerEqualsTest() { byte a = 123; assertEquals("Go Int", go(a)); short b = 259; assertEquals("Go Int", go(b)); long d = 12345L; assertEquals("Go Long", go(d)); float e = 123.34F; assertEquals("Go Double", go(e)); } public String go(long a) { return "Go Long"; } public String go(int a) { return "Go Int"; } public String go(double a) { return "Go Double"; } }
2) Widening > Autoboxing > Var-args
@Test public void wideningTest() { assertEquals("Go Long", go(123)); // Widening beats Auto-Boxing assertEquals("Go Int", go(new Integer(123))); assertEquals("Go Auto-Boxing", go(1, 2)); // Auto-Boxing beats Var-Args } public String go(long a) { return "Go Long"; } public String go(Integer a) { return "Go Int"; } public String go(int... a) { return "Go Var-args"; } public String go(Integer a, Integer b) { return "Go Auto-Boxing"; }
3) It is also legal to widening reference types to its parent types.
public class WrapperTest3 { @Test public void wideningTest() { assertEquals("Hello Parent", sayHello(new Child())); } public String sayHello(Parent p) { return "Hello Parent"; } public static class Parent { } public static class Child extends Parent { } }
4) It is illegal to widening "Integer" to "Long" which may cause compilation error.
* You CANNOT widen from one wrapper type to another.
* You CANNOT widen and the box. (An int cannot become a Long)
* You can box then widen. (An int can become Object, via Integer)
* You can combine var-args with either widening or boxing.
3>
@Test public void logicTest() { boolean b = false; assertFalse(b = false); assertTrue(b = true); }
4> Flow Control
1) The only legal expression in an if test is a boolean. In some languages, 0 == false, and 1 == true. Not so in Java!
@Test public void conditionTest() { int i = 0; if (i) { // Compilation error! } }
2) A switch's expression must evaluate a 'char', 'byte', 'short', 'int', 'enum', or 'String'(as of Java 7).
@Test public void switchTest() { byte num = 123; switch (num) { case 127 : break; case 128 : // Compilation Error! break; case -128 : break; case -129 : // Compilation Error! break; } }
@Test public void switchTest() { int num = 123; switch (num) { case 127 : break; case 127 : // Compilation Error! break; } }
3) A case constant must be a compile time constant. It is not enough to be final, it must be a compile time constant.
@Test public void caseTest() { final int x = 2; final int y; y = 3; final int z = getNumber(); int num = 1; switch (num) { case x : System.out.println("Hello X"); break; case y : // Compilation Error! System.out.println("Hello Y"); break; case z : // Compilation Error! System.out.println("Hello Z"); break; } } private int getNumber() { return 0; }
4) 'break' statement:
@Test public void breakTest() { switch (Color.GREEN) { case BLUE : System.out.println("BLUE"); case GREEN : System.out.println("GREEN"); case YELLOW : System.out.println("YELLOW"); default : System.out.println("DEFAULT"); } } enum Color { GREEN, BLUE, YELLOW; } // Output: GREEN YELLOW DEFAULT
5) 'default' statement: The 'default' can be located at the end, middle, or top.
@Test public void defaultTest() { switch (Color.BLACK) { case BLUE : System.out.println("BLUE"); default : System.out.println("DEFAULT"); case GREEN : System.out.println("GREEN"); case YELLOW : System.out.println("YELLOW"); } } enum Color { GREEN, BLUE, YELLOW, BLACK; } //output: DEFAULT GREEN YELLOW
@Test public void defaultTest() { switch (Color.GREEN) { case BLUE : System.out.println("BLUE"); default : System.out.println("DEFAULT"); case GREEN : System.out.println("GREEN"); case YELLOW : System.out.println("YELLOW"); } } enum Color { GREEN, BLUE, YELLOW, BLACK; } //output: GREEN YELLOW
6) 'for' loop
@Test public void forLoopTest() { int i; int[] array = {1, 2, 3, 4}; for(i : array){ // Compilation error! i already declared! } }
7) 'for' loop
// continue statement must be inside a loop; otherwise, you'll get a compiler error. // break statement must be inside either a loop or a switch statement.
8) 'continue' in 'for' loop
@Test public void forTest() { for (int i = 0; i < 10; i++) { continue; } // for (int i = 0; i < 10;) { // continue; // i++; //compilation error! Will never reach here! // } for (int i = 0; i < 10;) { if (i == 5) { continue; } i++; } } // the first for-loop will loop for 10 times. // the second for-loop will loop forever.
9) Labeled Statements:
@Test public void labeledTest1() { System.out.println("A"); boolean isTrue = true; for (int i = 0; i < 2; i++) { System.out.println("B"); while (isTrue) { break; } System.out.println("C"); } System.out.println("D"); } //output: A B C B C D
@Test public void labeledTest2() { System.out.println("A"); boolean isTrue = true; outer : for (int i = 0; i < 2; i++) { System.out.println("B"); while (isTrue) { break outer; } System.out.println("C"); } System.out.println("D"); } //output: A B D
@Test public void labeledTest3() { System.out.println("A"); for (int i = 0; i < 2; i++) { System.out.println("B"); for (int j = 0; j < 2; j++) { System.out.println("C"); continue; } System.out.println("D"); } System.out.println("E"); } //output: A B C C D B C C D E
@Test public void labeledTest4() { System.out.println("A"); outer : for (int i = 0; i < 2; i++) { System.out.println("B"); for (int j = 0; j < 2; j++) { // j++ is dead code System.out.println("C"); continue outer; } System.out.println("D"); // never executed } System.out.println("E"); } //output: A B C B C E
10) Assertion
// Assertions are not guaranteed to actually run. 1. Do Not Use Assertions to Validate Arguments to a Public Method. use Exception Mechanism to enforce them. 2. Do Use Assertions to Validate Arguments to a Private Method 3. Do Not Use Assertions to Validate Command-Line Arguments, use Exception Mechanism to enforce them. 4. Do Use Assertions, Even in Public Methods, to Check for Cases You Know are Never, Ever Supposed to Happen. 5. Do Not Use Assert Expressions that Can Cause Side Effects!
6> Strings, I/O, Formatting, and Parsing
1) Strings Are Immutable Objects
@Test public void immutableTest() { String s = new String("Hello"); String s2 = s; s2 = s2.concat(" World"); // Will return a new Object, instead of appending on the original str assertEquals("Hello", s); } @Test public void immutableTest2() { String s = new String("Hello"); s.toUpperCase(); // A new object will be returned assertEquals("Hello", s); }
2) StringBuffer & StringBuilder
StringBuffer is thread safe, whereas StringBuilder is NOT.
3) File Navigation and I/O
* File: Isn't used to actually read or write data. When you make a new instance of File, you're NOT yet making an actual file, you're just creating a filename.
* Stream classes are used to read/write bytes, and Reader & Writers are used to read and write characters.
boolean exists(); // Return true is it can find the actual file on DISK. boolean createNewFile();// Create a new file if it doesn't exist.
@Test public void ioTest() { char[] in = new char[128]; StringBuilder sb = new StringBuilder(); File file = new File("src/test/resources/ioTest.txt"); FileWriter writer = null; FileReader reader = null; try { writer = new FileWriter(file); writer.write("Hello, world"); writer.flush(); writer.close(); reader = new FileReader(file); int c = 0; while (-1 != (c = reader.read(in))) { sb.append(in, 0, c); } } catch (IOException e) { e.printStackTrace(); } finally { if (null != writer) IOUtils.closeQuietly(writer); if (null != reader) IOUtils.closeQuietly(reader); } assertEquals("Hello, world", sb.toString()); }4) java.io.Console
* It's possible for your Java program to be running in an env that doesn't have access to a console object, so be sure that your invocation of System.console() actual returns a valid console ref and not null.
@Test public void consoleIOTest() { Console console = System.console(); char[] pwd = console.readPassword("%s", "PWD: "); console.format("%s", pwd); }5) Serialization: ObjectInputStream & ObjectOutputStream /* Stream means it is byte based */
* Object Graphs: In Java, it wouldn't make any sense to save the actual value of a reference variable, such as: "0X234E", its value is useless in another JVM.
* If a class is Serializable, then all its properties should also be Serializable, except those who are marked as "transient".
@Test public void objectOutputStreamTest() throws ClassNotFoundException { ObjectOutputStream oos = null; ObjectInputStream ooi = null; try { oos = new ObjectOutputStream(new FileOutputStream( "src/test/resources/dog.ser")); oos.writeObject(new Dog(new Collar("Yellow"), "Woofee", 12)); oos.close(); ooi = new ObjectInputStream(new FileInputStream( "src/test/resources/dog.ser")); Dog d = (Dog) ooi.readObject(); ooi.close(); assertEquals("Woofee", d.name); assertEquals(12, d.age); assertNull(d.collar); // transient prop will be give its default value, 0 for int, false for boolean, null for reference, etc. } catch (IOException e) { e.printStackTrace(); } finally { IOUtils.closeQuietly(oos); } } static class Dog implements Serializable { public Dog(Collar collar, String name, int age) { this.collar = collar; this.name = name; this.age = age; } transient Collar collar; // If it is not "transient", checked exception "java.io.NotSerializableException" will be thrown. String name; int age; } static class Collar { String color; public Collar(String color) { this.color = color; } }
* Serializable class's constructor is NOT invoked during the course of deserialization, but its parent's non-args constructor will be invoked not implement Serializable.
@Test public void objectOutputStreamTest() throws ClassNotFoundException { ObjectOutputStream oos = null; ObjectInputStream ooi = null; try { oos = new ObjectOutputStream(new FileOutputStream( "src/test/resources/dog.ser")); oos.writeObject(new Dog("Woofee", 12)); oos.close(); ooi = new ObjectInputStream(new FileInputStream( "src/test/resources/dog.ser")); Dog d = (Dog) ooi.readObject(); ooi.close(); assertEquals("Doggy", d.name); assertEquals(12, d.age); } catch (IOException e) { e.printStackTrace(); } finally { IOUtils.closeQuietly(oos); } } static class Animal { String name; public Animal() { // Invoked when Dog are being deserialized. name = "Doggy"; } // If we do not have a no-args constructor, checked exception "java.io.InvalidClassException" will be thrown. public Animal(String name) { this.name = name; } } static class Dog extends Animal implements Serializable { public Dog(String name, int age) { super(name); this.age = age; } int age; }
* Serializable & Inheritence: 1) If super implements Serializable, all its subclasses are Serializable too, because they implements Serializable implicitly. 2) What happens if a superclass is not marked Serializable, but the subclass is? - See example above.
* If you serialize a collection or an array, every element in it must be serializable!
@Test(expected = java.io.NotSerializableException.class) public void serTest() throws FileNotFoundException, IOException { ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream( "src/test/resources/b.ser")); oos.writeObject(new B(Lists.newArrayList(new A(), new A()))); oos.close(); } finally { IOUtils.closeQuietly(oos); } } static class A { } static class B implements Serializable { List values; public B(List values) { this.values = values; } }
* Serialization Is NOT for Statics. Static variables are NEVER saved as part of the object's state.
4) Dates, Numbers, and Currency
* Calendar.roll() & Calendar.add()
@Test public void addTest() { Calendar c = Calendar.getInstance(); System.out.println(c.getTime()); c.roll(Calendar.MONTH, 10); System.out.println(c.getTime()); c.add(Calendar.MONTH, 3); System.out.println(c.getTime()); } // Output: Mon Dec 29 17:23:11 CST 2014 Wed Oct 29 17:23:11 CST 2014 Thu Jan 29 17:23:11 CST 2015
* DateFormat & NumberFormat: Can both have their locales set ONLY at the time of instantiation.
@Test public void dateFormatTest() throws ParseException { Date d = Calendar.getInstance().getTime(); DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM); System.out.println(formatter.format(d)); d = formatter.parse("Dec 29, 2014"); System.out.println(d); } //output: Dec 29, 2014 Mon Dec 29 00:00:00 CST 2014 // Time information are missing
@Test public void formatTest() { float f1 = 123.4567f; System.out.println(NumberFormat.getInstance(Locale.FRENCH).format(f1)); System.out.println(NumberFormat.getInstance(Locale.CHINESE).format(f1)); System.out.println(NumberFormat.getCurrencyInstance(Locale.FRENCH) .format(f1)); System.out.println(NumberFormat.getCurrencyInstance(Locale.CHINESE) .format(f1)); }