DEV Community

limjy
limjy

Posted on • Updated on

Core Java / Java Theory

Theory stuff about Java

Content here is not original. It is my summary of the following resources
References:
This medium post by Edureka (along with other articles in the series) are insanely good

in28Minutes github - this is a great resource for interview prep. ( However do double check with other sources. I find their explanation of encapsulation & unchecked VS checked exception strange )

Other good resources:

javarevisited is a very good resource for in-depth questions. It's good for harder / obscure questions and makes your understanding clearer by doing a deep dive.

https://www.edureka.co/blog/interview-questions/oops-interview-questions/

Quick Summaries of OOP:
https://blog.udemy.com/oops-interview-questions/
https://blog.udemy.com/oop-interview-questions/

TOC

Java Stuff

Java syntax

block

-static VS instance block

Wrapper Class

Strings

Objects class / Java Objects basics

Data Structure Implementations( knpcode.com has really good tutorials and write ups for DS implementations )

Java Implementations / Interfaces / Common Classes ( will only go through general-purpose implementations coz no time )

  • Map Implementations
    • HashMap
    • TreeMap
    • LinkedHashMap
  • Set Implementations
    • HashSet
    • TreeSet
    • LinkedHashSet
  • List Implementations
    • ArrayList
    • LinkedList
  • Queue Implementations (see above)
    • PriorityQueue
    • LinkedList
  • Dequeue Implementations (double-ended queue) ( going to skip this )
    • LinkedList
    • ArrayDequeue

