/**
Sandeep Desai s_desai@hotmail.com http://www.thedesai.net
 
Fundamentals.java
  Show all the basic features of Java such as using scalars,
  arrays, control structures, strings, assert
  You can print this program and read it from top to bottom
 
Book Reference:
    Thinking in Java 3rd Ed
    Sun Certified Java Programmer by Kathy Sierra and Bert Bates
 
To run this program download the J2SDK 1.4.2 or later from java.sun.com
  cd \j2sdk1.4.2_05\bin
  javac Fundamentals.java
  set classpath=.
  java Fundamentals
 
 
restrictive  -> less
   private <default> protected public
 

valid identifiers (variable names) start with letters can have $ _ and digits
transient volatile for variables only
&& || only work with booleans
& | ^ works with int and boolean
Watch for variables with public access
byte b = (byte) 9 + 500; // precision loss error adding byte to int
Note difference between array.length and String.length()
instanceOf is not the same as instanceof
An assignment statement which looks like a comparison if( a=true)...
if System.exit() in try-catch-finally blocks then finally not executed
Uninitialized variable references with no path of proper initialization.
-0.0 == 0.0 is true.
continue must be in a loop( for, do , while ). not in case constructs.
Forward references to variables gives compiler error.
Primitive array types of different types can never be assigned to each other
== gives compiler error if the operands are cast-incompatible.
compiler errors for statement after break or return as unreachable
protected void finalize() throws Throwable
char promoted to int but int not promoted to char
Compiler should see path where final variable initialized
    (similar to local variable usage)
String s, StringBuffer sb; if (s==sb) compile time error
if (true ^ false) compiles
static methods can be protected
String, StringBuffer, System, Math, Wrapper classes are final
String, Wrappers immutable
Math not object so not immutable
~3 == -4
loop: int x=0; for(..) if () break loop; // compilation error
 
*/

// optional but has to be first line, namespace to
// resolve conflicts java converts . to directories
//package foo;
// use internet domain in reverse to guarantee uniqueness
// package com.mydomain.test

/**
Reserved keywords
 abstract boolean break byte case catch char class const continue
 default do double else extends final finally float for goto if
 implements import instanceof int interface long native new package
 private protected public return short static strictfp super switch
 syncrhonized this throw throws transient try void volatile
 while assert
 
 Note const and goto unused reserved keywords
*/

/**
 Note assignment left to right
 x = 0; a[y] = ++y; // update a[0] and not a[1]
 Operator precedence
 Mnemonic Operator Type           Operators
 Ulcer    Unary                   + - ++ --
 Addicts  Arithmetic and Shift    * / % + - << >>
 Really   Relational              > < <= >= == !=
 Like     Logical and bitwise     && || & | ^
 C        Conditional (ternary)   a > b ? c : d
 A lot    Assignment              = += *= %= /=
*/


// All the comments below are picked up the javadoc tool and are used
// for generating documentation, it generates
// cross-referenced HTML pages
// All the @ tags tell javadoc markers

/**
 * Javadoc is a way to document code
 * Embedd <em>html</em>
 * @author author info
 * @see classname
 * @see fully-qualified-classname#method-name
 * @since
 * @version
 * @throws class-name descriptions exceptions thrown by class or method
 * @deprecated cause Java compiler warnings that this class or method may
 *     be removed
 * {@docRoot}
 * {@inheritDoc}
 * method specific javadoc are @throws, @deprecated @param and @return
 * @param parameter-name description
 * @return description
 **/
 
public class Fundamentals  {

  // public static means a function accessible from anywhere (global function)
  // narrow to widest byte short int long float double
 
