Advanced class design:

Anonymous classes are implicitly final and it can never be static.

static method > default method

default method > abstract method

default method > default method (re-declared with different implementation)

default method > static method

static method > non-static method

non-static method > static method

Static methods can never be abstract.

Static interface methods must be invoked using the interface name instead of reference variable – otherwise an error will be raised.

When overriding you set of exceptions may be smaller (none is ok) or the same but no bigger; although you can add as many unchecked exceptions as you need.

Differences between static and default methods in Java 8

  1. Default methods can be overriden in implementing class, while static cannot.
  2. Static method belongs only to Interface class, so you can only invoke static method on Interface class, not on class implementing this Interface
  3. Both class and interface can have static methods with same names, and neither overrides other!

Lambda Expressions and Functional Interfaces:

A local variable has to be final or effectively final to be accessed from an inner class or lambda expression.

All of the java.lang package wrapper classes are immutable: Boolean, Byte, Character, Double, Float, Integer, Long, Short, String.

The parameter names in the lambda expression exist in the same scope as the method or the block in which the lambda expression is created.


  • Enum constructor is always private.
  • Enums are implicitly final.
  • Enums cannot extend anything (they already extend java.lang.Enum) but can implement some interface.
  • You cannot clone enums.
  • Implement Comparable (can be added to sorted collections)
    • important note here: elements are compared by the order they were defined! not alphabetically or some other way!
  • these methods are important:
    • values() – an array of all constants
    • valueOf() – return a constant from Enum
    • ordinal() – index of constant starting with 0
    • name() – name of the constant 

Access modifier of constructors match that of the class it belongs to.

Outer classes have access to private inner members of inner classes.

Generic methods:

Generic methods are methods that take generic parameter types – that is they may be used on different types (classes, interfaces) not just one (as in case of simple methods).

Difference between simple and generic method:

  • Simple method:
  • Generic method:


Subtyping does not work for generic parameters.


Wildcard parameter types allow for subtyping.


Wildcard parameters

Wildcard parameters can be used when you want just to use methods that access objects.

Wildcard parameters cannot be used when you plan to use methods that modify objects.



Collection name May add null keys May add null values
HashSet Not applicable Yes
HashMap  Yes Yes 
ConcurrentHashMap NullPointerException NullPointerException


TreeMap methods to be learned:

  • pollFirstEntry() – removes first map entry and returns removed Map.Entry, null if map empty
  • pollLastEntry() – removes last map entry and returns removed Map.Entry, null if map empty
  • tailMap(K fromKey, boolean inclusive) – returns a view of the map starting with fromKey and may include that element or not depending on inclusiveView here is an important term – if you modify the map that is a view of another map the source map will get modified.


  • can act as Queue and as Stack – so it has methods that reproduce behavior of:
    • Queue (FirstInFirstOut), has methods:
      • add(e) / offer(e) 
        • add(e) – returns true if element added or throws IllegalStateException if queue already has maximum capacity
        • offer(e) – returns  true if ok or false if not – no exceptions
      • remove() / poll()
        • remove() – removes and returns head of queue or throws NoSuchElementException if queue is empty
        • poll() – removes and returns head or null if queue is empty
      • element() / peek()
        • element() – returns head of queue or throws NoSuchElementException if queue is empty
        • peek() – returns head or null
    • Stack (LastInFirstOut), has methods:
      • push(e) – equal to addElement(e); pushes an item to top of stack. Returns the item pushed.
      • pop() – removes top element of stack and returns it (just like remove() in queue) or throws EmptyStackException if stack was empty.

Nota bene: In Stack peek() may throw an EmptyStackException whilst in Queue peek() would just return null.

⇐ Out (Queue)    Dequeue queue behaviour   ⇐ In
  • removeFirst
  • pollFirst
  • getFirst
  • peekFirst
  • addLast
  • offerLast
⇒ In (Stack)
⇐ Out (Stack)
  Dequeue stack behaviour    

  • addFirst


Collections.sort(someCollection, null) – will just use the default sorting for someCollection – no exception will be thrown.

Sorting strings rule:
spaces < numbers < uppercase < lowercase