OOP Concepts & OOP in Java( references in this section mainly from educative articles: OOP & OOP in Java

Java Exception Handling (JournalDev Exception Handling article primarily used as reference for this section )

OOP Concepts

  • SOLID (https://www.baeldung.com/solid-principles)
    • single responsibility
    • openfor extension closed to modfication
    • lishov subsitution (sub subclass for base class)
    • interface segregation (split big interface itno smaller ones)
    • dependency inversion (depend on abstract classes/ interfaces instead of classes)

UML

  • needed to understand different design patterns
  • Class Diagram
    • Association
    • inheritance / generalization / abstraction
    • multiplicty
  • Sequence Diagram

Design Patterns

MultiThreading

Statically Typed

Reference: Oracle Documentation

  • perform type checking at compile time
    • provides type safety
    • if Java code contains errors, it will fail to compile until the errors have been fixed
  • declare data types of variables before you use them
    • int num; num = 5; VS num =5
    • expects variables to be declared before it can be assigned value.

Opposite of statically typed is dynamically-typed (eg. python)

Class based

Reference: mozilla developer docs & stack overflow & zendesk & wikipedia

Class based programming / class-orientation is a style of Object-oriented programming (OOP)
Class-based: makes distinction between objects & class.
prototype-based: no distinction. It has objects. start with an instance / object & modify it.

  • Defining class
    • define class in class definition & specify methods (constructors) to create instances of the class.
    • prototype : class definition not separate from constructor. constructor function creates object with initial set of properties & values
  • Subclass / inheritance
    • create heirachy via class definition Manager extends Employee
    • prototype: associate object with any construtor function. (call another object in the constructor function of subclass)
  • Adding & removing properties
    • cannot change type / number of properties after class definition
    • class created at compile time & objects instantiated at compile or run time
    • prototype: ca remove or add properties of any object at run time.

Opposite of class based is protoype-based / object-based (eg. javascript)

What is Object-oriented programming

Reference: wiki & educative & educative - Oop JS

OOP is a programming paradigm based on the concept of "objects".
Program is broken down into segments of objects that communicate with each other.
Each objct is define by:

  • its functions (called methods)
  • its data (called properties)

This is a general overview of OOP. as seen in previous section that are also different "styles" of OOP (object-based & class-based).

From some articles we can also see the question "Is a OOP langauge?" is not a straight forward yes or no answer.

To be OOP language, programming language has to satisfy a list of OOP condition / properties. Depending on whether programming language has satisfied some / all OOP conditions we can then say "yes" or "no".
Even if the answer is "yes" programming language is OO. There is still the question of "is purely object-oriented?"

Alternatives / Opposite
There is no "opposite" of object -oriented proramming. But there are different programming paradigms like: (reference: SO)

  • procedural
  • fuctional etc.

Java not pure OOP

Reference: GeeksforGeeks & dataflair

Java is not a pure object-oriented language. Because it has:

  1. primitive data type
  2. static keyword
  3. wrapper class

To fulfill pure OOP, language must satisfy all 7 conditions:

  1. Encapsulation / Data Hiding
  2. inheritance
  3. polymorphism
  4. abstraction
  5. All predefined types are objects
  6. All user defined types are objects
  7. All operations performed on objects must be only through methods exposed at objects

Java fails condition 5(all predefined types are objects) & 7(operations performed on objects must be only through methods exposed at objects)

  • primitive data types
  • static keyword
    • when class is static, it can be used without objects
    • static function / variables. can be called without creating an object of class.
  • Wrapper class
    • unboxing: when using arithemtic operators (% or +=) are performed on wrapper classes. compiler converts object to primitive datatype at runtime. Thus violating condition 5 (primitive types are not objects)
    • arithmetic operations on object String test = "hello" + " world" use of arithmetic operations on wrapper class also violate condition 7 (can communicate with objects with calling their methods)

Java platform Independent

Java is WORA (Write once Run anywhere). java source code can run on all operating systems.
byte code (.class) generated by javac compiler can be executed on any OS. Bytecode is understandable is any JVM installed on any OS.

JAVA is platform-independent language, the JVM is platform-dependent.
must install different JVM for different OS.

JVM will convert bytecode (.class) to machine code
Since machine code is run, this makes run time faster.

Reference: javatpoint & codingningjas & guru99

Java: JVM, JRE, JDK

alt text

JDK: Java development Kit
software development environment used for making applets & Java applications.

  • JRE + compiler + debugger JRE: Java Runtime Environment software designed to run other software. To run Java you need JRE. It contains class libraries, loader class & JVM.
  • JVM + libraries + other components (to run applets / java applications) JVM:
  • Virtual machine running java bytecode
  • maeks java portable
  • comes with JIT(Just-In-Time) compiler that converts java source code to low-level machine langauge.

Reference: guru99 & javatpoint & geeksforgeeks

Java JIT Compilation

Just-In-Time (JIT) Compilation also known as dynamic compilation.
Program is compiled to native code during runtime to improve performance.

In JIT compilation,

  • translates bytecode(.class) to machine code instructions of running machines
    • resulting machine code is optimized for running machine's CPU architecture
  • compilation is done at runtime of program (as opposed to prior to execution)
  • since compilation takes place in run time, JIT compiler has access t dynamic runtime information enabling it to mae better optimizations

The hope is that the efficiency of running machine code will overcome inefficiency of recompiling program every time it runs.

Optimizations
JVM execute bytecode & mantians count of how many times function is executed
If count exceeds pre-defined limit, JIT compiles code into machine lanaguage that can directly be execute by processor.

Next time, function is calaculated, compiled code is executed again unlike normal interpretatio --> faster execution

Reference: freeCodeCamp & GeeksforGeeks & javatpoint

Memory Managment in Java

Memory management is the process of allocation & de-allocation of objects. Java uses automatic memory management system called garbage collector.

Reference: javatpoint & oracle docs & peter lee medium

Java: Heap Space VS Stack Memory

To run application in optiomal way, JVM divide memory into stack & heap memory
Stack:

  • used for execution of thread
  • primitive values specific to a method
  • references to objects that are in a heap, referred from method.
  • thread-safe: eahc thread operated in its own stack Heap:
  • actual objects
  • dynamic memory allocation for Java objects & JRE classes at runtime
  • String Pool
  • not thread-safe: needs to be guarded by properly synchronizing code

New objects are always created in heap space and the references to this objects are stored in stack memory. When the heap becomes full, garbage is collected. So, no longer used are cleared, thus making space for new objects.

  • Heap
    • created when JVM starts up & may increase/decrease in size while application runs
    • when heap is full, garbage is collected
    • new objects created in heap space references to objects stored in stack memory
    • objects have global access and can be accessed from anywhere in the application, not thread safe
    • Broken down to 3 parts
    • Young Generation: all new objects are allocated & aged.
    • Old / Tenured Generation: long surviving objects stored. object stored in young gen, threshold for its age set. when threshold reached. Object moved to old gen
    • Permanent Generation: JVM metatdata for runtime classes & application methods.
    • When heap becomes full garbage is collected
  • Stack
    • referenced in LIFO order
    • when new method is called, new block on top of stack is created which contains values specific to that method (eg. primitive variables & references to objets)
    • method finish execution -> corresponding stack frame is flushed, flow goes back to calling method. space available for next method
package com.journaldev.test;

public class Memory {

    public static void main(String[] args) { // Line 1
        int i=1; // Line 2
        Object obj = new Object(); // Line 3
        Memory mem = new Memory(); // Line 4
        mem.foo(obj); // Line 5
    } // Line 9

    private void foo(Object param) { // Line 6
        String str = param.toString(); //// Line 7
        System.out.println(str);
    } // Line 8

}

Enter fullscreen mode Exit fullscreen mode

alt text

  1. Run program -> load runtime classes to Heap space
  2. main() method found at line 1, runtime create stack mem to be used by main() method thread. Whenever new object created,
  3. object created in heap memory
  4. stack memory contains the reference for it.
  5. when new method called -> new block created on top of stack (LIFO)
  6. String, reference in stack mem -> reference points to String pool in heap space
  7. when method (foo())terminates, stack becomes free (stack mem created for function destroyed)
  8. move to next program below (main())

alt text

Reference: stackify & baledung & JournalDev

Java Garbage Collection

GC: Process by which Java performs automatic memory management
When Java programs run on JVM, objects are created on the heap. When some objects no longer needed. GC will find the, delete them to free up memory.

4 garbage collectors: planning to bomb this if asked

  • serial
  • parallel
  • concurrent mark sweep
  • G1 (h=garbage first)

Benefits

  • automatically handles deletion of unused objects / objects out of reach to free up virtual memory resources.

Reference: stackify

Java: Comparison to Python

  • Java programs expected to run faster than python

    • Python tun time typing, python run time "works harder" than java (more tasks to do
    • python run time must inspect objects and find type then invoke operation
  • Java programs take longer time to develop

  • Java programs are longer (number of lines of code) than python

    • java is statically typed

Reference: python org

Objects & Classes

Class: user defined blueprint from which object is created
Object: basic unit of OOP, instance of a class.

objects can be created from class via constructor. There are 2 kinds

  • Default / non-parameterised
    • 0 arguments
  • Parameterised
    • constructors have specific number of arguments to be passed

constructor cannot be abstract final or static

Variables & Methods

Types of variables

  • local
  • instance
  • static

each object has own copy of instance variable however, all objects will share only one copy of static variable

alt text
alt text

Methods
Methods consist of

  • modifier
    • eg. private / public
  • return type
  • method name
  • parameters
  • method body / logic

static methods belong to a class, no need to instantiate object to use the method

Method Signature

Method signature is <method name>()<argument types>)
Does NOT include: access modifier & return type

In java, you cannot have >=2 methods with same method signature in the same class (even if methods have different return types)

public void display(String info){
  System.out.println(info);
}

// ERROR: duplicate method Signature
public String display(String info){
  // logic
}
Enter fullscreen mode Exit fullscreen mode

Packages

Group of classes & interfaces & sub-packages which has similar functionalities.
Provide folder structure to organise classes

packages naming style:

  • lower case
  • reverse domain

Access Modifiers

Modifiers set accessibility of classes or methods or any memebers

  • public
  • private
  • protected
  • default (no modifiers)

alt text
alt text

Reference: Jenkov tutorials & GeeksforGeeks

Abstract Keyword

non-access modifier applicable for classes and methods but not variables
Used to achieve abstraction in Java (one of the pillars of OOP)

Abstract class

cannot create / instantiate object of abstract class
Any subclass of abstract class must either implement all abstract methods or be declared abstract itself.

abstract class class-name{
    //body of class
}
Enter fullscreen mode Exit fullscreen mode

Due to partial implementation of classes, object cannot be instantiated.
Abstract class depend on subclass to provide complete implementation.
Any sub

Abstract method

Abstract method dont contain body. sub classes will implement them

abstract type method-name(parameter-list);
Enter fullscreen mode Exit fullscreen mode
  • any class containing abstract method must be abstarct
  • the following combinations of modifiers cannot be used with abstract
    • final (class & method)
    • private (method)
    • static (method)
    • synchronized (method)
    • native / strictfp

Further reading of abstract method on Java Goal

References: GeeksforGeeks & javatpoint

Abstract Illegal modifiers

Abstract final

  • Class: final used to prevent inheritance
    • Abstract classes depend on child classes to complete implementation.
  • Method: final used to prevent overidding -abstarct method need to be overidden in sub classes

Abstract private

  • Method: private method cannot be accessed outside current class
    • child classes cannot access private abstract methods & cannot implement it.
  • Class: nested class. everything within class can access a nested private class
    • can have a nested private abstract class SO example

Reference: tutorialspoint & stackoverflow

Abstract static

  • Method: static methods can be hidden but not overidden
    • abstract method must be overidden to be implemented. Static methods cannot be overidden, so they cannot be abstarct.

Reference: tutorialspoint & stackoverflow

Abstract synchronized

Abstract strictfp

strictgp is a an access-modifier. no modifiers allowed on abstarct methods except public and protected.

Final Keyword

for classes, variables & methods
used to finalize implementation of them

alt text

  • Final variable
    • to create constant variable
    • cannot change the value of final variable once it is assigned. It will be constant.
    • can be initialized in constructor.
  • Final method
    • prevent method overriding
    • can be inherited but cannot be overridden.
    • constructor cannot be made final. constructor cannot be inherited so it cannot be overriden, will have compile time error.
  • Final class
    • prevent inheritance

references javatpoint & GeeksforGeeks & tutorialspoint

Static Keyword

for variables, methods, block, nested class
used to define classes members indepedent from any instances

  • static variable
    • single copy of variable is create & shared among all objects at class level
  • static methods
    • can be accessed before any objects of class created & without reference to any object.
    • can only directly call other static methods
    • can only directly access static data
    • cannot refer to this or super
  • static nested / inner class
    • mainly for convinience
    • no need to instantiate outer class to instantiate inner class
    • refer to: https://stackoverflow.com/a/47568544
    • useful for: builder pattern (inner builder class is static)
  • static block
    • do computation to initialize static variables
    • is executed exactly once - when class is first loaded.
class Test {
    // static variable
    static int a = 10;
    static int b;

    // static block
    static {
        System.out.println("Static block initialized.");
        b = a * 4;
    }
}
Enter fullscreen mode Exit fullscreen mode

References: GeeksforGeeks & javatpoint & Baeldung

Static VS Instance block

static block:

  • runs at time of class loading
  • will execute in same order they appear in the class
  • static block of parent class execute FIRST because compiler loads parent class BEFORE child class

instance block:

  • runs at time of instance creation
  • executees during every constructor invocation
  • parents instance block will run first BEFORE child's instance block

Order is
Super class - static
Sub class - static
Super class - instance
Super class - constructor
Sub class - instance
sub class - constructor

Note that by default JVM will insert super() ins first line of sub class constructor if developer has not done so.

ref: https://www.quora.com/In-Java-does-every-object-constructor-automatically-call-super-in-object-before-its-own-constructors
ref: https://www.javamadesoeasy.com/2015/06/differences-between-instance.html

Image description

ref: https://www.baeldung.com/java-static-instance-initializer-blocks

Wrapper Classes are immutable

Wrapper classes are immutable so operations like add, subtarct create new object and do not modify the old

Reference: GeeksforGeeks
eg.

public static void main(String[] args)  {
        Integer i = new Integer(12);
        System.out.println(i); // 12
        modify(i);
        System.out.println(i); //12
}

private static void modify(Integer i) {
        i = i + 1;
}
Enter fullscreen mode Exit fullscreen mode

paramete i is referenced in modify however it does not change since objects are immutable.

Creating new object
Reference: SO & []

Integer a=3;
Integer b=3;
a+=b; // a=a+b
System.out.println(a); // 6
Enter fullscreen mode Exit fullscreen mode

In this case, a+=b actually does a = new Integer(3+3)
a is a reference, in the line a+=b, the code changes the reference a to points to a different, equally immutable Integer.

Why wrapper class

Wrapper classes wraps around data type and give it an object appearance, this provides object methods to primitive types.
Reasons:

  • null is possible value
  • use it in Collection
  • methods that support object (eg. creation from other types Integer test = new Integer("55");

Different wrapper classes
alt text

Constructor VS valueOf

There are two ways to create wrapper class

  • constructor Integer test = new Integer("100");
  • valueOf Integer test = Integer.valueOf("100");

constructor: always creates new object
valueOf: may return a cached value if it is within range. (eg. if long is between -128 to 127, valueOf implements a cache). If not in cache gives new object.

valueOf is generally recommended since it results in better space and time performance by caching frequently requeste values.

Since wrapper classes are immutable, its important to reuse values.

Under the hood autoboxing also invokes the static valueOf method

Reference: java docs & SO answer

Autoboxing & Unboxing

automatic conversion Java compiler makes between primitive types & their corresponing object wrapper class.
Conversion the other way is called unboxing.

// autoboxing
Integer test = 9; 

// autounboxing
Integer test1 = Integer.valueOf(10);
test1++;
Enter fullscreen mode Exit fullscreen mode

Autoboxing
create Integer object from primitive data type
Integer test = Integer.valueOf(9);

Auto Unboxing
airthmetic operations (+, %, +=) do not apply to Integer objects. Java compiler compiles code with no errors since it does autounboxing, invoking intValue to convert Integer to an int at runtime. test1.intValue()++;

reference: java docs

Autoboxing Advantages

lets developers write cleaner code that is easier to read.

Additionally, Autoboxing uses static valueOf method which is more efficient

Reference: java docs

Typecasting - Implicit & Explicit

Typecasting: converting primitive/interface/class in Java into another type.
If 2 types are compatible java performs conversion automatically else they need to be converted explicitly.

  • Implicit/widening/automatic
    • happens if both types are compatible & target type is larger than source type

alt text
casting smaller value to a larger variable types

byte i = 50; // 50
short j = i; // 50
int k = j; // 50
long l = k; // 50
float m = l; // 50.0
double n = m; // 50.0   
Enter fullscreen mode Exit fullscreen mode
  • Explicit/narrowing
    • assigning larger type to a smaller type

alt text
casting larger value to a smaller variable types

double d = 75.0; // 75.0
float f = (float) d; // 75.0
long l = (long) f; // 75 
int i  = (int) l; // 75
short s = (short) i; // 75
byte b = (byte) s; // 75
Enter fullscreen mode Exit fullscreen mode

Reference: GeeksforGeeks & javainterviewpoint & edureka

Strings - immutable

Value of String object once created cannot be modified.
Any modification creates a String object
String is mainly immutable becuase it encapsulates a char[]

String test = "hello";
test.concat(" world");
System.out.println(test); // hello
Enter fullscreen mode Exit fullscreen mode

value of String object was not modified. the concat()operator like toUppercase() operator produces a new String. The original value remains unchanged.

String str = "hello";
str = str + "world";
System.out.println(str); //hello world
Enter fullscreen mode Exit fullscreen mode

In the code snippet, str was not changed. Rather a new String object "hello world" was instantiated and assigned to the reference str.

Reference: SO

Where are string values stored i memory?

depends on how we create them

  1. String literal -> String constant pool (in heap)
  2. new Object -> heap memory
  • String literal
    • value stored in String constant pool (heap memory)
    • compiler finds String literal -> check if exists in pool, reused.
  • String object constructor
    • new object created on heap, reference in stack.
    • not reuse of values

Java String Pool

String Pool in java is a pool of Strings sorted in Java Heap memory.

  • saves space for Java runtime
  • more time to create string.

alt text

only possible becuase

  • String is immutable in Java
  • implementation of String interning concept

String pool is an example of Flyweight design pattern.

String literal
String test = "hello";
when create string via String literal,

  • java looks for string with same value in string pool
    • found: returns reference
    • else: create new String in pool -> return reference.

String constructor
force Java to create new String object in heap space

String s1 = "Cat";
String s2 = "Cat";
String s3 = new String("Cat");

System.out.println(s1==s2); // true
System.out.println(s1==s3); // false
Enter fullscreen mode Exit fullscreen mode

Reference: JournalDev

Java String Interning

method of storing only 1 copy of each distinct String value, which must be immutable.

Java String class has public method intern()

  • invoke intern() method on String object.
  • looks for the string contained by object in the pool
  • if string is found
    • string from pool is returned
  • else:
    • String object added to pool & reference to String object returned.

So by applying String.intern() on strings will ensure all strings with same content share same memory. eg. if 'hello' appears 100 times, interning ensures 1 'hello' is actually allocated memory.

String s1 = "Test"; // s1 in SCP
String s2 = "Test"; // s2 in SCP
String s3 = new String("Test"); // s3 in heap
final String s4 = s3.intern(); // s4 in SCP
System.out.println(s1 == s2); // true
System.out.println(s2 == s3); // false
System.out.println(s3 == s4); // false
System.out.println(s1 == s3); // false
System.out.println(s1 == s4); // true
System.out.println(s1.equals(s2)); // true
System.out.println(s2.equals(s3)); // true
System.out.println(s3.equals(s4)); // true
System.out.println(s1.equals(s4)); // true
System.out.println(s1.equals(s3)); // true
Enter fullscreen mode Exit fullscreen mode

Reference: GeeksforGeeks & DZone

Number of Objects created in String Construction

String str = new String("Cat");
Enter fullscreen mode Exit fullscreen mode

Either 1 or 2 objects created

  • String literal
    • "Cat" String created in String pool (if does not exist)
  • String str object

Never + String in loops

each concatenation creates a new object, since string in immutable
use String Buffer/Builder

String test = "lup";
String test2 = "dup";
for (int i=0;i<100000;i++){
  test = test + test2;
}
Enter fullscreen mode Exit fullscreen mode

Loop creates about 100 000 String objects.

String Buffer

StringBuilder test = new StringBuilder("lup");
String test2 = "dup";
for (int i=0;i<100000;i++){
  test.append(test2);
}
String result = test.toString();
Enter fullscreen mode Exit fullscreen mode

This would yield better performance.

String VS StringBuffer

  • String immutable, StringBuffer used to represent values that can be modifed.
  • both are thread safe

StringBuilder VS StringBuffer

String Builder not thread safe String Buffer is

Java What is a class

template for creating multiple objects.
It defines:

  1. state
  2. behaviour that an object can exhibit

State
Values object has.
In Java, this would be the instance variables of the object

Behaviour
methods that are part of the class

State of object can change with time, can change via behaviour / class methods.

Java:

instance of class
Can create objects via constructor

ParentClass of every class

Java Object class is the super / parent class of every class in Java

Useful if you want to refer to any object whose type you dont know.

Classes will inherit all properties & methods of Java Object class.
eg.

  1. toString
  2. hashCode
  3. equals
  4. clone

Java Object toString method

used to print content of object
It is inherited from the Java objects class.
Default : print hash code
overridden : content returns by toString overidden implementation is printed.

The toString() method MUST

  1. be public
  2. return type: String
  3. not accept any parameteres

Object class default toString method

public String toString()
{
      return getClass().getName()+"@"+Integer.toHexString(hashCode());
}

MyClass test = new MyClass();
System.out.println(test);
// com.example.demo.MyClass@f7e66a96
Enter fullscreen mode Exit fullscreen mode

Reference: GeeksforGeeks & in28Minutes

Java equals() method

used to compare 2 object
Inhierited from java Objects class
Default: uses == operator (check if references point to the same object)
overidden: usually implemented as checking all properties of object have equals value

If making you own custom class, must override equals method to check the contents of the object.

equals() Method Criteria

All implementation of equals method must meet following criteria

  • Reflexive
    • For any reference values x, x.equals(x) returns true
  • Symmetric
    • x.equals(y) == y.equals(x)
  • transitive
    • if x.equals(y) = true & y.equals(z) = true, thenx.equals(z) == true.
  • Consistent
    • multiple invocations x.equals(y) will consistently return true or consistently / always return false.
    • outcome wont change when operation is repeated.
  • Null comparison
    • For any non null reference x, x.equals(null) must return false.

Usually just use IDE to generate

Reference JournalDev & in28minutes

Java hashCode() method

used in collections like hashmap.
Default: derived from memory address of object used in heap
Used in hashing to decide which bucket object should be place in.
Therefore, hashCode() decides the effectiveness of Hashing.
Good hashing function will distribute objects evenly across different buckets.

hashCode Method Criteria

Good hashCode should have following proerties

  1. obj1.equals(obj2) == true --> obj1.hashCode() == obj2.hashCode()
  2. consistent. obj.hashCode() shuould return same value when run multiple times if values used in obj equals() have not changed
  3. if obj1.equals(obj2) == false --> obj1.hashCode MAY BE == obj2.hashCode().

Basically.

  • two unequal objects
    • might have same hashcode (hash collision)
  • two equals objects
    • must have same hashcode
      • if 2 equal objects have same hashcode, they can be placed in different buckets.
      • equals() function will never run on obj1 & obj2. obj2 will never replace obj1
      • hashmap can hold duplicate keys

Importance of equals() & hashCode()

It is a must to override / implement equals() & hashCode() method if you are using objects as hashma keys

Implementtation of equals() & hashCoe() follow these rules / contarct:

  1. if o1.equals(o2) --> o1.hashCode() == o2.hashCode()
  2. if o1.hashCode() == o2.hashCode() == true, o1.equals(o2) MAY NOT be true

So, if you implement equals method, its good practice to override hashCode so both methods follow contract.

however, this will only really come into play if you use objects as hashmap keys.

In hashing
equals():used to check if key exists in Hashmap
If wrongly implemented,

  • hashMap.get(obj) may return null, since wrong equals method cant tell that obj and key are equal
  • hashMap.put(obj1) may give "duplicate" keys. Since Java cant tell that obj1.equals(obj) and make obj1 override obj

hashCode(): decide which bucket obj will be placed in
If wrongly implemented:

  • equivalent objects can get placed in two different buckets.
    • since equals() only runs on 1 bucket, Java cant tell that obj already exists on HashMap
    • HashMap can store "duplciate" keys.

Reference: JournalDev

Java Objects Inheritance

process where one class aquires properties (methods & field) of another.
IS-A type of relationship
class : ChildClass extends ParentClass
interface : ChildClass implements Interfae1, Interface2

Sub Class: child class
Super class: parent class

Only 1 superClass
In Java,

  • child class can only extend 1 Parent Class
  • child class can implement >=1 Interface

Inheriting constructors
subclass inherits all memebers (fields methods, nested classes). but constructos are nont members & are not inhierted.
but constructor os superclass can be invoked from subclass super()

Private member inheritance
subclass does not inherit private members of parent class.
but subclass can use superclass's public / protected methods (eg. getter, setter) To access superclass's private fields.

During inheritance, only object of subclass created not super class

public class ChildClass extends ParentClass{
}
ChildClass test = new ChildClass()
Enter fullscreen mode Exit fullscreen mode

In this case, only 1 ChildClass object created no ParentClass object is created.

Reference: GeeksforGeeks & tutorialspoint & w3schools

Java == VS equals

==: compares if 2 references point to the same object
can apply == for every primitive type
equals(): overrides Object equals method.

String class

  • String pool ensures '==' works for string literals (references will point to same object / address in pool)
  • equals(): can check the value of the String object (String pool ensures == works for string literals) For String, can check value of object

Object class

java Object's default implemenetation of equals() is actually ==

public boolean equals(Object obj) {
  return (this == obj);
}

Enter fullscreen mode Exit fullscreen mode

For custom object to correctly implement the equals() method you MUST override the default implementation.

@Override
public boolean equals(Object o) {
  if (this == o) {
    return true;
  }
  if (o == null || getClass() !=  o.getClass()) {
    return false;
  }
  Simpson simpson = (Simpson) o;
  return age == simpson.age && weight == simpson.weight && name.equals(simpson.name);
}
Enter fullscreen mode Exit fullscreen mode

Reference: GeeksforGeeks & infoworld

How hashmap works internally

Hashamp works on principle of hashing- an algorithm to map object data to some representative integer value
load factor : entries / buckets (0.75)
capacity : number of buckets (16)
threshold : capacity * load factor (12)

In Java, threshold (default) is 12. that means after the 12th kay value air is added, capacity of hashmap will increase (double)

There are two main scenarios in a Java Hashmap

  1. constructing & putting items in (hashMap.put(key,value))
  2. retrieving items from hashmap via key (value = hashMap.get(key))

Constructing HashMap

  • 16 initial buckets
    • initial capacity = number of buckets = 16 (new HashMap<>())
  • default load factor is 0.75
  • default threshold = 12
    • default threshold = 16 * 0.75 = 12
    • rehash is performed on 12th key value pair insert
  • get hashCode of key
    • on hashmap.put(key,value), Java calculate hashCode() of key key.hashcode()
  • calculate bucket index (eg. 6)
    • since hashcode may be bigger than number of buckets
    • bitwise AND. hashCode AND number of bucket. to determine bucket index to insert key value pair in
  • Create Node object with key-value pair
    • Node like LinkeList

Since hashCodes are not unique, there will be a collision

Collision

  • get key1.hashCode()
  • get bucket index of key1 (eg. 6)
  • there is an object at index 6
  • check that inserted object and existing one are not equals
    • key.equals(key1) to check equality
    • if same: replace
    • else: collision
  • Connect node of key1 to node of key via linked list
    • keyNode.next = key1Node
    • both key-value pairs stored at index 6

alt text

As more and more objects are inserted, load factor increases. An increasing load factor means more complex get() / put() which will defeat the great advantage of hashmap (ie. O(1) gets and puts)

To keep load factor low, once treashold is exceed, rehashing occurs

Rehashing

  • Threshold (12) exceeded
  • after 12th insert -> rehashing
  • new Hashmp object created with double the old capacity (so 32 buckets)
  • repeat hashMap.put(key,value) on all elements of old hashMap.
    • all key-value pairs of old hashmap are placed into new hashMap
    • must recalculate their hashcode, index
    • then insert (linkedlist if collision)

Rehashing process is both space O(number of buckets) and Time consuming O(number of entries).
Therefore, a good balance must be struck between theshold and rehashing.

  • High threshold
    • rarely rehash
    • BUT: hashmap load factor is high
    • get and put will be complex
  • Low threshold
    • load factor of hashmap is low, will have efficient gets and puts
    • rehash very often -> waste time and space

Getting Item from HashMap

Load factor (& hashing function) will affect the complexity of get()
value = hashMap.get(key)

  • calculate hashCode of key
  • calculate index of key (eg. 6)
  • go to bucket of index
  • compare first Node with key sing equals()
    • node.equals(key)
  • if both are equal: return value
  • else go down linked list and check if node exists.

Reference: SO answer &&javaconceptoftheday && javarevisited && javacodegeeks && geeksforgeeks && baeldung

Adding Null key to hashmap

only one null key is permitted

  • hash calculation is not done
  • (key,value) pair always added to bucket 0

Reference: knpcode

HashSet internal implementation in Java

Hashset uses HashMap internally a dummy object is always added as value to backing HashMap.
HashSet class used to create collection that uses hash table for storage. It contains unique elements only.

Like HashMap,

  • Capacity = 16
  • load factor = 0.75
  • threshold = 0.75 * 16 = 12

add values
HashSet implementation, values are stored as hashmap keys. So set only contains unique elements.
In the underlying hashMap data, a dummy object is always added as value
hashSet.add(element);
underlying implementation is
hashMap.put(element,DUMMY)

get values
there are not values. just use key iterator to get keys
hashMap.keySet().iterator()

you can use hashMap to check if key is present in Set

remove values
same as removing items in hashmap

Reference: knpcode

ArrayList: Capacity VS Size

Capcity: maximum item list can hold before it can be resized
Size: number of itesm in the list.

List<Intger> test = new ArrayList(20);
test.add(1);
test.add(2);
test.add(3);
Enter fullscreen mode Exit fullscreen mode

In this case, capacity is 20, size is 3.

How ArrayList works Internally in Java

Arraylist is resizeable array implementation in java.
backed by an array

  • default capacity = 10
  • add(): ensure arraylist has required capacity.
    • if capacity exhausted
    • new array created with 50% more capacity
    • Arrays.copyOf() used to copy elements from old array to new array
  • remove(): remove element from array
    • elements shift to fill gap created by removed element

Reference: GeeksforGeeks & javatpoint & knpcode

Java Vector class

Vector is basically a thread safe arraylist.
Vector is synchronised, can use it in multiple threads.

Vector came first (before arraylist), in jdk since jdk 1.0

Synchronization has an overhead, so if you are not using multiple threads you can use a class without synchronization overhead.

How is stack implemented by Java internally?

Stack is LIFO (last-in-first-out) stack of objects
operations: push, pop, peek, empty, search

No items on stack creation.

implemented with underlying Vector class. Vector is a growable/dynamic array.

This could be due to backwards compatibility (see Quora source)

Reference: SO & Quora & java docs

Queue implementations in Java

Queue is a FIFO (first-in-first-out) data structure
operations: add, remove, element

In java, Queue is an interface.
There is no Queue class, it has to be implemented.

Implementations

  • LinkedList
  • PriorityQueue
    • based on heap data structure.
    • orders elemnts accoridng to order specified at construction time.
    • queue retrieval operations (poll, remove, peek) access element at head of queue.
    • if mutliple elements are tied for head of queue, tie is broken arbitarrily.

Map Implementation: HashMap, TreeMap, LinkedHashMap

All offer unique key-> value mappings & implement Map interface .
Difference is time guarantees & ordering of keys
HashMap: implemented as hash table & no ordering on keys or values.
TreeMap: implemented based on red-black tree structure, & ordered by the key.
LinkedHashMap: preserves the insertion order
Hashtable: synchronized HashMap.

  • HashMap
    • implemented by array of linked lists
    • O(1) look up & insertion
    • key orders -> arbitrary
  • TreeMap
    • implemented by Red-Black Tree.
    • O(logN) lookup & insertion
    • keys orders -> ordered, need to iterate through keys in sorted order
    • does not use hashing for storing key-pair values
  • Linked Hash
    • implemented doubly linked list between key-value pairs (on top hashmap implementation) that keeps track of insertion order
    • O(1) look up & insertion
    • keys orders -> insertion order

alt text
Source

  • LinkedHashmap operations
    • on top of hashmap, maintains an additional doubly-linked list to make it "aware" of ordering of key-value pairs

alt text
LinkedHashMap, internal implementation Medium article by Anmol Sehgal provides really good explanation of Linked hashamp

  • TreeMap internal workings
    • does not use hashing
    • sorts object kyes using red-black-tree algorithm alt text

Reference: oracle docs & GeeksforGeeks & DZone

Set Implementation: HashSet, TreeSet, LinkedHashSet

HashSet -> HashMap
TreeSet -> TreeMap

Reference: oracle docs & GeeksforGeeks

<a name="arraylist-linkedlist-java

">List Implementation: ArrayList VS LinkedList

both implement List
Arraylist: dyamically add & remove items, automatically resizes iteself, elemnts stored in contiguous memory
LinkedList: linear data strucutres, every element is seaparate object with data & address part. elements are linked using points & addresses.

alt text

alt text

  • manipulating data like removing data. (arraylist, underlying array everything must shift).

Referece: javatpoint & GeeksforGeeks & Baeldung

What is OOP

OOP is a programming prardigm that relies on the concepts of classes & objects.
Developer will strcuture code in terms of classes & objects

alt text

An alternate paradisn is procedural programming.

  • program is divided into samller parts called mathos
  • methods are basic entities in this technique
  • use methods for code reuability

OOP's benefits are

  • Clear structure for program
  • Reusable code, Java code is DRY (dont repeat yourself)
  • code easier to maintain modify & debug

OOP Pillar: Inheritance

Allows classes to inherit features of other classes.

  • mechanism to create new class by deriving old classs
  • Inheritance supports reusability
  • Represents IS-A relationship

alt text

Subclasses are IS-A relationship with super class.

public class SuperClass{}
public class SubClass **extends** SuperClass{}
Enter fullscreen mode Exit fullscreen mode

In Java, object class is super class of all objects.

References: javatpoint

Types of Inheritance

5 types

  • single
    • class inherit another class
  • multilevel
    • chain of inheritance
    • Corgi extends Dog, Dog extends Animal
  • heirarchical
    • 2 or more classes inherit single class
  • multiple (interface)
    • sub class has >1 super class
  • hybrid (interface)
    • mix of 2 or more of above types.
    • Since java calsses can't support mutiple inheritance, class cannot support hybrid inheritance.

alt text
image from simplesnippets

Why Java class cannot support multiple iheritace

  • reduce complexity / simplify language If sub class (C) inherits 2 classes (A,B). If A & B have same method (testMethod()) & method is called from subclass C.testMethod(). Does subclass implement method from A or B?

references: GeeksforGeeks & javatpoint

Inheritance in Java: OOP

Reference:https://www.geeksforgeeks.org/inheritance-in-java/#:~:text=important%20facts%20about%20inheritance%20in%20java%20

Inheritance in Java done via following:

  • key words
    • extends
    • implements
  • types of classes
    • class
    • interface
    • abstract class

Important facts

  • Default super class
    • besides object, every Java class has super class
    • every class is implicty subclass of objet class
  • only 1 super class
  • inherit construcotrs
    • cannot inherit super class constructors
    • can call super class constructors super() in subclass constructor
  • private memeber inheritance
    • cannot inherit private memebts (fields, methods, nested classes)
    • can access / modify private methodss via super class getter / setters (super.getProperty())

What can be done

  • Inherited fields
    • use them
    • Declare new field in subclass
  • inherited methods
    • use them
    • override them (use same method signature as superclass @Override)
    • Hide static methods (use same method signature as superclass static method)
    • declare new methods
    • write new subclass constructor that uses constructor of superclass (super())
    • Call to super() must be first statement in subclass

Extends VS Implements

alt text

OOP Pillar: Abstration

process of hiding implementation details & only showing functionality to the user

Abstractions lets developer focus on what an object does instead of how an object is doing it.

Implementation of function is hidden from user.

Reference: SO

OOP Abstraction in Java

Java has 2 ways to achieve abstraction

  1. Abstarct class (0-100%)
  2. Interface 100%
  • Abstract class
    • class declared as abstract
    • can have abstarct & non-abstarct methods
    • needs to be extended
    • child class must implement all its abstarct methods
    • cannot be instantiated
    • can have constructor, data members, abstract & non-abstarct methods.
abstract class Bike{  
  abstract void run();  
}  
class Honda4 extends Bike{  
  void run(){
  System.out.println("running safely");
}  
public static void main(String args[]){  
   Bike obj = new Honda4();  
   obj.run();   // running safely
 }  
}  
Enter fullscreen mode Exit fullscreen mode
  • Interface
    • can only have abstract methods (no method body)
    • Java 8 allows default & static methods in interface
    • allows multiple inheritance
    • class implementing interface must implement all methods declared in interface
    • cannot be instantiated
    • all fields are public static final alt text
interface Drawable{  
  void draw();  
  default void msg(){
    System.out.println("default method");
  }  
  static int cube(int x){
    return x*x*x;
  }
}  
class Rectangle implements Drawable{  
  public void draw(){
    System.out.println("drawing rectangle");
  }  
}  


Drawable d=new Rectangle();  
d.draw();  // drawing rectangle 
d.msg();  // default method
Drawable.cube(3); // 27
Enter fullscreen mode Exit fullscreen mode

Reference: javatpoint & [javatpoint-interface]

Abstarct Class VS interface

alt text
From oracle docs

When to use:

  • Abstract Class

    • share code among closely related classes*
    • expect classes extending abstract class have many common methods / fields / require access modifiers other than public (abstract classes can declare non-public methods & fields)
    • declare static or non-final fields
  • Interface

    • unrelated classes will implement interface
    • use multiple inheritance
    • expect API to not change for a while (if change 1 interface method all classes must change)

Reference: techvidvan

OOP Pillar: Encapsulation

OOP technique of wrapping data & code in to achieve data hiding.
technique is
Data hiding: Unauthorized users should not have access to / modify data
Benefits:

  • flexibility: can decide which variables have read/ write priviledges
  • control: class can control what is stored in fields (is setter is bad input, reject it)

alt text

How does it achieve data hiding?

  • wrap data (vairables / fields) & code that manipualtes data (methods) together in a single unit
  • variables are hidden from other classes
  • variables are onlt accessed through methods in their current class alt text

Code now becomes like a "protective shield" that prevents data from being acessed by unauthorize users / means.

Reference: Educative & javatpoint & GeeksforGeeks & tutorialspoint

Encapsulation in Java

Encapsulation in Java is achieved by

  1. declare fields of class as private
  2. provide public setter an getter methods & modify and fields
public class EncapTest {
   private int age;

   public int getAge() {
      return age;
   }

   public void setAge( int newAge) {
      age = newAge;
   }
}
Enter fullscreen mode Exit fullscreen mode

Tight Encapsulation

Class has only private variables / fields

Reference: SO

OOP Pillar: Polymorphism

ability of object to take on many forms.

  • Compile-time Polymorphism / Static polymorphism
    • method overloading
  • Runtime Polymorphism / Dynamic method dispatch
    • method overriding In Java, inheritance allows for polymorphism (method overriding)
  • Compile-time polymorphism (

    • static bining / early binding / overloading
    • object bound with their functionality at compile time
    • call is resolved by the compiler
    • Fast execution: method to be executed known early (at compile time)
    • less flexible/u>: all things execute at compile time
  • Run-time polymorphism

    • dynamic binding / late binding / overriding
    • object bound with functionality at run time
    • method invocation is determined by JVM not the compiler
    • Slow execution: method to be be executed only known at runtime
    • more flexible all things execute at runtime

alt text
From: GeeksforGeeks

Polymorphism: Method Overloading

Allows a class to have more than 1 method with:

  • same name
  • different number & types of argument list At time of compilation, method calls get resolved by compiler (javac). Also known as: compile-time polymorphism / early binding

There are 2 ways this can be performed

  1. changing number of arguments
  2. changing the data type
public void display(String info){
  System.out.println("String into");
}

// method overloading - change data type
public String display(int info){
  System.out.println(info);
  return "result";
}

public void display(String info1,String info2){
  System.out.println("2 information string");
}
Enter fullscreen mode Exit fullscreen mode

When call display method compiler display results based on the arugments dev pass.

  • if argument is int
    • call display(int)
  • argument is string
    • call display(string)
  • type promotion can be performed (implicitly) if no matching type is found and if there is no ambiguity.

alt text

Type Promotion Example
if not matching data types found, one type promoted to another.

public void sum(int a long b){
  System.out.println(a+b);
}

// second argment (int literal) will be promoted to long. 
sum(20,20); // 40
Enter fullscreen mode Exit fullscreen mode

If there is ambiguity,

  • no matching type aguments in metho
  • each method promotes simliar number of arguments
public void sum(int a,long b){
  System.out.println("a method invoked");
}

public void sum(long a,int b){
  System.out.println("b method invoked");
}

//ambiguity
sum(20,20); // Compile Time Error
Enter fullscreen mode Exit fullscreen mode

Now there is amiguity, both methods promote simliar number of arguments.

Benefits:

  • increase readability of program
    • no need to create & remember different names for functions doing the same thing.

Method Overloading Conditions
CANNOT

  • not possible by changing return type of method only
    • if only change return type but ethod signature remains same, there is ambiguity, which method should be called?
  • can't overload methods that differ only by static keyword
    • number of parameters, type of parameters & method name is same
    • same method signature -> not overlaoding CAN
  • can overload main() method
    • main() method usually received string array as arguments.
    • but can overload main()method to receive no arguments / different arugments
  • method overloading with type promotion
    • one type can be promoted to another implicitly if not matching datatye found.
    • one type cannot be de-promoted implicitly.
  • can overload static method
    • can have >=2 static method with same name but difference in input parameters.

reference: javatpoint & GeeksforGeeks

Polymorphism: Method Overidding

allows subclass / child class to provide specific implementation of method that is already provided by by one of its super classes or parent classes
Subclass methods must have

  • same name
  • number & type of parameters
  • retur type JVM does the job of method resolution --> Runtime polymorphism Type of referred object determines which version of an overriden method will be executed
class Base {
  public void show(){}
}

class Derived extends Base {
  // method overriding
  public void show(){}
}
Enter fullscreen mode Exit fullscreen mode
Derived der = new Derived();
der.show();
Enter fullscreen mode Exit fullscreen mode

JVM first checkls if child class (Derived) has provided any implementation to method (show).
yes -> call derived overriden method,
no -> call parent method

Base obj = new Derived();
obj.show();
Enter fullscreen mode Exit fullscreen mode

reference if of Base type, however object is still of Derived type.
Method resolution takes place at runtime.
show method of Derived class is called.

Derived obj = new Base(); // not valid
Enter fullscreen mode Exit fullscreen mode

This is not valid.
Important
Important
type of referred object etermine which version of overidden method will be executed NOT typoe of reference variable.
Runtime object determines which method will be called --> overiding = runtime polymorphism

Rules

  • MUST have same retur type or at least subtype of parent's return type Exception Handling
  • super class overriden method does not throw exception
    • sub class overridding method can only throw unchecked exception (i.e. exceptions that are not checked at ompile time)
  • super class overridding method throws exception
    • sub class overriding metho can only throw same subclass exception. CAN
  • override access-modifiers
    • can allow more but not less access (eg. protected instance method can be made public but not privde in sub class)
  • final methods cannot be overidden
    • final keyword prevents overriding
  • call parent class method in overridding method
    • super.method()
  • can override abstarct method
    • abstarct methods in interface / abstarct class are menat to be overidden in derived class
  • can override synchronied / strictfcp method CANNOT
  • static methods cannot be overridden
    • static method bound to class not object
    • static method with saae method signature in subclass is method hiding NOT method overidding.
  • cannot override main method
    • main metod is static
  • private methods cannot be overriden
    • private methods not inherited
    • private methods bonded during compile time
  • cannot override constructor
    • parent & child constructor can never have same name
    • constructors are not inhierited

Reference: GeeksforGeeks & javatpoint

Overriding VS Hiding (static methods)

static methods cannot be overidden. But they can be hidden.
When child class has same static method as parent class. Static method hides another static method.
Difference Overriding gives run-time polymorphism, hiding does not.

Code example and explanation taken from coderanch:

class Foo {
    public static void classMethod() {
        System.out.println("classMethod() in Foo");
    }

    public void instanceMethod() {
        System.out.println("instanceMethod() in Foo");
    }
}

class Bar extends Foo {
    public static void classMethod() {
        System.out.println("classMethod() in Bar");
    }

    public void instanceMethod() {
        System.out.println("instanceMethod() in Bar");
    }
}

class Test {
    public static void main(String[] args) {
        Foo f = new Bar();
        f.instanceMethod(); // instanceMethod in Bar
        f.classMethod(); // classMethod in Foo
    }
}
Enter fullscreen mode Exit fullscreen mode

instanceMethod(overriding): JVM finds actual class of the instance f at run-time and determines which method to run. f is declared as Foo however class created is actually Bar. At run-time, JVM find that f is Bar instance and calls instanceMethod in Bar.

classMethod(hiding): class/static method. JVM wont expect to need an actual instance to invoke method. At compile-time compiler looks at declared type (Foo) of reference to decide which method to call.

Therefore static methods do not have run-time polymorphism.

alt text

References: Stack Overflow & CodeRanch

OOP Java: Association

Association is relation between 2 separate classes which establishes through their objects. Can be

  • one-to-one
  • one-to-many
  • many-to-one
  • many-to-many Composition & aggreagation are 2 forms of association

alt text

Aggregation

special form of assocation

  • Has-A relationship
  • unidirectional
  • parent can exist without the child & vice-versa
public class Foo {
  private Bar bar;
  Foo(Bar bar) {
    this.bar = bar;
  }
}
Enter fullscreen mode Exit fullscreen mode

If Foo dies, object Bar can still "live".

alt text

Composition

restricted form of aggreagation, 2 entities are highly dependent on each other

  • *part-of-realtionship
  • child object cannot exist without parent entity
  • lifecycle of child is controlled by parent that owns it
public class House {
   private Room room;
   public House() {
       // without a house there can be no room, if house deleted, room is also deleted
       room = new Room();
   }
}
Enter fullscreen mode Exit fullscreen mode

alt text

Reference: GeeksforGeeks & infoworld

OOP Java: Coupling

measure of how much class is dependent on other classes
There should be iminmal dependencis -> low coupling

OOP Java: Cohesion

measure of how related responsibilitie of class are
class must be highly cohesive (responsibilties shuold be highly related to one another)

Exceptions handled

Java Exception Handling frameowork handles runtime exceptions only. Compile time exceptions must be handled by developer or else code wont run

Reference: JournalDev

Exception Handling: keywords

  • throw -throws -try-catch -finally
  • throw
    • used inside function / block of code
    • to explicitly throw an exception in the rpgoram
  • throws
    • used in method signature
    • declare exception that might get thrown by method & method will not be handling it.
  • try-catch
    • code block for excpetion handling in code
    • can have multiple catch blocks with a try block -can be nested
  • try
    • start of block
  • catch
    • end of try block to handle exceptions
    • required parameter that should be of type Exception
    • java 7 automatic resource management (catch many resource in 1 catch block)
    • catch(IOException | SQLException ex){}
  • finally
    • optional
    • always gets executed wheter exception occured or not
    • onlt NOT executed if exception thrown in finally or if JVM crashes in between (System.exit())
    • can be used with try catch block
    • since exceptions halts process of execution, may have some resources open that will not get closed, close them in finally block

Java Exception Hierarchy

When exception is raise, an exception object is geting created.
Throwable is parent class of Java Exceptions Hierarchy & has 2 chid objects

  • Error
  • Exceptions
    • checked exceptions
    • runtime exceptions

Java Exceptions are hierarchichal & inheritance used to categorize different types of exceptions

alt text

  • Errors
    • not possible to anticipate or recover from them (fatal)
      • hardware failure
      • OutOfMemoryError
      • StackOverflowError
  • Exceptions
    • errors that can be anticiapted & recovered from
  • Checked Exceptions
    • exceptions checked at compile time
    • sually occures when interacting with outside resources
    • FileNotFoundException
    • IOException
  • Runtime Exception
    • exceptions not checked at compile time
    • usually due to bad programming / mistakes
    • get element from array but give wrong index
    • ArrayIndexOutOfBound, Arithemetic Exception

Java Unchecked VS Runtime Exception

CheckedException:

  • mandatory to provide try-catch / try-finally block
  • force by compiler
  • dealing with outside resoruces / networks Runtime exception: not mandatory
  • occur during runtime
    • programming errors
  • Checked Exception
    • if not handled, will result in compile time errors
      • either handle with try-catch/ try-finally block or specify method uses throws
    • usually error scenarios outside immediate control of program
    • usually interacting with touside resources /networks
      • data base / network
    • eg.ClassNotFoundException, IOException, SQLException, FileNotFound
  • RuntimeException
    • not checked by compiler
    • will occur once buggy code is executed
    • method not forced to delared unchecked exception thrown
    • eg. ArithmeticExcetion, ArrayStoreException, NullPointerException

Extend from CheckedExcetion or Runtime Excpetion?
Checked Exception

  • method likely to fail
  • Checked Exception to ensure alternalte processing in case of failure (enforces proper error handling) Runtime Exception

BUT

  • can make code ugly (lots of boilerplate code)

reference: GeeksforGeeks VS java67 & javadocs

Java Exception Class Methods

all methods depend on parent Throwable class

  • String getMessage()
  • String getLocalizedMessage()
  • synchronized Throwable getCause()
  • String toString()
  • void printStackTrace()
  • getMessage()
    • message String of Throwable
    • message provided when creating exception through constructor
  • getLocalisedMessage()
    • subclass can override it to provide locale-specific message to calling program
  • getCause()
    • cause of exception or null if cause is unnown
  • toString()
    • name of throwable class & localised message
  • printStackTarce()
    • prints the stack trace information to the standard error stream
    • is overloaded and can pass PrintStream or PrintWriter as an argument to write the stack trace information to file or stream

Java Exception Handling Criteria

ALLOWED

  • finally can still be executed if try & catch have return statements
  • try without catch is allowed (try{}finally{})

NOT ALLOWED

  • try without catch & without finally

Java Exception Handling Best Practice

  • Use Specific Exceptions
    • dont throw base exception class
  • throw early / fail fast
    • throw exception as early as possible
  • catch late
    • throw exception to caller
    • let caller decide how to handle & caller can get notification for exception
  • closing resources
    • close all resources i finally block
    • java 7 try-with-resources block
    • eg. try (Scanner scanner = new Scanner(new File("test.txt"))) {scanner.doSomething()}
  • log exceptions
    • log exception messages when throwing exceptions
  • single catch block for multiple exceptions
    • catch(SQLException|AnotherException ex){}

Reference: JournalDev

UML Class Diagram

Designing the class
alt text

Association

very generic term
one class used functionalities provided by another class
alt text

Composition

part-of
alt text

Aggregation

one object "owns" another object but child can exist without parent
alt text

Multiplicty
alt text

Generalization / Inheritance / Abstraction
alt text

source

UML Sequence Diagram

denote how objects and classes with code interact with each other
show sequence of the events

alt text

OOP: Design Patterns

basket of pre designed solutions / blueprints to common patterns in OOP or to solve given design problem in code.

Creational: creating objects
Structural: composition of classes & objects which form larger structures
Behaviour: responsibility & interaction between objects

Singleton Design Pattern

restricts instantiation of class to one. Ensure only 1 instance of class exists in JVM.
Used for: logging, drivers object, cahcing & thread pool.
Implementation

  1. private construtor to restrict instantiation of class from other classes
  2. private static variable of same class that is only instance of class
  3. public static method getInstance() returning instance of class, so other classes can get instance of singleton

Techniques:

  • Eager initialization - create singleton BEFORE its used
    • public static final SingletonClass instance = new SingletongClass()
    • use static block
  • Lazy Initlialization
    • creates instance in getInstance() method. can cause issues in multithreaded environment
  • Thread Sage singleton (for laxy initialization)
    • make getInstance() method synchronized so only 1 thread executes this method at a time
  • use Enum to declare singleton
    • Java ensures any enum value only instantiated once. does not allow lazy initialization. public enum EnumSingleton{INSTANCE;}
  • Serialization & singleton
    • implement readResolve() method. When implement serializable interface, when deserialize singleton class, new instance of object is created. protected Object readResolve() {return getInstance()}

alt text

Reference: vainolo & journalDev

Factory Design Pattern

define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate
Responsibility of instantiation is on factory class not client program.

alt text
alt text

Implementation

  • super class (Computer) can be interface , abstart class or normal class
  • Factory class can be singleton or can keep the method returning classes (getComputer) as static.
    • very troublesome to keep instantiating factory clas
  • based on input parameter, different subclass created & returned
public class ComputerFactory {

    public static Computer getComputer(String type, String ram, String hdd, String cpu){
        if("PC".equalsIgnoreCase(type)) return new PC(ram, hdd, cpu);
        else if("Server".equalsIgnoreCase(type)) return new Server(ram, hdd, cpu);

        return null;
    }
}
Enter fullscreen mode Exit fullscreen mode

Advantage

  • remove instantiation of actual classes from client code
  • layer of abstraction between implementation classes(PC & Server) & client code (ComputerFactory

Abstract Factory
Abstarct factory is like a factory of factories.

Reference: javatpoint& JouralDev & tutorialspoint

Decorator Design Patterns

Add new features to existing object with changing its structure
Decorate class wraps original class & provides additional functionality, keeping class methods signature intact

  • uses abstract classes or interface with **composition* to implement*

alt text

alt text

Decorator class implements HAS-A relationship with component interface. Concrete Decorators will extend base decorator functionality & modify component behaviour.

// Component Implementations
public class BasicCar implements Car {

    @Override
    public void assemble() {
        System.out.print("Basic Car.");
    }

}

// Decorator
public class CarDecorator implements Car {

    protected Car car;

    public CarDecorator(Car c){
        this.car=c;
    }

    @Override
    public void assemble() {
        this.car.assemble();
    }

}

// Concrete Decorator
public class SportsCar extends CarDecorator {

    public SportsCar(Car c) {
        super(c);
    }

    @Override
    public void assemble(){
        super.assemble();
        System.out.print(" Adding features of Sports Car.");
    }
}
public class LuxuryCar extends CarDecorator {

    public LuxuryCar(Car c) {
        super(c);
    }

    @Override
    public void assemble(){
        super.assemble();
        System.out.print(" Adding features of Luxury Car.");
    }
}

// Testing Decorator Program
Car sportsCar = new SportsCar(new BasicCar());
sportsCar.assemble(); 
// Basic Car Adding features of Sports Car
        System.out.println("\n*****");

Car sportsLuxuryCar = new SportsCar(new LuxuryCar(new BasicCar())); sportsLuxuryCar.assemble(); 
// Basic car. Adding features of Luxury Car. Adding Features of SportsCar. 
Enter fullscreen mode Exit fullscreen mode

Reference: Baeldung & tutorialspoint & JournalDev

Flyweight Design Pattern

factory which recycles created objects by storing them after creation. Existing object is returned otherwise new one created.
Flyweight objects must be immutable, any operation on state must be performance by factory.
Benefits

  • decrease memory footprint
  • increase performance

When to use

  • number of object to be created by application should be huge
  • object creation heavy on memory & can be time consuming
  • flyweight object must be divided into intrinsic & extrinsic. Intrinsic properties make object nuique, extrinsic properties are set by client code & used to perform different operations.

Reference: Baeldung & tutorialspoint & JournalDev

Adapter Design Pattern

act as connector between 2 incompatible interfaces that otherwise cannot be connected directly.
2 implementations

  • class adapter
    • uses inheritance & extends adaptee interface
    • single class called adaptor between 2 incompatible interfaces
  • object adapter
    • uses composition & adapter contains adaptee object.
    • wraps around class, allowing 2 classes / interface to work together without changing any code on either side.

Object Adapter
alt text

  • Client can only see target
  • adapter class implements target interface & provides implementation for Request()
  • adapter is composed with adaptee

Process

  • Client makes call to adapter
  • adapter does conversion
  • makes rqeuired call to adaptee
public class SocketObjectAdapterImpl implements Targer{

//Using Composition for adapter pattern
    private Adaptee sock = new Adaptee ();

    @Override
    public Volt get120Volt() {
        return sock.getVolt();
    }

    @Override
    public Volt get12Volt() {
        Volt v= sock.getVolt();
        return convertVolt(v,10);
    }

    @Override
    public Volt get3Volt() {
        Volt v= sock.getVolt();
        return convertVolt(v,40);
    }

    private Volt convertVolt(Volt v, int i) {
        return new Volt(v.getVolts()/i);
    }
}
Enter fullscreen mode Exit fullscreen mode

Class Adapter
alt text

  • adaptor implements target
  • inherits adaptee

Process

  • Client makes call to adapter
  • adapter DOES NOT delegate request to adaptee
  • adapter uses inherited method (SpecificRequest()) from adaptee to handle specific request
//Using inheritance for adapter pattern
public class SocketClassAdapterImpl extends Adaptee implements Targer{

    @Override
    public Volt get120Volt() {
        return getVolt();
    }

    @Override
    public Volt get12Volt() {
        Volt v= getVolt();
        return convertVolt(v,10);
    }

    @Override
    public Volt get3Volt() {
        Volt v= getVolt();
        return convertVolt(v,40);
    }

    private Volt convertVolt(Volt v, int i) {
        return new Volt(v.getVolts()/i);
    }

}
Enter fullscreen mode Exit fullscreen mode

alt text

JournalDev & GeeksforGeeks

Observer Design Pattern

one-to-many dependency between objects so when 1 object (subject) changes state, all of its dependents (observers) are notified & updated automatically.

eg. wishlist item is out of stock, tell website to notify you when it is in stock.
alt text

// subject
public interface Subject {

//methods to register and unregister observers
  public void register(Observer obj);
  public void unregister(Observer obj);

//method to notify observers of change
  public void notifyObservers();

//method to get updates from subject
  public Object getUpdate(Observer obj);
}

// object
public interface Observer {

//method to update the observer, used by subject
public void update();
// observers will print updated subject in this method

//attach with subject to observe
public void setSubject(Subject sub);
}

public class MyTopic implements Subject {

    private List<Observer> observers;
    private String message;
    private boolean changed;
    private final Object MUTEX= new Object();

    public MyTopic(){
        this.observers=new ArrayList<>();
    }
    @Override
    public void register(Observer obj) {
        if(obj == null) throw new NullPointerException("Null Observer");
        synchronized (MUTEX) {
        if(!observers.contains(obj)) observers.add(obj);
        }
    }

    @Override
    public void unregister(Observer obj) {
        synchronized (MUTEX) {
        observers.remove(obj);
        }
    }

    @Override
    public void notifyObservers() {
        List<Observer> observersLocal = null;
        //synchronization is used to make sure any observer registered after message is received is not notified
        synchronized (MUTEX) {
            if (!changed)
                return;
            observersLocal = new ArrayList<>(this.observers);
            this.changed=false;
        }
        for (Observer obj : observersLocal) {
            obj.update();
        }

    }

    @Override
    public Object getUpdate(Observer obj) {
        return this.message;
    }

    //method to post message to the topic
    public void postMessage(String msg){
        System.out.println("Message Posted to Topic:"+msg);
        this.message=msg;
        this.changed=true;
        notifyObservers();
    }

}

//create subject
MyTopic topic = new MyTopic();

//create observers
Observer obj1 = new MyTopicSubscriber("Obj1");
Observer obj2 = new MyTopicSubscriber("Obj2");
Observer obj3 = new MyTopicSubscriber("Obj3");

//register observers to the subject
topic.register(obj1);
topic.register(obj2);
topic.register(obj3);

//attach observer to subject
obj1.setSubject(topic);
obj2.setSubject(topic);
obj3.setSubject(topic);

//check if any update is available
obj1.update(); // Obj1:: No new message

//now send message to subject
topic.postMessage("New Message");

// OUTPUT
Message Posted to Topic:New Message
Obj1:: Consuming message::New Message
Obj2:: Consuming message::New Message
Obj3:: Consuming message::New Message
Enter fullscreen mode Exit fullscreen mode

Mutex subject in code snippet is used for locks

Sequence Diagramm
alt text

Reference: vogella & JournalDev & Baeldung & tutorialspoint

Strategy Design Patterns

class behaviour or algorithm can be changed at runtime.
eg. Collections.sort()
2 ways:

  • interface & implement many times
    • start with interface which is used to apply an algorithm
    • implement it multiple times for each possible algorithm
  • Java 8 & lambdas
    • use lambda in place of anonymous inner type

alt text

Interface & Implementations

// Startegy interface
public interface Strategy {
   public int doOperation(int num1, int num2);
}

// Startegy concrete classes
public class OperationAdd implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 + num2;
   }
}
public class OperationSubstract implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}
public class OperationMultiply implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 * num2;
   }
}