  public static void primitives() {
    // Primitive data types all data types are signed,
    // no unsigned data type except char
    boolean ab1; // Initialize to false can be true or false
    boolean ab2 = true;
    boolean ab3, ab4;
    char ac = 'a'; // 16-bit Unicode range 0 to 2^16-1
    char ac2 = '\uaaaf'; // Unicode hex 32-bit character
    byte ab = 2; // 8-bit range -128 to +128
    ab  = (byte)257; // ab becomes 1 as overflow is 257 % 256 (range of byte)
    short as1 = 5; // 16-bit range 2^15-1 +2^15+1 (-32768 to 32767)
    short as2 = 6;
    // without typecast compilation error about loss of precision
    short as3 = (short) (as1 + as2);
    as2 += as1; // OK
    int ai1 = 1; // range -2^31 to +2^31 (-2147483648 to 214783467)
    int ai2; // Initialized to zero
    int ai3 = 0x2f; // Hexadecimal (lowercase)
    int ai4 = 0X2F; // Hexadecimal (uppercase)
    int ai5 = 0177; // Octal (leading zero)
    int ai6 = 'c'; // Valid
    int ai7 = ai3 + ai4; // No compilation error for overflow
    long al = 2L; // 64-bit range -2^63 to +2^63-1
    float af = 0.5f; // 32-bit
    // Will not compile as all fractions are double by default
    //float af2 = 0.3;
    double ad = 47e47d; // 47^47
    double ae = 10e3d; // 10000
    final int fi = 2; // Constant value of f cannot be changed
    //ai7 = fi++; // error cannot increment final
 
 
    int b = -2; // Negative twos complement, flip all bits and add 1

    // + - * / % (modulus)
    ai1 = 2 + 2; ai1 = 4 * 2;
    ai1 += 2; // same as ai1 = ai1 + 2;
    int x = 17 % 4; // Result is 1 which is remainder
    x = -10 % 4; // Result is -2 which is remainder
    x = 10 % -4; // Result is 2 which is remainder
    ++x; // add 1 to x
    --x; // subtract 1 from x
    x = 1;
    x = x++; // still 1 execution left to right
    int y = x++; // assign first and then increment
 
    // bitwise operators work on boolean and int
    // & bitwise and
    // | bitwise or
    // ^ bitwise XOR  (true if bits are different else false)
    //       1 ^ 1 is 0 and 1 ^ 0 is 1
    // ~ bitwise negation
    // << bitwise left shift (same as mulitply by 2 to power of shift)
    // >> bitwise right shift (same as divide by 2 to power of shift)
    // >>> unsigned right shift (zero filled right shift)
    // Negative number are two complement -2 will be ~2 + 1
    System.out.println("Hex of -2=" + Integer.toHexString(-2));
    ai1 = 1;
    ai1 = ai1 << 1; // left shift by 1 result is 2 (always add 0 to right)
    ai1 = ai1 >> 33; // is ai1 >> 1 as Java does 33 % 32
    ai1 = ai1 >> 32; // is do nothing
    ai1 = 8; // 01000
    ai2 = ai1 >> 2; // result if 2 (0010) (same as ai2 = ai1 / (2^2)
    ai1 = 0x80000000; // 1 followed by 31 0 hex values of Integer.MIN_INTEGER
    ai2 = ai1 << 1; // result 0 as left shift drops the first 1 (does not wrap)
    ai1 = -1;
    ai2 = ai1 >> 1; // Number remains negative as 1 is shifted in from left
    ai1 = -1;
    ai2 = ai1 >>> 1; // Number turns positive as we shift in 0 from left
    System.out.println("-1 >>> 1=" + ai2); // 2147483647
    ai2 = ai1 >> 34; // becomes ai2 >> 2 (34 % 32)
    ai2 = ai1 >> 32; // value will not change
    ai1 = 1;
    ai1 = ai1 << 31;
    ai1 = ai1 >> 31;
    System.out.println(" 31 shift  " + ai1); // -1
    ai1 = 5;
    System.out.println("bitwise negation ~5=" + ~ai1); // -6
    ai2 = 3;
    // ternary operator
    ai1 = (ai2 == 3) ? 4 : 5; // if true set ai1 to 4 else 5
    ai1 = (int) 4.3; // ai1 will be 4
 
    ai1 = Integer.MIN_VALUE;
    int bi1 = -ai1; // value is Integer.MIN_VALUE because of overflow
 
    long l = 130L;
    // result is -126 as left most bits beyond 8th bit are trimmed
    short s = (short) l;

    long al5 = ai1; // implicit cast widening
    // explicit cast required because of possible loss of precision
    ai1 = (int) al5;
 
   //byte b = (byte) 9 + 500; // compile error
    b = (byte)( 9 + 500); // OK
 
    int c = 0;
    try { int d = 3 / c; }
    catch (ArithmeticException e)
    { System.out.println("Runtime exception " + e); }
    try { int d = 3 % c; }
    catch (ArithmeticException e) {  }
    float afz = 3f / 0; // No exception
 
    // Note && is short circuited so if first part is false,
    //    it does not evaulate 3/0
    // hence no runtime error
    boolean b5 = ((3 < 2) && (1 < (3 / 0)));
    // since first part true don't evaluate second part
    b5 = ((3 > 2) || (1 < (3 / 0)));
 
    // Note here both b7 and b8 evaluated
    //divide by zero exception thrown
    try { boolean b9 = true | (1 < 3/ 0); }
    catch (ArithmeticException e)
    { System.out.println("/ by zero because of |");}
 
    // logical operators && || !
    boolean b2 = ai1 > 0 && ai1 < 5;
 
    // b2 = ~b2; //compilation fails
    b2 =!b2; // runs
  }

