Skip to content

Oracle Certified Associate

This is step one to become Certified Master. It is a mandatory step by the way. You will have to pass 3 exams and all of them cost around 200 euro, so a good preparation might be a money saving thing:

  • Oracle Certified Associate
  • Oracle Certified Programmer
  • Oracle Certified Master

My aim is to at least become OCP, but of course if i have that i am going to try OCM as well. But first things first : i only had half of the assessment questions right on the OCA guide so here is an extract of the study guide.

Important

I will be putting hard statement and limits in these boxes. example : There are 8 primitive types : boolean , byte , char , short , int , long , float and double .

Java building blocks

This may come in handy to know beforehand. I may repeat it later.

Liskov substitution principle

If S is a Subtype of T then objects of type T may be replaced with objects of type S without altering any of the properties of T.

Class structure

!! important "classes can have 2 kinds of members"

fields and methods

The most minimal (usable) Class could be :

small class
public class Animal { 
} 

So no implementation at all, this compiles, but so does an empty file. Even smaller will compile :

minimal class
class A{};

fields

Fields are also called variables and they maintain the state of the program and objects.

methods

Method operate on the state of objects/classes. The full declaration of a method is called the signature. This includes the modifiers (public in this case)

methods
// signature
public int numberVisitors(int month);

comments

!! important "There are 3 kinds of comments"

single-line, multi-line and javadoc.

The comments are ignored, but not completely since they do act as whitespace :

comments
// this compiles :
class/* act as whitespace*/A {}

imports

Important

the package java.lang.* is the only automatically imported package

Of course... also the current package is 'imported' but i always view that as 'already being inside' that package.

In case of conflicts the compiler is smart about most things. For instance Data is a class in both java.util and java.sql. But this will work : compiler knows which Date you mean and still can use the wildcards for the rest.

import
1
2
3
4
5
6
7
8
import java java.util.*;
import java java.util.Date;
import java java.sql.*;

...

Date d = new Date(); // without an actual usage there would also be no problem
java.sql.Date sqldate; // and you will no have use the other one like this

packages

If you don't use a package name, java still assumes some 'default' package without any name. Otherwise the directory structure follows the package name but the compiler won't create it for you, you need to follow the source structure.

If you put this in Sample.java

packages
/* comments are allowed, but the package is always the first line if used */
package org.klopt.test;

/* then all imports.. if any */

/* then classes */
public class Sample
{
    public static void main(String[] args)
    {
        System.out.println("Sample");
    }
}

It will compile, but the class is now called org.klopt.test.Sample so this will fail :

run
1
2
3
javac Sample.java
java Sample 
Error: Could not find or load main class Sample

Put it into this structure and it will work :

directory tree
>mkdir -p org/klopt/test
>mv Sample.java org/klopt/test
>javac org/klopt/test/Sample.java
>tree org/
org/
└── klopt
    └── test
        ├── Sample.class
        └── Sample.java
>java org.klopt.test.Sample
Sample

variables and types

literals

K.. here are some new ones for me..

Important

Just like 0x... for hexadecimal, java7 and up have the 0b.. binary format. So 0b11 is 3 !!

Important

For clarity, you can use underscore in numbers to make thousands clearer, int x = 1_000_000, sadly also 1_00_00_00.00; but NOT _100 or 100_ or 100_.00

identifiers

Important

You should stick with : [_\(A-Za-z][_\)A-Za-z0-9], but you could* use all unicode letters. Actually do NOT use $ either. !!

  • An identifier my start with a letter, _ or $.
  • After that also numbers may be used.
  • Reserved words are not allowed.

So legal are :

legal identifiers
1
2
3
4
okidentifier
$OK2Identifier
_alsoOK1d3ntifi3r
__SStillOkbutKnotsonice$

These examples are not legal:

illegal identifiers
1
2
3
4
3DPointClass // identifiers cannot begin with a number
hollywood@vine // @ is not a letter, digit, $ or _
*$coffee // * is not a letter, digit, $ or _
public // public is a reserved word

local,instance and class variables

  • local variables are local to a member function, they contain garbage if not initialized, and so won't compile. Parameters to methods are also local.
  • instance variables are members of objects, if they are not initialized they get a default value of something closest to 0.
  • class variables or static variables are also initialized to 0, these are initialized once when the class is first loaded.

member functions can be called the same as the class name!

When it has a return type (even void !!) it is NOT a constructor. Think of it as: if a constructor should return anything, it would be the class itself.

variables
1
2
3
4
public class Test {
    Test() {} // constructor
    void Test {} // Normal member function
}

initialization

Member variables can be initialized.

  • directly in the declaration
  • in one or more initialization blocks
  • in the constructor

The initialization blocks can be nested like normal code blocks (though you should keep them small). They can be intermixed with declarations, and they are executed in order. Afterwards the body of the constructor is run. So this code will assign the following to X in this order : 10, 20, 30, 40.

initialization
public class X {
    int i=10;

    { i=20; }

    X() { i = 40; } 

    { i=30; }

    public static void main(String[] a) { X x = new X(); }
}

One detail about this , you can use variable as left hand side (assign to it) before it is declared, but not the right hand side (like print it) this code fails on the println command, and not on the assignment :

prints 20
public class X {

    { System.out.println(i); } // compile ERROR
    { i=20; }                  // no error , program prints 20

    int i;                      // if you say int i=10; the output is 10
    X()

    public static void main(String[] a) { X x = new X();
        System.out.println(x.i); }
}


X.java:4: error: illegal forward reference
    { System.out.println(i); }

If you remove the second initialization block with the println, it will compile and print 20. But order still matters: if you change the declaration to int i=10; the program will print 10 !!.

So as i see it this next code :

prints 20
public class X {

    { i=20; }

    int i=10;
    static int j;
    X() { i = 30; }

    public static void main(String[] a) { 
        X x = new X();
       System.out.println(x.i); 
       System.out.println(x.j); 
    }
}

Triggers these actions :

  • load class, initialize j to 0
  • call the main function
  • create an instance of X when encountering new X
  • create a member variable called i uninitialized (random value)
  • now walk all initializers, so start with making i 20
  • assign i value 10
  • next the constructor so i becomes 30
  • now print the values: so 30 and 0

Note that even after the i=20; you still can't use it for printing. This is where it differs from local variables, where you cannot initialize them before the declaration, but you CAN use that as soon as they have a value:

error
1
2
3
4
5
6
7
8
void func() {
    k = 10; // compile ERROR

    int k;  // OK
    System.out.println(k);  // compile ERROR
    k = 11; // OK
    System.out.println(k);  // OK
} 

the compiler evaluates all possible paths

If there is a path in which a variable does not get a value but does get used, you get a compile error.

error
1
2
3
4
5
6
7
8
void func(boolean val) { 
    int k;

    if (val == true) { 
        k = 12;
    }
    System.out.println(k);  // compile ERROR (*might* not have been initialized)
} 

freeing memory

In general you just drop an object by dropping it's reference. For instance when you let it go out of scope, or setting it null, or stop referencing the object it is a member of.

!! important "There is a function called System.gc() that does NOT invoke the garbage collector"