// use context to call & execute startegy interface
public class Context {
   private Strategy strategy;

   public Context(Strategy strategy){
      this.strategy = strategy;
   }

   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}

Context context = new Context(new OperationAdd());      
      System.out.println(context.executeStrategy(10, 5)); // 15

context = new Context(new OperationSubstract());        
      System.out.println(context.executeStrategy(10, 5)); //5 

context = new Context(new OperationMultiply());     
      System.out.println(context.executeStrategy(10, 5)); // 50
Enter fullscreen mode Exit fullscreen mode

Using Java Lambdas
Java 8 can create static methods in interfaces

public interface Discounter {
    BigDecimal applyDiscount(BigDecimal amount);

    static Discounter christmasDiscounter() {
        return amount -> amount.multiply(BigDecimal.valueOf(0.9));
    }

    static Discounter newYearDiscounter() {
        return amount -> amount.multiply(BigDecimal.valueOf(0.8));
    }

    static Discounter easterDiscounter() {
        return amount -> amount.multiply(BigDecimal.valueOf(0.5));
    }
}
Enter fullscreen mode Exit fullscreen mode

Sequence Diagram
alt text

Reference: Baeldung & tutorialspoint & JournalDev

State Design Patterns

allows object to change its behaviour (during run time) when the internal state of the object changes.

  • used when: object depends on its state & behaviour must be changed during run time depending on its internal state. Implementation allow object to change its behaviour without changing its class