  // Java checks that an array index is in range, if not it reports an error
  // Array is an instanceof Object
  public static void arrays() { // void means returns nothing
    // Array of 3 elements with all elements initialized to zero
    int[] afoo1 = new int[3];
    Object o = afoo1; // Array is an object
    int [] a,b; // both a and b arrays
    int c[],d; // a[] array and b is int
    // Array of 2 elements afoo2.length returns the length of an array
    int[] afoo2 = { 3, 5 };
    // ****  int[2] = {4, 5} compilation error
    // Java will report index out of range error (throw exception)
    //afoo2[3] = 1;
    int[] bref = afoo1; // bref points to afoo1
    int[][] a1 = { { 1, 2, 3}, {4, 5, 6} };  // 2 Dimensional array
    short[] ashort3;
    //ashort3 = afoo1; // compilatin error incompatible types int[] and short[]
    afoo2[0] = 4;
    // class Car {} class Honda extends Car
    // Honda[] h; Car[] c = h; // OK
    // h = c; // compile error
    if (afoo2 instanceof Object) System.out.println("int[] instanceof object");
    // afoo2.length is array length
    System.out.println("afoo2 length " + afoo2.length);
    int p[] = { 4,5};
    int q = 1;
    p[q] = q = 0;
    // p[1] = 0, q = 0
    // evaluated left to right
    int[] ia = null;
    char[] ca = null;
    // Cannot cast primitive array from type to another
    //ia = (int[]) ca; // will not compile
  }

/**
String is not a primitive datatype it is a full fledged Java Object
String is immutable, once set cannot be modified, have to create
  new String objects
String class is final cannot be overriden
JVM tries to reuse String reference if the String data is same,
  hence String immutable and class final
Strings stored in String constant pool so that when new String
  created Java checks in the String constant pool and reusesthe String

String("abc")
String(String orig)
String(StringBuffer)
String(char[] values)
 contentEquals(StringBuffer sb)
 toLowerCase() // will return the same string if no modification required
 boolean endsWith(String suffix)
 equalsIgnoreCase(String anotherString)
 indexOf(char) indexOf(char ch, int fromIndex)
 indexOf(String str) indexOf(String str, int fromIndex)
 lastIndexOf
 startsWith(String str) startsWith(String str, int offset)
 substring(int startIndex)
 substring(int startIndex, int endIndex) // endIndex count 1 from start
 trim()
 static valueOf() all primitive types
 static valueOf(char[] ch)
 static valueOf(char[] ch, int start, int end)

StringBuffer final does not override equals or hashCode
   methods are syncrhonized
StringBuffer(String s)
 append() // all primitive data types, String, StringBuffer, Object
 delete(int start, int end)
 insert(int offset,...) like append
 delete()
 indexOf(String str)
 indexOf(String str, int fromIndex)
 lastIndexOf(String str)
 lastIndexOf(String str, int fromIndex) // search backwards fromIndex
 replace(int start, int end, String str)
 setLength(int length) // truncate if less else fill with '\u0000'
 substring(int start)
 substring(int start, int end)
*/
  public static void strings() {
    String sa = "Hello"; // String is not a primitive data type
    String sb = "Hello"; // sa == sb
    if (sa == sb) { } // true as Strings are stored in
    sa = new String("Hello");
    sb = new String("Hello");
    if (sa == sb) {} // false because of new
    sb = sa;
    sb = sa + " World World"; // concat string
    int ai = 10;
    // Automatic Integer to String coversion
    sb = sa + ai + 4; // Hello World World104
    sb = sa + (ai + 4); //  Hello World World14
    sb = ai + 4 + sa; // 14HelloWorld
    // Not above + creates a new String so sa is not modified
    sb = sb.trim(); // trim white space
    String s1 = "abc";
    // constructs new string internally and returns reference
    s1 = s1.concat("def");
    // The next two statements create 3 string objects
    s1 = new String("abc");
    s1 = s1 + sb;
    //****** Imutability examples
    s1.concat("ghi"); // Does not modify s1
    s1.toUpperCase(); // Does not modify s1
    s1 = s1.toUpperCase();
    s1 += "z"; // same as concat
    //b.compareTo("Hello World"); // used for sorting
    boolean b = sb.equals("Hello World World");
    b = sb.equalsIgnoreCase("hello world world"); // returns true
    char c = sb.charAt(4); // returns 'o'
    b = sb.endsWith("World");
    int index = sb.indexOf("World"); // returns 6
    String aa = "one two one two";
    int lastIndex = sb.lastIndexOf("one", 10); // searches backward from index 10
    // index = sb.lastIndexOf("World", startIndex);
    // ***** String has length() method and Array has length attribute
    int length = sb.length(); // 17
    b = sb.matches("^Hello.*"); // regular expression match returns true
    // ([{\^$|)?*+. regular expression metacharacters
    sb.replaceAll("^Hell.?", "Ola"); //  ???? how does this work
    String[] sp = sb.split(" "); // split string based on regular expression
    String lowerCase = sb.toLowerCase();
    String upperCase = sb.toUpperCase();
    sb = sb.trim(); // trim whitespaces
    // convert int to string, also takes float, decimal etc
    String str = String.valueOf(5);
    sa = "abcdef";
    sa = sa.replace('b', 'd');
    sa = "abcdef";
    sa = sa.substring(1); // begin -> "bcdef"
    sa = "abcdef";
    // Note end not zero based
    sa = sa.substring(1, 3); // begin, end returns "bc"
    System.out.println("After substring sa=" + sa);
 
    // StringBuffer not immutable
    StringBuffer sbuf = new StringBuffer("hello");
    sbuf.append(" ").append("world"); // can chain methods because of mutability
    sbuf.append(3); // append takes boolean, char, double, float, int long
    sbuf.insert(6,"to "); // offset, string -> "hello to world3"
    System.out.println("sbuf.insert=" + sbuf.toString());
    sbuf = new StringBuffer("abc");
    sbuf.reverse();
 
    String s = "Hello,World";
    java.util.StringTokenizer st = new java.util.StringTokenizer(s, ",");
    while (st.hasMoreTokens()) { String token = st.nextToken(); }
  }
 
/**
Math class is final
Math class has all static methods
0.0 == -0.0
-1.0/0.0 == Infinity

int Math.round(float)
double Math.random() between >=0 and < 1
long Math.round(double) // only method to return int
Math.floor() and Math.ceil() return type double

All comparisons involving NaN and a non-Nan always result in false.
Default type of a numeric literal with a decimal point is double.
integer (and long ) operations / and % can throw ArithmeticException
 while float / and % will never, even in case of division by zero.

double abs(double a)
float   abs(float a)
int     abs(int a)
long  abs(long a)
double acos(double a) // Returns the arc cosine of an angle, in the range of -pi/2 through pi/2.
double asin(double a)
double atan(double a)
double atan2(double y, double x) // Converts rectangular coordinates (x, y) to polar (r, theta).
double ceil(double a) // Returns the smallest (closest to negative infinity) double value that is
    // not less than the argument and is equal to a mathematical integer.
double cos(double a) // Returns the trigonometric cosine of an angle.
* double exp(double a) Returns Euler's number e raised to the power of a double value.
double floor(double a) // Returns the largest (closest to positive infinity)
   // double value that is not
   // greater than the argument and is equal to a mathematical integer.
double IEEEremainder(double f1, double f2) // Computes the remainder operation on two arguments as
   // prescribed by the IEEE 754 standard.
double log(double a) // Returns the natural logarithm (base e) of a double value.
double max(double a, double b) takes float, long, int
double min(double a, double b) takes float long int
double pow(double a, double b)
double random() // >= 0 and < 1
double rint(double a) // Returns the double value that is closest in value to
   // the argument and is equal to a mathematical integer.
long  round(double a) // Returns the closest long to the argument.
int   round(float a) // Returns the closest int to the argument.
double sin(double a) // Returns the trigonometric sine of an angle.
double sqrt(double a) // Returns the correctly rounded positive square root of a double value.
double tan(double a) // Returns the trigonometric tangent of an angle.
double toDegrees(double angrad) // Converts an angle measured in radians to an
      // approximately equivalent angle measured in degrees.
double toRadians(double angdeg) // Converts an angle measured in degrees to an
      // approximately equivalent angle measured in radians.
*/
  public static void math() {
    //
    double pi = Math.PI;
    double e = Math.E;
    float p_i = Float.POSITIVE_INFINITY; // e.g result of 16d / 0.0
    float n_i = Float.NEGATIVE_INFINITY;// e.g result of 16d / -0.0
    double notanum = Double.NaN; // 0.0d /0.0
    if (notanum != notanum) {} // not equal
    if (Double.isNaN(notanum)) {} // true
    if (Double.isNaN(Math.sqrt(n_i))) {} // true
    if (Double.isNaN(Math.sqrt(-16d))) {} // true
 
    int x = Math.abs(-99); // 99 takes long, float, double
    x = Math.abs(-0); // 0 takes long, float, double
    // still returns Integer.MIN_VALUE as positive number does not fit
    // 0x80000000 = -2147483648
    x = Math.abs(Integer.MIN_VALUE);
    System.out.println("abs(Integer.MIN_VALUE)=" + x);
    // ceil and floor take double only
    double d = Math.ceil(3.1); // returns double as 4.0
    d = Math.ceil(-3.1); // returns double as -3.0
    d = Math.floor(3.1); // returns double as 3.0
    d = Math.floor(-3.1); // returns double as -4.0
    // Math.round returns int or long
    long al = Math.round(1.6); // 2 adds 0.5 and does a truncate
    al = Math.round(-1.5); // -1 adds 0.5 and does a truncate
    al = Math.round(1.5); // 2 takes float and double
    al = Math.round(1.4); // 1
    x = Math.max(1, -1); // can handle int, long, float, double
    x = Math.min(1, -1); // can handle int, long, float, double
    double r = Math.random(); // r >= 0.0 &&  r < 1
    r = Math.sin(Math.toRadians(90.0)); // takes double as parameter
    r = Math.cos(Math.toRadians(90.0)); // takes double as parameter
    // cos() tan()
    r = Math.toDegrees(Math.PI * 2.0); // 360.0 takes double returns double
    // 6.283185 (Math.PI*2) takes double returns double
    r = Math.toRadians(360.9);
    r =  Math.sqrt(9); // 3 takes double returns double
  }
 
/**
All primitive datatypes have wrapper objects for providing addtional functionality
All wrapers immutable and final
void, Void // can be instantiated
char Character,
int Integer extends Number
long Long extends Number
float Float extends Number
double Double extends Number
byte Byte extends Number
short Short extends Number

create using new or valueOf

abstract class Number has byteValue(), shortValue() etc

string to number can throw runtime NumberFormatException

Character does not have any of the below

// All Wrappers
toString()
static String toString(<primitive>) // convert to primitive
static Wrapper valueOf(String s)
static <primitive> parseXXX(String s)


// only Integer and Long
static String toHexString(int i)
static String toBinaryString(int i)
static String toOctalString(int i)
static int/long decode(String s) can handle octal, hex etc
static Integer/Long valueOf(String s, radix)
static int Integer.parseInt(String s, int radix)

// only Integer
static Integer Integer.getInteger(String nm) // reads system property

Long a = new Long(10); int b = new Integer(10);
if (a.equals(b) {} // false
 */
  public static void wrappers() {
    Character c = new Character('c'); // only one constructor
    Boolean bw = new Boolean(true); // takes
    bw = new Boolean("TrUe"); // case insensitive String true or false
    //if (bw) {} // won't compile
    Integer iw = Integer.decode("5"); // String to integer
    iw = Integer.valueOf("101");
    iw = new Integer("42");
    // valueOf and parseXXX take radix valueOf
    // returns Wrapper and parseXXX primitive
    iw = Integer.valueOf("101", 2); // in binary
    // can throw NumberFormatException (RuntimeException)
    int ai = Integer.parseInt("123");
    Float fw = new Float("3.2f");
    String s = Integer.toString(254, 16); // int to hex string
    s = Integer.toOctalString(254); // toXXXString Hex,Octal,Binary
    s = fw.toString(); // All wrappers implement toString()
    s = Float.toString(3.2f);
    ai = iw.intValue(); // xxxValue Wrapper conversion to primitive
    byte ab = iw.byteValue();
    // equals checks if same type e.g
    iw = new Integer(42);
    // Short sw = new Short(42); // will not compile as 42 is int
    Short sw = new Short((short)42);
    if (iw.equals(sw)) {} // false
    // Immutable arbitrary-precision integers
    java.math.BigInteger bi = new java.math.BigInteger("123448273592");
    java.math.BigDecimal bd = new java.math.BigDecimal("123.56728347");
  }
 