It just suggests to the garbage collector that now might be a good time to run, the VM itself decides if it will do so !

Objects are just blobs of data on the heap without any name, you don't get it's physical address just a reference that make you access it. And once the last reference is gone it goes on the candidate list for re-use.

finalize

finalize is a function that get's called when an object is collected by the garbage collector. So that might run much later then when you release the reference, or not at all, like when you exit the program.

Important

When you exit() java VM is not going to walk all finalizers, it just quits and frees all memory !

You can however rely on the fact that it does not get called twice. For instance if the garbage collector fails to reclaim an object en retries again later, the second time it does not call finalize() again!.

Important

finalize() get's called 0 or 1 time, never more.

An example of this is when you add 'this' to a list that still remains visible outside of the object. Suddenly the object is now referenced again and the object can no longer be reclaimed.. Now when you remove the object (or the whole list) the finalizer is not called again.

Don't use finalize for closing resources or things like that, you never know if or when it's called. Better yet:

Effective java, rule 7

Avoid finalizers

arrays

Both before and after the variable name is supported.

arrays
1
2
3
4
5
int[] a = new int[10];
int b[] = new int[10];
int[] c = { 1,2,3,4,5 };
int[] d = new int[] { 1,2,3,4,5 };
int[] e = new int[5] { 1,2,3,4,5 }; // error !, no size allowed

Actually in parameter list there is a third notation, these all make an identical String array inside main :

identical
1
2
3
public static void main(String[] args){}
public static void main(String args[]){}
public static void main(String ... args){}

character arrays

These could actually works as strings if you fill each element individually.

c-style strings
1
2
3
4
char[] cstring = "hello"; // error !
char[] cstring = { 'h','e','l','l','o'}; // works

System.out.println(cstring);        // hello

object format

Arrays are also objects, so if you print them you get something like :

format
1
2
3
4
5
int[] a = new int[10];
String[] b = new String[10];

System.out.println(a);  // [I@7d4991ad
System.out.println(b);  // [Ljava.lang.String;@4aa298b7

