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
- Language
- Execution System
Java syntax
- Basics
- Modifiers (Access & Non-access modifiers)
- Non access modifiers
block
Wrapper Class
- immutable
- why wrapper classes
- constructor VS valueOf
- Autoboxing & Unboxing
-
Typecasting
- implicit/widening
- explicit/narrowing
Strings
- Implements CharSequence Interface
- immutability
-
where are strings stored in memory
- String pool
- heap & stack
- String Interning
- how many objects created in new String()
- String (+) is bad in loop
- String VS StringBuffer
- StringBuilder VS StringBuffer
Objects class / Java Objects basics
-
What is a class
- state
- behaviour
- What is an object
- == VS equals()
- super class of every class
- toString metho
- equals() method
- hashCode() method
- importance of equals() & hashCode()
- instanceOf VS getClass
- Object class Inheritance
- [constructors]
Data Structure Implementations( knpcode.com has really good tutorials and write ups for DS implementations )
- HashMap
-
how hashmap works internally
- 16 initial buckets, 0.75 load factor, threshold of 12
- hashCode for bucket index calculation
- LinkedList for collision
- equals() to compare keys
- rehashing when meet threshold, buckets are doubled
- null key added
-
how hashmap works internally
- HashSet
-
hashset internal implementation in Java
- implemented with hashmap
- set element are hashmap keys
- all hashmap values are a dummy object.
-
hashset internal implementation in Java
- ArrayList
- capacity VS size
-
how arraylist works internally
- implemented with array
- initial capacity of 10
- grows 50% when no space
- Vector
-
Java vector class
- thread safe arraylist
-
Java vector class
- Stack
-
how is stack implemented by java
- empty on creation
- dynamic array NOT linkedlist
-
how is stack implemented by java
- Queue
-
queue implementations in Java
- interface not a class
- implemented by PriorityQueue & LinkedList
-
queue implementations in Java
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
- What is OOP
- 4 Pillars of OOP
-
inheritance
- Types of Inheritance
- single inheritance
- multilevel
- multiple
- hierarchical
- hybrid
- inheritance-in-java
- extends VS implements
- Abstraction
-
Encapsulation
-
encapsulation in java
- getters & setters
- tight encapsulation
-
encapsulation in java
- Polymorphism
-
inheritance
- Abstraction VS Encapsulation (https://stackoverflow.com/a/51304341)
- Relationships (https://www.c-sharpcorner.com/UploadFile/3614a6/is-a-and-has-a-relationship-in-java/)
- IS-A relationship (inheritance)
- HAS-A relationship (composition)
- Other concepts
-
Association
- association (2 classes have a link, need to communicate between them)
- aggregation (weak association, child can exist independently of the parent)
- composition (strong association, child cannot exist independent of parent)
- association VS aggregation VS composition
- Coupling
- Cohesion
-
Association
Java Exception Handling (JournalDev Exception Handling article primarily used as reference for this section )
- runtime exceptions
-
exception handling keyword
- try
- catch
- finally
- Java Exception Hierarchy
- Exception Class Methods
- Excpetion Handling criteria
- Exception Handling Best Practice
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
- Creational
- singleton
- factory & abstract factory
- Builder
- Structural
- Behavioural
MultiThreading
- thread VS process
- Threads & Runnable
- Thread VS Runnable
- keywords
- synchronized
- volatile
- wait()
- notify()
- notifyAll() https://howtodoinjava.com/java/multi-threading/wait-notify-and-notifyall-methods/ https://dzone.com/articles/difference-between-volatile-and-synchronized-keywo https://stackoverflow.com/a/3519736 https://howtodoinjava.com/java/multi-threading/java-runnable-vs-thread/ https://stackoverflow.com/a/15471504
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;
VSnum =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)
- create heirachy via class definition
- 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:
- primitive data type
- static keyword
- wrapper class
To fulfill pure OOP, language must satisfy all 7 conditions:
- Encapsulation / Data Hiding
- inheritance
- polymorphism
- abstraction
- All predefined types are objects
- All user defined types are objects
- 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
- primitives are not objects
- 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
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
}
- Run program -> load runtime classes to Heap space
- main() method found at line 1, runtime create stack mem to be used by main() method thread. Whenever new object created,
- object created in heap memory
- stack memory contains the reference for it.
- when new method called -> new block created on top of stack (LIFO)
- String, reference in stack mem -> reference points to String pool in heap space
- when method (foo())terminates, stack becomes free (stack mem created for function destroyed)
- move to next program below (main())
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
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
}
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)
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
}
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);
- 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
- Method: synchronised. thread gets lock on object on entering method
- thread entering synchronized method must get lock of the object in which method is define. cannot instantiate abstract class so no object with lock. https://javagoal.com/abstract-method-in-java/ https://stackoverflow.com/a/12805823
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
- 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;
}
}
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
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;
}
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
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");
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++;
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
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
- Explicit/narrowing
- assigning larger type to a smaller type
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
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
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
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
- String literal -> String constant pool (in heap)
- 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.
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
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
Reference: GeeksforGeeks & DZone
Number of Objects created in String Construction
String str = new String("Cat");
Either 1 or 2 objects created
- String literal
- "Cat" String created in String pool (if does not exist)
- String
str
object- String object created on heap Reference: JournalDev & SO
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;
}
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();
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:
- state
- 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.
- toString
- hashCode
- equals
- 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
- be public
- return type: String
- 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
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
- obj1.equals(obj2) == true --> obj1.hashCode() == obj2.hashCode()
- consistent. obj.hashCode() shuould return same value when run multiple times if values used in obj equals() have not changed
- 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
-
must have same hashcode
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:
- if o1.equals(o2) --> o1.hashCode() == o2.hashCode()
- 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()
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);
}
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);
}
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
- constructing & putting items in (
hashMap.put(key,value)
) - retrieving items from hashmap via key (
value = hashMap.get(key)
)
Constructing HashMap
- 16 initial buckets
- initial capacity = number of buckets = 16 (
new HashMap<>()
)
- initial capacity = number of buckets = 16 (
- 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 keykey.hashcode()
- on
- 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
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 consumingO(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);
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
- LinkedHashmap operations
- on top of hashmap, maintains an additional doubly-linked list to make it "aware" of ordering of key-value pairs
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
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.
- 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
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
Subclasses are IS-A relationship with super class.
public class SuperClass{}
public class SubClass **extends** SuperClass{}
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.
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 subclassC.testMethod()
. Does subclass implement method from A or B?
references: GeeksforGeeks & javatpoint
Inheritance in Java: OOP
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
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
- Abstarct class (0-100%)
- 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
}
}
- 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
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
Reference: javatpoint & [javatpoint-interface]
Abstarct Class VS interface
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)
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
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
- declare fields of class as private
- 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;
}
}
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
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
- changing number of arguments
- 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");
}
When call display
method compiler display results based on the arugments dev pass.
- if argument is int
- call
display(int)
- call
- argument is string
- call
display(string)
- call
- type promotion can be performed (implicitly) if no matching type is found and if there is no ambiguity.
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
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
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(){}
}
Derived der = new Derived();
der.show();
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();
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
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
}
}
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.
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
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;
}
}
If Foo dies, object Bar can still "live".
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();
}
}
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
-
Errors
- not possible to anticipate or recover from them (fatal)
- hardware failure
- OutOfMemoryError
- StackOverflowError
- not possible to anticipate or recover from them (fatal)
-
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
- either handle with try-catch/ try-finally block or specify method uses
- usually error scenarios outside immediate control of program
- usually interacting with touside resources /networks
- data base / network
- eg.
ClassNotFoundException
,IOException
,SQLException
,FileNotFound
- if not handled, will result in compile time errors
- 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
Association
very generic term
one class used functionalities provided by another class
Composition
Aggregation
one object "owns" another object but child can exist without parent
Generalization / Inheritance / Abstraction
UML Sequence Diagram
denote how objects and classes with code interact with each other
show sequence of the events
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
- private construtor to restrict instantiation of class from other classes
- private static variable of same class that is only instance of class
- 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
- creates instance in
- Thread Sage singleton (for laxy initialization)
- make
getInstance()
methodsynchronized
so only 1 thread executes this method at a time
- make
- use Enum to declare singleton
- Java ensures any enum value only instantiated once. does not allow lazy initialization.
public enum EnumSingleton{INSTANCE;}
- Java ensures any enum value only instantiated once. does not allow lazy initialization.
- Serialization & singleton
- implement
readResolve()
method. When implement serializable interface, when deserialize singleton class, new instance of object is created.protected Object readResolve() {return getInstance()}
- implement
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.
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;
}
}
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*
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.
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.
- 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);
}
}
- 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);
}
}
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.
// 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
Mutex subject in code snippet is used for locks
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
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
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));
}
}
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
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
Reference: Baeldung & tutorialspoint & JournalDev & DZone
Top comments (3)
Great post
stackoverflow.com/questions/688636...
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.