  public static void wrapperArray() {
   Integer[] ss = new Integer[3];
   Integer[] s2 = { new Integer(1), new Integer(2) };
   Integer[] s3 = new Integer[] { new Integer(1), new Integer(2) };
 
    Integer[][] a;
    a = new Integer[2][];
    a[0] = new Integer[2];
    a[0][0] = new Integer(1);
 }
 
/**
local variables have to be initialized before use
int x;
int k=1;
if () x=1; else x=2; ++x; // OK
if () x=1; if () x=2; ++x; // compiler error
switch (k) { case 0: default: x =2; } ++x; //OK

for (int i=0,j=0; i < 5; ++i) {} // OK
int j=0; for (int i=0,j=0; i < 5; ++i) {} // Compiler error j declared twice
 */
  public static void controls() {
    int i = 0;
    int j = 0;
    if (i == 0) { }
    else {  }
 
    if (i == 0) {  }
    else if (i == 1) {  }
    else { }
 
    if (i == 0 && j == 0) { }
    // && is logical and || is logical
    if (!(i == 0)) {  }
    // ! is negation
    if (i != 0) { }
    if (i != 0)
      ;
    else { }
    // if (i = 1) {} will not compile
    boolean b = false;
    // Not = insteadof == this will compile and run OK
    // requirement is that expression in () should evaluate to boolean
    if (b = true)  { }
    // ternary operator short cut way of writing an if
    int r = (i == 0? i * 3: i * 5);
    // while (boolean expression) can't do while (int x = 0) {}
    while (i < 3) { ++i; }
 
    do { --i;  } while (i > 0);
    do { System.out.println("do-while executed once"); } while (false);
 
    // i value never reaches 3 because of break
    // break must be in loop or switch else compile error
    r = 0;
    for (int k = 0,z = 0; k < 3; ++k,z++) {
      if (k == 2)
        break;
      // break out of loop
      ++r;
    }
    for (int k = 0; k < 1; System.out.println("for iteration")) {
      ++k;
    }
//    // Note continue must be in loop else compile error
    for (i = 0; i < 3; i += 2) {
      if (i == 2)
        continue;
      // skip
      ++r;
    }
    // we are naming these loops here
    outerloop:
    for (i = 0; i < 2; ++i) {
      innerloop:
      for (j = 0; j < 2 ; ++j) {
        if (i == 1 && j == 1)
          break outerloop;
        // breaks out of both for loops
        if (j == 0)
          continue outerloop;
      }
    }
    // will reach here on break outerloop
    // will run 3 times
    for (i = 0; i < 3 ; ++i) {
      here:
      if (i == 1)
        break here;
    }
    r = 0;
    final int x = 2;
 
    /**
     * switch takes int, short, byte, char
     * case has to have a final compile time constant
     * case cannot have duplicates
     * if switch has byte, case values should be less than 128
     *    else compile time error
     */
    switch (r) {
      // if break not specified values will be 7 as code
      // is executed till break found
      case 0: r = 5; break;
      case 1: r = 7;
        //case 1: r = 20; break; // cannot repeat case
      default: --r; break;
        // default can be in the middle or top or end also
      case x: r = 9; break;
      case x + 7: r = 9; break;
      case 'a': r = 7;
    }
    byte by = 5;
    switch (by)    {
      case 4:
      case 'A': break;
    }
    String s = null;
    // short circuited expression since s != null s.length() is not evaluated
    if (s != null && s.length() > 2) {
      // 'A' OK as it fits in byte
      // short circuited expression since s != null s.length() is not evaluated
    }
  }

/**
assertions disabled by default
compile javac -source 1.4 foo.java
runtime assert disabled by default
Can also be programatically enabled or disabled using ClassLoader
java -ea foo
-da -disableassertions -ea -enableassertions
-dsa -disablesystemassertions -esa
java -ea -da:com.foo.bar blah
disable assertion for com.foo.bar package and subpackages
java -ea -da:com.foo... blah

assert (true boolean expression) if false throw AssertionError
can be any expression that returns value after : (not allowed void)
Assert best practices
  use in private methods not in public
  OK to put assert postconditions at end of public method
  do not use in switch default
  expresion after : should not cause side effects
  sometimes OK to throw AssertionError explicitly
  AssertionError(all primitivet types)
  does not take String as constructor
 */
  private static void assertCheck(int n) {
    assert (n >= 0) : "Negative number => " + n;
    assert (n <= 10);
    boolean b = n <= 5;
    assert b;
    assert b: n++; // bad causing side effect
    //assert (n <= 15) : foovoid(); will not compile as foo returns void
  }
 