The [ means array and this is followed by the type, I is for integer, D is for double, J is for long (not L it's use for objects) ... . If it is an object like string you get the whole type between 'L' and ';'. The last parts is not the address, but the HashCode !!.

In fact it seems that the default toString implementation from object is :

probable toString
1
2
3
public static String defaultToString(Object o) {
    return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode());
}

And indeed if you print .getClass().getName() for a String and of an array of String you get :

output
java.lang.String;
[Ljava.lang.String;

Including the trailing ;

printing

The java util Arrays class has a nice way of printing arrays, without having to loop over it:

print array as string
int[] a = { 1,3,5,98,3,5 };
System.out.println(Arrays.toString(a)); 

This will come in handy for the sorting section next.

sorting

The sort function also comes from the java.util.Arrays class :

sorting
1
2
3
4
int[] a = { 1,3,5,98,3,5 };
System.out.println(Arrays.toString(a)); 
Arrays.sort(a);
System.out.println(Arrays.toString(a)); 

searching

binary search
1
2
3
4
5
6
{
int[] a = { 1,3,5,98,3,5 };
}
System.out.println(Arrays.binarySearch(a,98)); // undetermined (-7 in this case)
Arrays.sort(a);    // binarySearch must have a sorted array
System.out.println(Arrays.binarySearch(a,98)); // 5

There is no such thing as a linear search for unsorted arrays in the Arrays class. You will have to loop yourself.

multidimensional arrays

Arrays are objects, so you can create arrays of objects which are itself arrays.

multidimensional
1
2
3
4
5
6
7
8
int[][] a;  // two dimensional
int[] b[], c[][]; // 2-dim and 3-dim, it's just adding brackets

int[][] d = { { 1,3,5} , { 98,3,5 }, {2, 4} };

System.out.println(Arrays.toString(d)); // [[I@4aa298b7, [I@7d4991ad] 
System.out.println(a.length);         // 3
System.out.println(a[2].length);         // 2

That also means that every sub-array can be any size, it's a separate array. As you can see, Arrays.toString does not go deeper and prints the object references, .. sad.. Also note that length is now a public member, and not a function.

length

length() is a method on Strings, length is a member on arrays.

In C/C++ arrays are contiguous slots in memory, so they have to be rectangular/cubic etc.. A java multidimensional array is exactly like an array of pointers to arrays in C++.

More instantiation forms :

initialization
1
2
3
4
5
int[][] = new int [3][]; // create an array of 3 empty arrays

int[0] = new int[2];
int[1] = { 1, 2, 3};    // ERROR 
int[2] = new int[] { 1, 2, 3} // works !

Printing the array is most terse using enhanced for loop :

enhanced for
1
2
3
4
5
6
7
for (int [] inner : a) {
     for (int num : inner) {
         System.out.print(num);
         System.out.print(" ");
     }
     System.out.println();
 }

operators and statements

operators

Especially the precedence is important, but here is also a breakdown to remember :

Operator example hint
Post-unary Pre-unary Other unary Multiplication Addition a++ a--++a --a ~ + - ! * / % + - a+++a becomes (a++)+a
Shifting << >> >>> binary shifts
Relational < > <= also : instanceof
Equality == != lower than < >
Logical &
Short circuit &&
Ternary ? : only 1 flavour
Assignment = += >>= also binary but lowest

Roughly, you could divide this in

  • unary: in the order : x++, ++x, !~+-
  • binary: *,+,>>,>=,==,&,&&
  • ternary: ?:
  • assignment: = += <<=

On the same level operators are evaluated left to right so !~+- is in no particular order, but the comma's mean lower levels.

Ok, after much nonsense threads i finally got an example of where postfix unary takes precedence over prefix :

postfix wins
1
2
3
4
int a =10;
int b = a+++a; // becomes (a++) + a (valid : 21)
int c = a++++a; // becomes (a++) ++a; (error)
int d = a+++++a; // becomes ((a++)++)+a (error : it says (11++)+a

In this example you don't take a+(++a) but (a++)+a ... sigh! Notation like this do not compile :

error
int a=10;
int b= ++a++; // ++a is a value, so (++a)++ says : (11)++

assignment

Important

Whenever you risk losing information, you get a compiler error !

lossy conversion is not allowed by the compiler:

assignment
1
2
3
double x = 1;   // works fine = 1.0
int y = 1.0;    // incompatible types: possible lossy conversion 
long l = 298728793; // nope, you have to add L : 298728793L 

!! important

All floating point literals are assumed to be of type double.

So this is a tricky one, because you have to use the 'f' notation for floats :

use f
1
2
3
double d = 1.1; // ok
float f = 1.1;  // ! incompatible types: possible lossy conversion
float f2 = 1.1f;    // ok;

numeric promotion

In expressions:

  • If two values are of different type, java will promote the smaller one to the larger one.
  • If one is integer and the other a floating type, the integer is promoted to floating.
  • All types smaller than int/32 bits (char,byte,short) are promoted to int even if no operand is that big.
  • After all promotions are performed, the result will have the promoted type.

Some consequences of these rules :

promotion
1
2
3
4
5
6
short s1 = 3;
short s2 = 10;
short s3 = s1 * s2;  // won't compile
int   i1 = 10;
short s4 = i1;       // just as this won't compile
short s5 = (short)(s1*s2); // casts are needed to compile

Since s1 and s2 are promoted to int, so you are now assigning a bigger type (int) to a smaller type.

casts

Important

casts are generally used to force bigger types into smaller ones. Be it int of floats into shorts or wider object types into subtypes etc.

Casting a larger type into a smaller one wraps/overflows if the high bits are set.

Important

note that overflow/underflow could be the wanted value in certain solutions !! though you should perhaps better use masking.

compound statements

Fairly straightforward : +=, -=, etc. But here is an extra advantage beside shorter notation.

automatic cast
1
2
3
4
5
6
long x=10;
int  y=5;
y = y * x; // this won't compile: y*x is long, and you assign it to int

y *= x;      // does compile because of automatic casts :
y = (int) ((long) y * x);

The compound operator performs the casts as shown in the last line.

Important

compound operators insert the casts when needed

relational operators

Weirdly these do not include the equality operators, but they DO include the instanceof operator.

instanceof

the relational operators are : <, <=, >, >= and instanceof

'a instanceof b' is true if a is an instance of b or a subclass of b or implements interface b.

Important

when comparing different types, numeric promotion is used, so 5.0 == 5 evaluates to true. "5" == 5 will not compile.

logical operators

&, | and ^ when used on numeric operands, perform bitwise and, or and xor like in C, when on boolean operands they are evaluated logical. All operands are evaluated. This in contrast with && and ||.

Important

&& and || only evaluate the right hand side if needed. boolean x = true || never_called() ; boolean y = false && never_called();

equality operators

These are use to compare :

  • two numerical operands, in which case they are promoted to the largest type
  • two boolean operands, 0 and 1 are not related to false or true !
  • two objects, in which case they just compare references, so these are in fact the same object.

To compare the content of two different references, you can override the .equals() method. By default this just does the same as == but for instance for Strings it is overridden, so :

equality operators
1
2
3
4
5
6
7
8
9
String a = "Hallo";
String b = a;
String c = new String("Hallo");
String d = "Hal" + "lo";

System.out.println(a == b); // true
System.out.println(a == c); // false
System.out.println(a.equals(c)); // true 
System.out.println(a == d); // true because of string Pool

Note that a and d are referencing the same string in the string Pool, while c was explicitly requested as a new string.

Literal strings are gathered in one string pool

This is after concatenation, so "Hell"+"o"; and "He"+"llo" will become the same entry/same pointer/same hashEntry.

statements

When you create an obvious unreachable statement the compiler will complain:

unreachable
return;
x=1;    // unreachable code

But not with runtime evaluations like this :

compiles
1
2
3
4
5
6
if (x2 < 10) {
      x2 = 11;
} else if (x2 < 3) {
      // compiles but can never be reached.
      x2 = 12;
}

or even this will get no compiler complaint (good!)

compiles
1
2
3
4
5
if (true) {
    System.out.println("Yep");
} else {
    System.out.println("Nope");
}

ternary operator

In the expression :

ternary
x ? y: z;

x must be a boolean expression, but y and z can be any type. This will work for instance for printing, but not for assignment.

boolean
System.out.println((x<5) ? "Horse" : 11); // fine
int y = (false) ? "Horse" : 11; // does NOT compile

Because there is a println(String) as well as a println(int) line 1 will work. Line 2 just will not fit, normal assignment rules apply.

Important

From java 7 and up ,only one of the operands y and z are evaluated, watch out if you depend on side-effects

switch statement

Allowed types for a switch are :

  • int and Integer
  • byte and Byte
  • short and Short
  • char and Character
  • int and Integer
  • String
  • enum values

Important

Remember the list above and note there is no boolean and no long, but there is String !!

This snippet shows that not every case is re-evaluated, it just chooses, sets the flow at that point and continues to the first break.

switch
int dayOfWeek = 5;
switch(dayOfWeek) {
    case 0:
    System.out.println("Sunday");
    default:
    System.out.println("Weekday");
    case 6:
    System.out.println("Saturday");
    break;
}

Also this show that :

Important

There is no requirement for the default to be at the end of the switch statement.

The case statements must match the type of the switch statement but you also cannot use common variables (except finals) :

match type
private int getSortOrder(String firstName, final String lastName) {

    String middleName = "Patricia";
    final String suffix = "JR";
    int id = 0;
    switch(firstName) {
        case "Test":
        return 52;
        case middleName: // DOES NOT COMPILE because not final !
        id = 5;
        break;
        case suffix:    // works !!
        id = 0;
        break;
        case lastName: // DOES NOT COMPILE because not constant !
        id = 8;
        break;
    }
} 

Note that lastName fails because it is final but not constant since it is passed to a function.

Important

case statements must be a literal, enum constant, or final constant variable.

Important

With a final constant we mean a variable that was declared final and initialized with a literal in the same statement. (So not the lastName parameter above).

Look at it as if the compiler wants to prepare the complete switch with hardcoded values. The parameter lastName would be problematic there.

for statement

There are 2 loop statements in java :

  • basic for loop (c style)
  • enhanced for loop (for-each)

basic loop

Some pitfalls:

You cannot declare a variable again as a loop variable:

similar problems
1
2
3
4
5
6
7
8
int x=0;
for(int x=1; x< 10; x++) {  // does not compile 
} 

// Just as this won't compile as well :
{
    int x=2;
} 

You can declare multiple variables in the for loop but that have to be of the same type !!

same type only
1
2
3
for(long y = 0, int x=0; x <5 && y<4; x++, y++) { // does not compile
    System.out.println(x);
}

But you CAN use them (and initialize. just not declare them).

only usage works
1
2
3
4
5
6
long y=10;
int x=10;

for(y = 0, x=0; x <5 && y<4; x++, y++) { // does compile
    System.out.println(x);
}

for-each loop

These loops are of the form

for(type element : collection) should be read as for(each) element in collection.

The right hand side (the collection) must be a java built-in array or an object hat implements java.lang.Iterable ! The left hand side must include a declaration for an instance of a variable who's types matches that of an element of the collection(right hand).

Important

Note that the left hand can't be just a variable, it must be a declaration.

When for-each loops were added in java version 1.5 they where just converted at compile time to a regular for loop. Therefore these two constructs are equivalent.

foreach
1
2
3
for(String name : names) {
    System.out.print(name + ", ");
}
same as
1
2
3
4
for(int i=0; i < names.length; i++) {
    String name = names[i];
    System.out.print(name + ", ");
}

For the objects that inherit java.lang.Iterable, the conversion is :

Iterable
1
2
3
for(int value : values) {
    System.out.print(value + ", ");
}
short for
1
2
3
4
for(java.util.Iterator<Integer> i = values.iterator(); i.hasNext(); ) {
    int value = i.next();
    System.out.print(value + ", ");
}

Notice that in both example, some part of the conversion appears inside the loop. This is probably why the left part MUST be a declaration.

Important

with a for loop you don't have access to the loop variable or index, making some constructs difficult.

For instance printing comma's between but not at the end of a list:

skip comma in standard loop
java.util.List<String> names = new java.util.ArrayList<String>();
names.add("Lisa");
names.add("Kevin");
names.add("Roger");
for(int i=0; i<names.size(); i++) {
    String name = names.get(i);
    if(i>0) {
        System.out.print(", ");
    }
    System.out.print(name);
}

This can't be done with a for-each without introducing a counter. So just use for-each loops when you cleanly want to traverse all members.

labels, break and continue

You can use labels to have more control over especially nested loops :

The structure of a loop and break is :

break loop
1
2
3
4
optionalLabel: while(booleanExpression) {
    // body
    break optionalLabel;
} 

A label has little use in a single loop like this, but only in nested loops. The label does not have to be on the same line, so this example works.

labels
int[][] myComplexArray = {{5,2,1,3},{3,9,8,9},{5,7,12,7}};
OUTER_LOOP: 
    for(int[] mySimpleArray : myComplexArray) {
    INNER_LOOP: for(int i=0; i<mySimpleArray.length; i++) {
        System.out.print(mySimpleArray[i]+"t");
        // continue; and continue INNER_LOOP; would print :
        // 5 2 1 3 ,3 9 8 9 ,5 7 12 7 ,
        // break INNER_LOOP; and break; would print
        // 5 ,3 ,5 ,
        // continue OUTER_LOOP; 
        // 5 3 5
        // break OUTER_LOOP; will quit after 1 loop : 
        // 5
    }
    System.out.print(",");
}

This example would print only the first

control usage

The break and continue are not permitted in every statement.

statement allows labels allows break allows continue
if yes no no
while yes yes yes
do while yes yes yes
for yes yes yes
switch yes yes no

Important

labels are allowed before any block statement.

So this is a legal extension to the Loop class above:

loop
public class Loop
{
    public static void main(String args[])
    {
        int[][] myComplexArray = {{5,2,1,3},{3,9,8,9},{5,7,12,7}};
        OUTER_LOOP: for(int[] mySimpleArray : myComplexArray) {
                INNER_LOOP: for(int i=0; i<mySimpleArray.length; i++) {
                     System.out.print(mySimpleArray[i]+" ");
                    break OUTER_LOOP;
                }
                System.out.print(",");
        }

        MY_LABEL: {
            System.out.println("done");
        }
    }
}

Core java api

Strings

adding/concatenation

When using + operator, if either operand is a string the result is concatenation by converting the other operand to string.

That means when evaluating the operands left to right :

result
System.out.println("a" + "b" + 3); // ab3
System.out.println(1 + 2 + "c"); // 3c

The string pool

Java uses a string pool to reuse string literals, but it does not use that when you use 'new'.

string pool
1
2
3
4
5
6
7
8
9
String n1 = "hai";
String n2 = "hai";
String n3 = new String("hai");

MY_LABEL: {
    System.out.println(System.identityHashCode(n1));
    System.out.println(System.identityHashCode(n2));
    System.out.println(System.identityHashCode(n3));
}

This print two times the same value, one time a different one. The first two are the same in the string pool, the last one is a new pointer.

pointers
1
2
3
1252169911
1252169911
2101973421

Note that using hashValue() prints the same number three times because that's simply the hash that is used to find strings in maps etc.

stringbuilder

Strings are immutable, StringBuilder is not.

Important

StringBuilder is the not-thread-safe version of StringBuffer but much more efficient because of that.

basic usage
1
2
3
4
5
6
7
// no import needed, it's in java.lang
StringBuilder sb = new StringBuilder("Start");
sb.append(" more").append(",");
sb.append(" and some more");

String s = sb.toString();
System.out.println(s);

So you build your string, and in the end convert it for usage. Also to show that append returns a reference to the same mutable object :

building
1
2
3
4
5
6
7
8
9
StringBuilder sb1,sb2;

sb1 = new StringBuilder("A");
sb2 = sb1.append("B");

sb1.append("C"):

System.out.println(s1.toString());  // ABC
System.out.println(s2.toString());  // ABC

Here is a short display of the StringBuilder functions.

functions
StringBuilder sb = new StringBuilder("abc");

// chaining :
sb.append("de").append("fg");
// this works, because println(Object x) calls String.valueOf(x) 
System.out.println(sb);             // abcdefg
System.out.println(sb.charAt(2));    // c

sb.insert(0, "_").insert(3, "++");   // at 0, at 3
System.out.println(sb);             // _ab++cdefg

int l = sb.length();
int i = sb.indexOf("de");
System.out.println(l + " and " + i); // 9 and 6

String s = sb.substring(3,5);       // from 3,upto 5
System.out.println(s);              // ++

sb.deleteCharAt(0).delete(2,4);     // at 0, from 2 upto 4
System.out.println(sb);             // abcdefg

sb.reverse();
System.out.println(sb);             // gfedcba

Array

arrays
1
2
3
4
5
int[] a = new int[10];
int b[] = new int[10];
int[] c = { 1,2,3,4,5 };
int[] d = new int[] { 1,2,3,4,5 };
int[] e = new int[5] { 1,2,3,4,5 }; // error !, no size allowed

int[] is preferable

Like : "a is of int[]" Try to shake the C habit!!

Actually in parameter list there is a third notation, these all make an identical String array inside main :

identical
1
2
3
public static void main(String[] args){}
public static void main(String args[]){}
public static void main(String ... args){}

ArrayList

This is a dynamic array. Probably the most used data structure ? Some basic usage.

Important

Always declare variables in their widest type. You can do more with the widest type !

arraylist
1
2
3
4
5
6
7
8
9
List<String> al = new ArrayList<String>();

al.add("Joop");
al.add("Klaas");
al.add("Joop");
al.add("Kees");

al.remove("Joop");  // removes only 1 entry !!
System.out.println(al); // [Klaas, Joop, Kees]

Now some caveats :

Generics only works with object

Not primitives. so List is a compile error.

add/remove
List<Integer> al = new ArrayList<Integer>();

// autoboxing makes Integers if needed
al.add(11);
al.add(12);
al.add(new Integer(13));
al.add(1);

al.remove(1); // this removes 12, at INDEX 1
System.out.println(al);
al.remove(new Integer(1)); // this will remove 1

System.out.println(al);

Converting ArrayList to an array must be done by providing an object of the wanted return type :

convert to array
List<Integer> al = new ArrayList<Integer>();

// autoboxing makes Integers if needed
al.add(11);
al.add(12);
al.add(new Integer(13));
al.add(1);

System.out.println(al);

Object[] obarr = al.toArray(); // possible, but not useable 
Integer[] arr = al.toArray(new Integer[0]);
System.out.println(arr.toString());

If you do it the other way round, the ArrayList will get references to the original so they become linked :

covert to arraylist
String[] arr = { "jan", "piet", "klaas"};

List<String> al = Arrays.asList(arr);

arr[1] = "joop";
al.set(2,"gerrit");
System.out.println(al);        // [jan, joop, gerrit]
System.out.println(Arrays.toString(arr)); // [jan, joop, gerrit]

// now you can't remove items because of the linkage
al.remove(1);   // UnsupportedOperationException

Date and Time

This has been changed for version 8, and i only handle the new formats.

Important

New Date and Time classes are from package java.time.* and start with Local[Date][Time]. These cannot be instantiated.

Important

The only units that are not just plain numbers are months and weekdays, and so these have enums called Month and DayOfWeek.

You use them with factory methods like so :

date
LocalDate now = LocalDate.now();
LocalDate then = LocalDate.of(2011,10,2);
LocalDate then2 = LocalDate.of(2011,Month.APRIL,2);
System.out.println(then2);  // 2012-04-02

// DayOfWeek is use for getting only :
DayOfWeek dow = now.getDayOfWeek();
System.out.println(dow);    // MONDAY

LocalDate later = then.plusDays(10).plusYear(1);
System.out.println(then);    // immutable: 2012-04-02
System.out.println(later);   // 2013-04-12

Besides that there are Period and Duration classes. But you cannot chain these :

Important

Durations and Periods have static member functions and can therefore not be chained.

Important

There is no point in chaining static methods because you cannot return your own 'this' object, since there isn't one.

So you need to pick a suitable factory method :

periods and durations
1
2
3
4
5
6
7
Period p = Period.ofDays(10);
Period p2 = Period.ofYears(1);
Period p3 = Period.of(1,0,7); // every year + 7 days

System.out.println(later);   // 2014-04-12
later = later.plus(p3);
System.out.println(later);   // 2015-04-19

Unix time stamp and formatting

time_t
LocalDateTime ldt = LocalDateTime.now();

long stamp = ldt.toEpochSecond(ZoneOffset.UTC); // unix time utc offset
System.out.println(stamp);

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMMM dd, yyyy, hh:mm");
DateTimeFormatter dtf2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
// both DateTimeFormatter and LocalDateTime have the .format() method :
System.out.println(ldt.format(dtf));   // October 23, 2017, 09:20
System.out.println(dtf2.format(ldt));  // Oct 23, 2017 9:20:49 AM

Parsing

Finally, parsing strings into dates used DateTimeFormatter as well :

parse date/time
1
2
3
4
5
String mydate = "2017 Nov 22 12:30:00";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy MMM dd HH:mm:ss");

LocalDateTime result = LocalDateTime.parse(mydate, dtf);
System.out.println(result);

Methods and encapsulations

Methods are built up the same :

[access modifiers] [specifier list] return_type method name ([parameter list]) [throws exceptionlist] {}

Simple way to remember is probably the main function. Which has one of each except .... the exceptions. 8)

modifiers
public static void main(String ... args) thorws InterruptedException {}

All access modifiers

Access modifiers are empty, private, protected or public.

  • If empty the access is default or 'package private'.
  • public means accessible for anyone
  • protected means accessible from with the package and for subclasses
  • private means accessible for this class only

Important

Specifiers can be a combination of static, abstract, final, synchronized, native and strictfp. Logically not all combinations are possible.

  • static : the method is not part of an instance
  • abstract : this method does not have an implementation
  • final : this method can not be overridden by a subclass
  • synchronized: the methods can be called in a threadsafe way
  • native : the method is implemented in another language, probably c
  • strictfp : method used strict (portable) floating point calculations

Only Constructors have no return type

If you make a method with the name of the class and a return type (including void), it's just a normal method."

protected access

public and private access are pretty straightforward. The first allows anything, the second nothing outside the own class. package private is also simple, everything in the same package has access.

Protected has some more caveats. It starts out as having the same access as package private but with subclasses added. First for java to find the classes you need to setup the directory structure so keep it as simple as possible :

directory
1
2
3
4
5
6
├── first
│   ├── Access.class
│   └── Access.java
├── second
│   ├── SubAccess.class
│   └── SubAccess.java

Both files need to be compiled together but i will comment them separate.

Important

The java compiler will automatically compile the other file as well if you only do javac first/Access.java

first package
package first;

import second.*;

public class Access
{
    private int x=11;
    protected int y=12;

    public static void main(String ... args) {
        SubAccess sa = new SubAccess();
        Access a = sa;

        System.out.println(a.x);    // ok
        System.out.println(sa.x); // compile error
    }
}

What we see here is that the reference type counts and not what it was created as. sa is a SubAccess type and has no access to x, a is an Access type and since we are within that class it has access to it's own members.

second package
package second;

import first.*;

public class SubAccess extends Access
{
    void function() {
        Access a = new Access();
        System.out.println(this.y); // ok
        System.out.println(a.y);    // compile error
    }
}

Here we are in a different package, so now this code can use the protected y member because it is within a subclass of Access. An access object itself can't use the y member because it is outside of the package, and outside of the Access class code.

Important

Access is granted to code within a class or package, not to an instance. Instantiating a class is completely outside the protection/privacy.

static methods

Note that since static methods are not related to an instance this is possible :

static method
1
2
3
4
5
6
7
8
9
public class Koala {
    public static int count = 0;
    public static void main(String[] args) {

        System.out.println(count);
        Koala k = null;
        System.out.println(k.count);
    }
}

There is no need whatsoever for java to check the reference, it just looks at the class and returns the static member. So this just works !

static initialization

You can also initialize static data with an anonymous section, just put static in front of it:

static initialization
private final int x;
private static final int y;

{
    x = 100;
}

static {
    y = 110;
}

Since there is no constructor involved these get called in order of appearance. And in this case (final) exactly 1 assignment has te be done.

static imports

Important

Static imports are for importing members, normal imports are for importing classes.

static import
import java.util.List;
import static java.util.Arrays.asList;

The static has to come after import and not before, but that's kinda logical since import is the 'command' or statement.

call by value

Important

All parameters to methods are call-by-value, there are copies on the stack.

This means you cannot alter the parameters themselves, only their content.

call by value
1
2
3
4
5
6
7
8
static void tryToAlter(int a, String b, StringBuilder c) {
   // no way to alter a or b, they are immutable
   a = 10; // the copy is now 10, and discarded at return
   b = "Anders"; // same here, contents will be lost on return

   // if you assign to c, the same happens, but not if you call a method
   c.append(" with some more");    // changed outside this method
}

overloading methods

Important

The access modifiers and exception list are irrelevant to overloading, and so is the return type.

Important

A method overload if it has the same name as another method but different parameters.

Note again that int[] and int ... both boil down to an integer array, but there is a small difference, this will not compile :

overloading
1
2
3
4
5
6
7
static void oload(int[] args) {
    System.out.println("int []");
}

static void oload(int ... args) {
    System.out.println("int ..."); // error: cannot declare both oload(int...) and oload(int[])
}

But you can only call the second one with oload(1,2,3). Only inside the function it's an int array. Outside you need to call the first version with :

overloading
oload(1,2,3); // only fits second version
oload(new int[] {1,2,3});   // fits both !!

So you could (ab)use the ... format to create an array :

overloading
1
2
3
int [] make_array(int ... args) {
    return args;
} 

autoboxing and integer promotion

Important

Java attempts conversion to a wider type (if needed) like short to int (promotion), or int to Integer (autoboxing) but not both at once : short to Integer.

Of course java will always match exact matches first, but with multiple variables the choice may become blurred.

  • Exact match by type is first.
  • Large primitive type conversion is tried next.
  • Autoboxing is third.
  • Varargs comes last.

Of course combinations are trickier, but this is not OCA material.. later.

Constructors

Important

A constructor is a method without return type and with the same name as it's class.

Important

If you do not create a constructor java will put a default constructor without parameters in itself.

You can view this with javap by the way:

constructors
public class Donkey{
}
disassemble
javac Donkey.java
javap Donkey.class

The second command is "The Java Class File Disassembler" and it will generated this :

result
1
2
3
4
Compiled from "Donkey.java"
public class Donkey {
   public Donkey();
}

This is more an outline of the class, for instance the Constructor has no body, you can use javap -v or -c for more elaborate listings.

It seems unimportant that java physically generates this constructor because it does nothing, but in some cases it does matter, for instance with other generated code like super() see later on ...

Constructors can be overloaded and chained, but :

Important

A constructor can call either one this() or one super() constructor but it has to be the first statement of the constructor.

So you can't call different super() and this() constructors in a row.

javabeans naming conventions

Since this is considered good practice, just use this :

naming
1
2
3
4
5
6
7
private int numEggs;    // private, lowerCamelCase, 
private boolean happy;  // 

// note the Variablename gets an uppercase when used below:
public boolean isHappy() {}; boolean getters use is<Variablename>()
public int getNumEggs() {};  other types use get<Variablename>();
public setHappy(boolean) {}; setters always use set<Variablename>();

immutable classes

In general just don't provide a setter method, but beware of returning references to internal variables or they become mutable after all :

immutable
1
2
3
4
5
private StringBuilder builder;

public StringBuilder getBuilder() { 
    return builder; // not immutable anymore
}

lambda's

Somewhat like function pointers or closures, but this is an example that shows the idea :

lambda functions
interface Calc {
    int operation(int a, int b);
}

public class Lambda
{
    static int perform(Calc c, int a, int b) {
        return c.operation(a,b);
    }

    public static void main(String ... args) {
        int result;

        result = perform( (a,b) -> { return a + b;}, 10, 11);
        System.out.println(result);
        result = perform( (a,b) -> { return a * b;}, 10, 11);
        System.out.println(result);
    }
}

The interface is needed to be able to pass the function as a parameter:

Important

An interface with one abstract method is called a 'functional interface'. Lambda's need a functional interface to work.

Important

View lambda' as an extra stackframe to sense what you can do with variables.

For instance :

  • You can use local variables and parameters but not change them.
  • Static and member variables can be used and changed.
  • You cannot redeclare a local variable inside the block.

lambda syntax

The full form with 1 parameter could be :

syntax
(Animal a) -> { return a.canHop(); }
  • Type name can be skipped.
  • Parenthesis are only needed if there are more than 1 parameter.
  • Brackets, return and ; can be skipped if there is only 1 statement

That means the shortest form of the lambda above is :

minimal
a -> a.canHop()

predicates

If you use lambda's to test simple condition, for instance to loop over a list and pick out elements on a simple check, you can use a pre-built functional interface called Predicate:

predicates
1
2
3
4
5
6
7
import java.util.function.*;

...

public interface Predicate<T> {
    boolean test(T t);
}

This is actually used by existing classes like ArrayList that makes this code work :

ArrayList uses predicates
import java.util.*;
import java.util.function.*;

...

List<String> bunnies = new ArrayList<String>();
bunnies.add("long ear");
bunnies.add("floppy");
bunnies.add("hoppy");

System.out.println(bunnies);    // [long ear, floppy, hoppy]
bunnies.removeIf(s -> s.charAt(0) != 'h');
System.out.println(bunnies);    // [hoppy]

class design

class modifiers

Top classes cannot be made private of protected, nested classes can !

Important

The only access modifiers to a top level class are public or default(absent).

Important

Nested classes can be private or protected !! You can and should view nested classes as members of the enclosing class.

all classes are Object subclasses

All classes inherit from java.lang.Object one way or the other. Either they extend a class, or the compiler adds 'extend java.lang.Object' to it. Take this code :

Object
class Sup
{
    Sup() {}
}

public class Pref extends Sup {
    Pref() {
        System.out.println("Sup");
    }

    public static void main(String args[]) {
        Pref p = new Pref();
    }
}

When using the disassembler, with the -c(ode) option you can see some of the code insertion done by the compiler :

under the hood code
1
2
3
4
5
6
7
javap -c Pref.class

public class Pref extends Sup {
Pref();
    Code:
    0: aload_0       
    1: invokespecial #1                  // Method Sup."<init>":()V

First the invokespecial line calls the constructor for Sup() explicitly, while we did not do that ourselves. Second if you look at Sup :

invokespecial
1
2
3
4
5
6
7
8
9
javap -c Sup.class

class Sup {
Sup();
    Code:
    0: aload_0       
    1: invokespecial #1                  // Method java/lang/Object."<init>":()V
    4: return        
 }

This one is short enough to print whole, and you see that it in turn invokes the constructor for Object(), also not in our code.

Personally i think this is a weak solution from java and it should have just throw a compile error if you omit a constructor.

Important

Define default constructors and super() calls explicitly yourself. Its just clearer.

Important

in java every first statement is a call to another constructor, either one of it's own by using this() or of it's parent using super().

Since you cannot keep calling this() recursively the call path of a constructor always ends up in a super() version.

Overriding methods

Important

You can override a method from a parent class by using the same signature and return type.

The rules for overriding are

  • The method must have the same signature and return type as the one in the parent class
  • The method in the child class must be at least as accessible as the parent.
  • The method in the child may not throw a checked exception that is new or broader than the on in the parent. New of course is also broader then nothing.
  • If the method returns a value, it must be the same as or a subclass of the type in the parent.

Important

Types that are the same or subclassed from a type are called covariant with that type.

redeclaring private methods

Attention

Private methods are not overridden, but just redeclared in the child class.

Best to look at it that for the child there is no method in the parent class if it's private: This means you just declare a new and fresh method.

Caution

All restriction mentioned in the list above do not apply since this is NOT an override but a completely different method.

hiding static methods

Important

When both parent and child methods have the same name + signature and are static, it is called hiding the method.

When you mix static and non static the compiler will not pass it, just like it wouldn't when you do :

mix static and non-static
1
2
3
4
5
6
class Sup
{
    void func(int x);  
    static void func() {};  // fail 
    static void func(int x);  // would work, different signature
}

Important

Hiding static methods can lead to confusion, just use another name !

overriding vs hiding

overriding vs hiding
class Sup
{
    void func() {
        System.out.println("Sup func");
    }
    static void sfunc() {
        System.out.println("static Sup func");
    }
}

public class Pref extends Sup {
    void func() {
        System.out.println("Pref func");
    }
    static void sfunc() {
        System.out.println("static Pref func");
    }
    public static void main(String args[]) {
        Pref p = new Pref();
        Sup s = new Sup();

        // class is Pref
        System.out.println("class is " + p.getClass().getName());
        p.func();       // Pref func
        p.sfunc();      // static Pref func

        // class is Sup
        System.out.println("class is " + s.getClass().getName());

        s.func();       // Sup func
        s.sfunc();      // static Sup func

        s = p;
        // class is Pref
        System.out.println("class is " + s.getClass().getName());

        s.func();       // Pref func
        s.sfunc();      // Sup func

        s = null;
        s.sfunc();      // Sup func !!
    }
}

Almost all these calls act like you expect except last s.func() call. If it's a Sup why does it print a Pref ?

If you look at it with a C/pointer eye it all makes sense. You created a Pref object with new Pref(), it's now just assigned to a wider pointer. It is still a Pref() !! The first reference s was created with new Sup() and so it's a Sup.

The static ones don't look at the content, they just print the static function which is why even the last call still works !!

creating final methods

making a method final means it cannot be overridden.

Important

Final methods cannot be overridden in their subclasses but also not hidden!

Making methods final means you are very certain that this is the behavior wanted. You could also make a method private if you don't want people to touch it but :

Important

The difference between making a method private and final is that the private one can't be called from the outside.

inheriting variables

Important

You can only hide variables, there is no overriding. Both for static and instance variables.

Important

You can reach the hidden variable with super. but it is bad practice and only leads to confusion. Just pick another name !

Important

An abstract class does not have to have any abstract methods.

Important

If any of the methods is abstract, the class has to be abstract.

creating abstract classes

Abstract classes and interfaces look alike, but :

You can declare whole classes as abstract but also separate methods.

Abstract methods may not have a body, not even empty braces. So they are always followed by a semicolon ;

abstract
abstract int implement_me(int x);

Important

In classes and methods you cannot use both abstract and final since the former says "start implementing here", and the latter says "stop implementing here".

Also private and abstract are incompatible.

Important

You cannot mark a method as both abstract and private. You can't override a method if you cannot call super() because it's private.

concrete classes

Abstract classes cannot be instantiated, only the first non-abstract class can be instantiated and it has to provide implementations for all abstract methods left.

Important

You can have a hierarchy of a number of subclasses each implementing some abstract methods, or even introducing new abstract methods on the way down...

Important

... The first subclass that is not abstract can be instantiated, becoming a concrete class. This class has to implement all remaining abstract methods.

defining interfaces

Important

An interface is an abstract data type that defines a list of abstract public methods that any class implementing the interface must provide.

Important

The keyword abstract is assumed and not required.

Important

If an interface is declared public it too has to be in it's own file. It can only be public or default.

  • An interface may not be instantiated directly.
  • An interface is not required to have any methods.
  • An interface may not be marked as final.
  • All top level interfaces (as opposed to inner interfaces!) cannot be final, private or protected.
  • All non-default (java 8 feature) methods are assumed abstract and public. So private,protected and final trigger compiler errors.

Important

Adding the abstract keyword is not required but considered good practice, i would personally do this. It is just not in the way in any sense.

inheriting from an interface

Extending is not implementing !!

You can extend an interface with another interface much like abstract classes.

There are 2 rules when extending an interface:

  • An interface that extends another as well as an abstract class that implements an interface inherits all of the abstract methods as it's own abstract methods.
  • The first concrete class that implements an interface or extends an abstract class must provide an implementation for all the inherited abstract methods (left).

Important

The only connection between class and interface is : class implements interface.

  • A class can extend a class.
  • An interface can extend an interface.
  • A class can implement an interface.

Important

An interface can not be a descendant of a class.

Multiple inheritance

You can implement multiple interfaces, but also extend multiple interfaces.

Important

For interfaces it is possible te extend multiple interfaces, single inheritance is merely for classes extending classes.

When two interfaces define the same function you have to implement only one and both will be satisfied.

Important

If a method from two inherited interfaces has the same name but different signature, it is like an overloaded method, and so you will have to supply both methods.

This leads to a very nasty 'bug' in the java design in my taste:

Important

You cannot inherit from two interfaces that have the same method signature but different return type.

This does mean that classes that have a similar method but different return type you will have to choose one !!

This does not compile

multiple inheritance
interface A {
    int f();
}

interface B {
    void f();
}

public class Pref implements A,B {  // compile error !!
    public int f() {
        System.out.println("Implemented");
        return 1;
    }

    public static void main(String args[]) {
    }
}

This is a rather nasty one no-one tells about !!?!

interface variables

Important

Interface variables are expected to be public, static and final. And so they should be set on declaration.

Since that are static, no instance is needed to refer to a variable :

interface variable
interface A {
    // int x;  
    // does not compile because it's turned into:
    // public static final int x; so it should be initialized :
    int x=12;  
    public static final int y=11;
} 

class B implements A {
   public static void main(String args[]) {
        System.out.println(x); //  works, member of this class
        System.out.println(A.y); // works through interface
   }
}

default interface methods

This one is new in java 8, if you prepend a method with the 'default' keyword it is not forced to be abstract and can provide a default implementation.

default
1
2
3
4
5
6
interface X { 
    public abstract int f1();
    public default int f2() {
        System.out.println("I am a default method");
    }
} 

Important

The default method was partly(mainly?) added to be able to add new methods to interfaces after distribution. Without it everyone implementing the interface would have to recompile with the new method implemented.

  • a default method may only be declared within an interface, not within an (abstract) class.
  • a default method must be marked with the keyword 'default', and must provide a method body.
  • a default method is not assumed to be final, static or abstract, as it may be used or overridden by a class implementing the interface.
  • like all methods in an interface a default method is assumed to be public and will not compile if its' private or protected.

An interface may override the default method when implementing the interface

In that case the standard overwriting rules apply (not more restrictive access, covariant return types..)

Important

An interface me declare the method abstract, forcing any lower implementations to implement the method.

default methods and multiple inheritance

This was one of my first thoughts: what about the diamond problem ? If a class implements two interfaces with the same method it depends on if the class implements that method what happens.

  • there will be a compile error if it does not implement it, so the compiler cannot choose.
  • it will compile if it does compile it, because then the ambiguity is removed.

static interface methods

Also new in java 8. These behave almost like static methods in classes except that they are not inherited by classes implementing the interface. You always have to use the interface name to call these methods. This is also a way to avoid multiple inheritance problems.

static
interface A {
    public static void func(int x) {
        System.out.println("func A ");
    }
}

interface B {
    public static void func(int x) {
        System.out.println("func B");
    }
}

public class Pref implements A,B {
    public static void main(String args[]) {
        Pref p = new Pref();
        p.func(111); // Will not compile 
        A.func(111); // func A
        B.func(111); // func B
    }
}

polymorphism

Literally it means multiple forms. In java you can assign references to object types wider then their current type.

Important

A java object may be referenced with a reference to all super classes and all super interfaces, including of course itself.

The other way around is not allowed without a cast. In this case you can see it as c-structures.

Important

In memory classes are just like structs, they get their structure from the new() call, reference are like pointers they are allowed to provides less detail (members) not more (because they are not there in memory).

  • The type of an object determines it's properties in memory
  • The type of the reference determines with properties are accessible to the java program. So this can never be more than in memory.

casting

You could put different types of animal in the same list by assigning them to superclass animal, but when you want your kangaroo back you are not allowed unless you use a cast.

casting
class Cat extends Animal {
}

class Kangaroo extends Animal {
}

public class Animal{
    static Animal[] plist = new Animal[2];

    public static void main(String args[]) {
        plist[0] = new Cat();
        plist[1] = new Kangaroo();

        Kangaroo whatami = plist[0];     // Compile error
        // but if you insist with a cast !!! 
        Kangaroo whatami = (Kangaroo) plist[0];     // ClassCastException
    }
}

virtual methods

Virtual methods are methods of which the implementation is not known until runtime.

Important

Every non-static, non-final and non-private method is considered a virtual method.

Virtual methods are the most important feature of polymorphism and one of the primary reasons we have class structure at all.

Important

Virtual methods behave like member variables in the object. Like a function pointer remembering which version to use. Reassigning a reference to another object type would not affect that pointer.

virtual method
class A extends B {
    String getName() { return "A"; }
    void func() { System.out.println("A virtual"); }
    static void statfunc() { System.out.println("A static"); }
}

public class B {
    String getName() { return "B"; }
    void func() { System.out.println("B virtual" + getName()); }
    static void statfunc() { System.out.println("B virtual"); }

    public static void main(String args[]) {
        A a = new A();
        B b = new B();

        b = a;
        b.func();       // A virtual : A
        b.statfunc();   // B static
    } 
}

Note that the static version does not even need a valid object behind the reference. Note that although B.func() is inside B, this.getName() is an A structure and thus calls A.getName()..

Important

For types available outside a class like parameters and return types it is considered good practice to use the widest version (superclass or interface).

For example List is more versatile than ArrayList :

example
List al = new ArrayList();

Exceptions

Important

Don't use exceptional return codes like null or -1 because these can be forgotten or ignored by the caller, exceptions shout "Deal with Me !"

Two mayor types are java.lang.Error, and java.lang.Exception which are both subclasses of java.lang.Throwable. Furthermore RuntimeException is a subclass of Exception.

Important

All exceptions (all throwables) happen at runtime, otherwise it would be a compile error. You therefore can better read RuntimeException as "unchecked Exception".

  • Errors mean something went horribly wrong: like StackOverflowError, you should not attempt to handle it, maybe rewrite code so it does not happen anymore.
  • unchecked exceptions mean something unexpected happened but you can reasonably recover from it : accessing an invalid array index, or division by 0
  • checked exception mean something happens you could have foreseen : trying to read a file that does not exist.

The last one therefore is checked at compile time that you either handle the exception or pass (throw) it on to a higher level to handle.

Type Ok for program to catch ? Program required to handle


Runtime exception Yes No Checked exception Yes Yes Error No No

try statement

The smallest form of try statement is :

try catch
1
2
3
try { 
} catch(Exception e) { 
} 

Important

The try and catch blocks are also called clauses and are similar to functions in that the curly braces are required.

Important

At least try and 1 catch block are required.

The try clause is the normal programming logic and it will continue until an exception is thrown, or until the end of the block. If an exception is thrown there is a direct jump to the catch block, or the best matching catch block if there are more.

jump
try { 
    walk();
    fall();
    walk();     // never reached 
} catch(RuntimeException rte) {
    handle();
    walk();
} 

...

void fall()  { throw new RuntimeException(); } 

Important

Exceptions are just classes, so you have to create an instance before you can throw one.

finally

An optional clause is the finally clause.

Important

If you use finally it should always be the last clause: try{} catch() {} ... catch() {} finally {}

The finally clause is 'always' called regardless if an exception occurred.

Important

Finally is 'always' executed, with 'always' in quotes because it will not be called when you hard exit the program.

As an example :

finally
public class Test
{
    public static void main(String args[])
    {
        try {
            System.out.println("Trying...");
            trigger();
            System.out.println("Trying...");
        } catch (RuntimeException e) {
            System.out.println("Catching...");
            //System.exit(1);
            return;
        } finally {
            System.out.println("Finalizing...");
        }
    }

    static void trigger() { throw new RuntimeException(); }
}

With the return this will print :

output
1
2
3
Trying...
Catching...
Finalizing...

Switch the return and the exit and it will be :

output
Trying...
Catching...

So this does imply that when return is called the compiler first visits the finally clause.

Important

You cannot put a less specific Exceptions before a more specific one in catch blocks. The compiler will not allow that and print en unreachable statement error.

throwing a second exception

You can have more try blocks nested inside all clauses, but that could sometimes lead to multiple exceptions being thrown, however only 1 (the last) is actually thrown.

Important

Only the last exception to be thrown matters !!

For instance :

last exception
1 public class Test
2 {
3     public static void main(String args[])
4     {
5         try {
6             System.out.println("Trying...");
7             throw new RuntimeException();
8         } catch (RuntimeException e) {
9             System.out.println("Catching...");
10            throw new RuntimeException();
11         } finally {
12             System.out.println("Finalizing...");
13            throw new RuntimeException();
14         }
15     }
16 
17 }

This prints :

output
1
2
3
4
5
Trying...
Catching...
Finalizing...
Exception in thread "main" java.lang.RuntimeException
        at Test.main(Test.java:13)
  • The first exception is thrown on line 7,
  • and immediately caught on line 8.
  • So now first the catch block runs, throwing an exception on line 10,
  • and then finally runs throwing an exception on line 13

Obviously the exception on line 10 never happens, java takes the last one and removes all others.

Exception types

Runtime exceptions

Exception Thrown By description
ArithmeticException
ArrayIndexOutOfBounds
JVM JVM mainly : division by zero
ClassCast JVM when casting an object to a subclass of which it is not an instance
IllegalArgument programmer after parameter checks
NullPointerException JVM when trying to dereference null
NumberFormatException programmer when wrong number format is used

checked exceptions

Exception Thrown By description
FileNotFoundException IO code trying to open a nonexistent file
IOException IO code problems trying to read or write a file

errors

Error Thrown By description
ExceptionInIntialzeError JVM when a static initializer throws an exception java can't start using it
StackOverflowError JVM normally a recursion error
ClassNotFoundError JVM a class was found at compile time but not at runtime

subclasses

When a class overrides a method from a superclass, or implements a method from an interface, it may not add new checked exceptions to that overridden method.

subclasses
class NoChocolateException extends Exception;

public class Animal
{
    void feed();

    public static void Animal(String ... args) {
        Animal a = new Dog();
        Dog d = new Dog();

        // We would have to do  :
        try {
            d.feed();
        } catch (NoChocolateException nde) {
        }

        // but this would be allowed, but it calls Dog.feed() and 
        // that throws a NoChocolateException !
        a.feed();  // which does not get handled now
    }
}


class Dog extends Animal {

    @Override
    void feed() throws NoChocolateException { // overridden method does not throw NoChocolateException
        throw new NoChocolateException();
    }   
}

Important

I think this is a java design flaw since more detailed classes are bound to encounter more exception types. You will now have to add any new exception up along the class hierarchy.

Important

Exceptions thrown by overridden methods may only become more specific on the way down, never broader.

Important

This means every exception in the exception list has to be a subclass of the parents exception list. The exception list of the subclass may be shorter or absent.