From java.util only 2 collections are thread-safe:

  1. Vector
  2. Hashtable

You can turn a simple collection in a thread-safe one using java.util.Collections.synchronizedCollectionName() like:

Since Java 5 there is a special package with thread-safe collections – java.util.concurrent.

Keys of a TreeMap have to be comparable between each other.

Integer class hashCode() returns the int value.

Exceptions and Assertions

Any exception that is thrown while closing a resource is added to the list of suppressed exceptions of the exception thrown while opening a resource (or thrown from the try block.)

The exception parameter in a multi-catch clause is implicitly final. Thus, it cannot be reassigned. If there is only one exception in the catch clause exception parameter is not final.

Resources are closed automatically at the end of the try block in reverse order of their creation. The close method is called on all the resources one by one even if any resource throws an exception in its close method.

An overriding method must not throw any new or broader checked exceptions than the ones declared in the overridden method. This means, the overriding method can only throw the exceptions or the subclasses of the exceptions declared in the overridden method. It can throw any subclass of Error or RuntimeException as well because it is not mandatory to declare Errors and RuntimeExceptions in the throws clause. An overriding method may also choose not to throw any exception at all.

When an assertion fails, a programmer should always throw the exception.

AutoCloseable‘s close method throws Exception while Closeable‘s close method throws IOException.

In try-with-resources resources are closed at the end of the try block and before any catch or finally block.

Using the Java SE 8 Date/Time API

Important classes in java.time

java.time contains following subpackages:

  1. java.time.temporal – access date/time fields and units
  2. java.time.format – format input/output of date/time objects
  3. – handle timezones
  4. java.time.chrono – support foreign calendar systems


java.time.LocalDate – date without time or timezone. Represented in ISO-8601 – YYYY-MM-DD – 2018-10-26.

  • – current date in YYYY-MM-DD formate ex. 2018-05-07. System time, default timezone.
  • LocalDate.of(2018, 1, 5) – not 01

To avoid ambiguity with months – java.time.Month enum may be used.

ex.: LocalDate.of(2018, Month.MAY, 05) 


Represents time without dates or time zones. Time is in ISO-8601 calendar system format: HH:MM:SS.nanosecond.


Represents both date and time – without time zones.

You can extract LocalDate and LocalTime from LocalDateTime using .toLocalDate() and .toLocalTime().

When printing LocalDateTime you get something like 2018-10-03T16:14:11.344. T is a separator between date and time.


Instant is used for timestamps. It stores seconds since the beginning of Unix epoch (January 1, 1970 at 00:00:00). Negative values are stored for any time before that moment.

Instant stores seconds in long types variables and nanoseconds in int type.

Nota bene:’s time zone is Greenwich not system default time zone.


Used for measuring an amount of time in yearsmonthsdays.

Important methods:

  • Period.between(LocalDate a, LocalDate b)
  • Period.of(int years, int months, int days)
  • Period.ofWeeks(int a)
  • Period.ofDays(int a)
  • Period.ofMonths(int a)
  • Period.ofYears(int a)
  • Period.parse(CharSequence string) – ex. Period.parse(“P2Y1M3D”)

Printing returns something like: P3Y2M4D.

P – period


Duration is similar to Period but it works with hoursminutes, seconds, milliseconds (millis) and nanoseconds (nanos).

When printed you obtain: PT4H3M46S.

Note the smallest unit being printed is S. Millis and nanos are printed as decimal formatted units of seconds. 

If a section has zero value it is omitted.

Prints: PT0.002S

Prints: PT0.000000003S

Enum ChronoUnit (implementation of TemporalUnit – the only one as of version 8) is very handy when you need to work with time-related constructos and so on.

Working with time zones and daylight savings

Time zones are identified by the offset from GMT(Greenwich Mean Time – GMT aka UTC/Greenwich).


Zone ids are held in a Set<String>. Like: “Asia/Kolkata”


Atlantic Time


ZoneOffset represents zone offset from GMT (UTC/Greenwich).



LocalDate + LocalTime + ZoneId = ZonedDateTime


LocalDateTime + ZoneId = ZonedDateTime




Please enter your comment!
Please enter your name here