  static void foovoid() {}
 
  // required for passing to inner class also in Thread
  // final can be added or removed for overridden methods
  // parameters to method are pass by value, so modification
  //     inside method do not affect caller
  // Value of caller not changed only local copy changed
  public static void foo1(final int x) { }
  public static void foo2(int x) { x=5; }
  // caller will see the appended value
  public static void foo3(StringBuffer s) { s.append("s"); }
  int size = 7;
  // we are shadowing instance variable with local variable
  // note instance size will not be modified
  public static void foo4(int size) { size = 8; }
 
  // method return types
 
  static Object ret1() { int[] x = new int[1]; return x; }
  void ret2() { /* return "blah"; // compile error */ }
  class foo {} class bar extends foo {}
  foo ret3() { return new bar(); }  // will compile OK
 
  // cannot make static -> class, constructor interface, inner classes,
  // inner class methods, local variables
 
  transient int x; // do not serialize
  volatile int y; // sync private copy in thread with master copy
 
  // Local variables -> final
  // Variables non local -> final public protected private static transient volatile
  // Methods final public protected private abstract
  // Concrete Methods synchronized strictfp native static
 
  public static void methods() {
    int x = 1;
    foo1(x); // x will remain 1 after call
    foo2(x);
    System.out.println(x);
    StringBuffer s1 = new StringBuffer("Hello");
    foo3(s1); // contents of s1 can be modifed
  }

/**
new always allocates memory on the heap
Java uses Garbage collection no need to do free
Garbage Collecter varies by JVM implementation
May use mark and sweep or reference counting
Object is marked for garbage collection when no live thread
   has reference to the object
Each Java app has one or more threads
Note that until application exits main() thread is running
finalize() may never be called
finalize() method only called once
finalize() exceptions ignored and garbage collection canceled
 */
  public static void memory() {
    System.gc(); // hint to JVM to run garbage collector. May or maynot run
    // Ways to make object eligible for garbage collection
    String s1 = new String("s1");
    s1 = null; // s1 now marked for garbage collection
    s1 = new String("s1");
    String s2 = new String("s2");
    s1 = s1; // s2 string eligible for garbage collection
    // we can also have islands of isolation where we have objects
    // refering to each other but no objects refering to them
    // at the end of method local variables eligible for garbage collection
 
    System.out.println(  "TotalMemory (bytes)=" + Runtime.getRuntime().totalMemory()
                       + ",FreeMemory=" + Runtime.getRuntime().freeMemory());
  }
 
  public static void foo9(char c) {System.out.println("char");}
  public static void foo9(float f) {System.out.println("float");}
  public static void foo9(double d) {System.out.println("double");}
  public static void casting() {
    System.out.println("**** casting ****");
    int i = 3;
    foo9(i); // calls foo9(float)
  }
 
/**
can handle primitives and Strings concatenated by +
System.out.println("" + new Object()); // compilation error
 */
  public static void print() {
    System.out.println("*** System.out.println ***");
    // System.out.println only converts primitives
    //System.out.println("" + new Object()); // compilation error
    int i=0;
    float j=0;
    System.out.println(i + j); // prints 0.0
    // will call Object.toString()
    System.out.println(new Object());
 
    Object a = new String("A");
    Object b = new java.util.ArrayList();
    Object c = new java.util.Vector();
    System.out.println("" + b + c);
    //System.out.println(b + c + ""); // compilation will fail
  }
 
  // We can name the args variables anything
  public static void main(String[] args) {
    primitives();
    strings();
    arrays();
    wrappers();
    math();
    controls();
    methods();
    memory();
    print();
    casting();
    assertCheck(-1);
  }
}