alt text
Context object will change its behaviour based on its internal state.
Context object will have an associated state which can change during program execution
Context will delegate behaviour to state implementation.

Example: TV remote can be on or off

// Staet interface 
public interface State {
    public void doAction();
}

// State implementations
public class TVStartState implements State {

    @Override
    public void doAction() {
        System.out.println("TV is turned ON");
    }

}

public class TVStopState implements State {

    @Override
    public void doAction() {
        System.out.println("TV is turned OFF");
    }

}

public class TVContext implements State {

    private State tvState;

    public void setState(State state){
        this.tvState=state;
    }

    public State getState() {
        return this.tvState;
    }

    @Override
    public void doAction() {
        this.tvState.doAction();
    }

}


TVContext context = new TVContext();
State tvStartState = new TVStartState();
State tvStopState = new TVStopState();
            context.setState(tvStartState);
context.doAction(); // TV is turned on  
        context.setState(tvStopState);
context.doAction(); // TV is turned off
Enter fullscreen mode Exit fullscreen mode

alt text

Reference: Baeldung & tutorialspoint & JournalDev & DZone

Top comments (3)

Collapse
 
john4650hub profile image
JohnDelvin

Great post

Collapse
 
rohit34780911 profile image
rohit
Collapse
 
sjain76 profile image
sushant singh

Java has been the go-to language for a really long time in this field. Despite the fact that it probably won't be very useful in IOS improvement, it is helpful while working with android studio.