Java 1
Java 1
2 types of memory:
1. STACK -> stores temporary variables
Store temporary variables and separate memory block for methods.
Store primitive data types.
Store Reference of the heap objects.
Types of reference:
- Strong reference : ClassName obj=new ClassName();
When GC, is invoked it is not deleted.
- Weak reference : ClassName<Person> obj=new ClassName<Person>(new Person());
When GC is invoked, it may be deleted.
Example
- Soft reference : Type of Weak Reference, Softly referenced objects are collected only when the JVM runs out of
memory. Widely used for caching mechanisms in applications.
- Phantom Reference: Type of weak reference. They are used to do post-mortem cleanup or finalization after an
object is garbage collected.
They are not accessible directly. You need to use a ReferenceQueue to receive notifications when the object is
garbage collected. Rarely used, mainly for final cleanup or tracking garbage collection.
JVM memory is divided into separate parts. At board level, JVM Heap memory is physically divided into 2 parts - Young
Generation and Old Generation.
Memory Management in Java - Young Generation
The young generation is the place where all new objects are created. When this is filled then garbage collection is
performed. This garbage collection is called Minor GC.
Young generation is divided into three parts - Eden Memory and two Survivor Memory spaces.
-> Most of the newly created objects are located in the Eden memory space.
-> When Eden space is filled with objects, Minor GC is performed and all the survivor objects are moved to one of the
survivor spaces.
-> Minor GC also checks the survivor objects and move them to the other survivor space. So at a time, one of the survivor
space is always empty.
Garbage Collection uses Mark and Sweep Algorithm:
- Mark : Marks the objects which needs to be deleted.
- Sweep : Moves the survived objects to the survival space and agce of survived objects is marked as 1.
This process is called minor GC.
When again new object is created and when GC is called again, then the same process is continued but this time new
objects are moved Eden to s1 and s1 moves to s2 but the age of previous objects will be increased by 1 and new objects
will be 1.
-> Objects that are survived after many cycles of GC, are moved to the Old generation memory space. Usually, it's done by
setting a threshold for the age of the young generation objects before they become eligible to promote to Old generation.
When the threshold is met, then the objects are moved to old generation and this is time taking process. This process is
called Major GC.
Memory Management in Java - Old Generation
Old Generation memory contains the objects that are long-lived and survived after many rounds of Minor GC. Usually,
garbage collection is performed in Old Generation memory when it’s full. Old Generation Garbage Collection is called Major
GC and usually takes a longer time.
Stop the World Event
All the Garbage Collections are “Stop the World” events because all application threads are stopped until the operation
completes. Since Young generation keeps short-lived objects, Minor GC is very fast and the application doesn’t get affected
by this. However, Major GC takes a long time because it checks all the live objects. Major GC should be minimized because
Algorithm of GC:
1. Mark and Sweep Algorithm
2. Mark and Sweep with Compaction
In Compaction, it compact the different memory together in sequential manner so that it would
be easy to added the memory when required
The Java ClassLoader is an integral part of the Java Runtime Environment (JRE) that dynamically loads Java classes into
the Java Virtual Machine (JVM). The Java run time system does not need to know about files and file systems because of
classloaders. Java classes aren’t loaded into memory all at once, but when required by an application. At this point, the
Java ClassLoader is called by the JRE, and these ClassLoaders load classes into memory dynamically.
ClassLoaders play a crucial role in Java's ability to dynamically load classes into memory as needed, enabling flexibility
and efficiency in Java applications.
Types of ClassLoaders in Java
1. Bootstrap ClassLoader (Primordial ClassLoader):
The Bootstrap ClassLoader is a machine code responsible for initiating the JVM's operations.
In Java versions up to 8, it loaded core Java files from [Link]. However, starting from Java 9, it loads core Java files from
the Java Runtime Image (JRT).
Bootstrap ClassLoader operates independently without any parent ClassLoaders.
2. Platform Class Loader (Extension ClassLoader):
In Java versions before Java 9, there was an Extension ClassLoader, but from Java 9 onwards, it's referred to as the
Platform Class Loader.
It loads platform-specific extensions from the JDK's module system.
Platform Class Loader loads files from the Java runtime image or from any other module specified by the system
property [Link] or --module-path.
3. System ClassLoader (Application ClassLoader):
Also known as the Application ClassLoader, it loads classes from the application's classpath.
It is a child of the Platform Class Loader.
Classes are loaded from directories specified by the environment variable CLASSPATH, the -classpath or -cp command-
line option.
Principles of Functionality of a Java ClassLoader
Overloading
Same name - different paramerters
Static can be overloaded
Final can be overloaded
Overriding:
Same name - same parameters - return type same/coveriant(sub-class)
Final cannot be overridden
Static cannot be overridden but it can be hidden using static
Because : static methods belong to the class, not the instance.
So method resolution happens at compile time, based on the reference type, not the object
Parent - Child
Checked - Unchecked
Checked - Checked
Exception - Checked
Exception - Unchecked
A HashMap<K, V> stores key-value pairs. It allows null keys and values, and provides O(1) average time for get() and put(),
assuming good hash distribution.
Core Components Inside HashMap
Internally, a HashMap uses:
An array of buckets (Node<K, V>[] table)
Each bucket is a linked list (or tree when collision threshold is high)
Each Node stores:
static class Node<K, V> implements [Link]<K, V> {
final int hash;
final K key;
V value;
Node<K, V> next;
}
How put(key, value) Works
[Link]("apple", 100);
Hash Calculation
Computes a hash code from the key:
int hash = hash("apple");
Index Determination
Converts the hash into an index for the array:
int index = (n - 1) & hash; // n = array length
Collision Handling
If the bucket at that index is empty → insert the new node.
If not → collision! → traverse the list:
If key already exists → update value
If not → add the node at the end (or in Java 8+, may treeify)
If size exceeds loadFactor * capacity, the HashMap resizes itself (usually doubling the capacity), and rehashes all keys.
How get(key) Works
[Link]("apple");
Calculate the hash → locate the bucket index
Traverse the linked list (or tree) at that index
Use equals() to find the correct key → return value
hash → index → check each node's key with equals() → get value
Treeification (Java 8+)
If one bucket has more than 8 nodes and capacity ≥ 64:
Java converts the linked list to a red-black tree.
Improves performance from O(n) to O(log n) in that bucket.
What Happens on Hash Collisions?
If two keys have the same hash and land in the same bucket:
They're stored in a linked list (or tree if many)
Java uses equals() to distinguish the keys
HashMap<String, Integer> map = new HashMap<>();
[Link]("A", 1);
[Link]("B", 2); // suppose A and B hash to same bucket
Bucket looks like: "A" → "B" linked
null key is always stored in bucket 0
Operation Time Complexity (Avg) Notes
put() O(1) Becomes O(log n) if treeified
get() O(1) Uses hash + equals()
remove() O(1) Similar to get
🔑
Git is Version Control System, records changes made to our code overtime in a special database called repository.
Without VCS, we need to maintain the copy of all the changes made by each developers, which makes system work slow
and merge all the changes which leads to many conflicts.
With VCS, we can
-> Track History
-> Work Together
VCS forms into 2 categories
1. Centralized - all the team members connect to a central server to get the latest copy of the code and to share the
code changes to all.
Examples -> Subversion, MS team Foundation server
Disadvantages -> Single point failure and cannot save data.
2. Distributed - every team members has the copy of the project and history of their machine so we can save the data
locally in our systems. If server is offline, we can directly synchronize our code with others.
Examples -> Git, mercurial
Why Git?
- Free
- Open Source
- Super fast
- Scalable
- Cheap Branching/Merging
Using Git,
- The command line - terminal and it is faster
- Code editors & IDEs - Source control panel in VS code - GitLens extension
- GUI - Git website - popular tools GitKraken Git GUI and SourceTree
GitKraken - works across different platforms and easy to integrate with other products like GitKraken Boards for
issue tracking and GitKraken Timelines for project management it is free for open source and for commercial it is
payable.
SourceTree - free open source available for windows and mac.
Why command line?
- GUI tools have limitations
- GUI tools may not be available
Installing Git
- Terminal to check version -> git --version -> 2.27.0
Installed application called GitBash = Born Again Shell -> Command prompt window which emulates unix and linux
environment.
- Configuring Git
Settings -> name, email, default editor, line ending
Configuration Settings in 3 levels,
1. System levels -> Applied to all users
2. Global levels -> Applied to all the repositories of the current user
3. Local levels -> applied to current repo
git config --global [Link] "XYX" -> name
git config --global [Link] xtc@[Link] -> email
default editor for mac is vim
download and install VScode and configure the path and then in terminal type code
git config --global [Link] "code --wait" wait flag to tell terminal to wait until we close the new vscode instance
All the global configuration are stored in text file which can be edited using default editor
git config --global -e -> opens our default editor to edit the global settings (default file name -> gitconfig)
In windows, end of line is marked with \r->Carriage Return and \n->Line Feed
JM-0 Page 1
In windows, end of line is marked with \r->Carriage Return and \n->Line Feed
In mac, end of line is marked with \n
We need to configure the end of line to avoid data issues, to prevent this we need to use [Link] property which is
carriage return line feed.
git config --global [Link] true/input(true for windows and input for mac)
Git help commands
git config --help (space for next page and q to exit)
git config -h -> summary for each commands and its options
Git Commands
To create directory -> mkdir dir
To open directory -> cd dir
To create empty repository/ initialize-> git init
By default subdirectories are hidden because of that we cannot see .git in list
To list all files and directories -> ls
To list all files and directories even hidden -> ls -a (a=All) we can .git subfolder then
To open .git, windows-> explorer, mac -> finder
To open .git file from terminal -> open .git
It contains branches, hooks, info, objects and references. If anyone deletes this folder then can lose the project history
To make terminal pretty (optional), windows -> posh-git, mac -> Zsh with Git plugin
To remove directory with sub repository -> rm -rf .git
Git Workflow:
Staging area / index -> review the changes and then commit and pushes the code to repository where it is stored
permanently.
git add f1 f2 f3 -> to add files from local to staging area
git commit -m "message" -> to send file from staging area to repository
After pushing the code to repository we still have files in staging area which says our working file
If we want to delete the file from the working directory then we need to delete the file from directory and then use git
add file to remove file from staging area and repository and then git commit.
Each commit contains ID, message, data/time, author, complete snapshot
Git reduces the storage by compressing the content and doesn't store duplicate content
Staging Files:
To add data into files -> echo hello > [Link] (> means to add data)
To track and the status of working directory and staging area -> git status
To add all files to staging area -> git add .
Green color for main branch with ? Indicates we have files which are not being tracked
Yellow color for main branch without ? But some other mark indicates that there are files in staging area and are ready
to be committed
echo world >> [Link] (>> means to append the data)
Committing changes:
git commit -m "message"
To add some additional info for the commit file (description)
git commit -> opens default editor (short description -> max 80 length and then line break and then long description)
Committing best Practices:
- Commit size shouldn't be too small and too big
- We don’t make a commit for every update
- Commit often with relevant changes(5 recommended)
JM-0 Page 2
- Commit often with relevant changes(5 recommended)
- Wording conversion (past tense -> fixed the bug rather then fix the bug)
Skipping the staging area:
git commit -a -m "message"
git commit -am "message" (a=All, m=message)
Removing Files : Should be removed from staging area and repository.
rm [Link] -> deletes file from working directory
But staging area contains the file , to check git ls-files
git add [Link]
git commit -m "msg"
Single command for this -> git rm [Link] *.txt -> removes file from staging area and working directory
Renaming and Moving Files:
mv [Link] [Link] -> unix command
git add [Link] [Link]
Single command -> git mv [Link] [Link] -> working and staging area
Ignoring Files:
Developers can have their own log files, it is not shared and synchronize with other team members
mkdir logs -> echo hello > logs/[Link] -> creates a log file into logs directory
To ignore files -> .gitignore file - This file has no name and it has only the extension and it should be created in the root
of the project
echo logs/ > .gitignore -> echo to create, write and display file
code .gitignore to open the file with VScode
Add the file path, file and directory to be ignored and not being staged
Gitignore works only when we have already included file/directory in our repository
We should stage the files separately from the directory so that it will be in tracked stage
After staging the file and directory, if we include it in gitignore then it doesn't work (not ignored since it is already in the
staging area)
To view the files in staging area -> git ls-files
To remove file from staging area:
git rm -h -> all the flags used with rm command
git rm --cached bin/ -> to remove empty directory
git rm --cached -r bin/ -> to remove directory recursively
After ignoring files if we again change the file it doesn't shows the changes in git and it doesn't track the file
Java .gitignore default files are *.class, *.log, *.ctxt
# -> comments in the git
Short Status:
git status -s -> gives the shortcut description for the files like M [Link] -> modified and ?? [Link] -> untracked file
Output is 2 columns, left column-> staging area, right column -> working directory (M->modified and A->Added)
Viewing Staging and unstaging changes:
git diff --staged -> staging area
Changes in the old copy indicated with - and changes to new copy indicated by +
For new file added in the staging area --- value will be null means previous data is not exists
git diff -> working directory changes -> unstagged
Visual Diff tools:
- KDiff3
- P4Merge
- WinMerge (windows only)
- VSCode
Using VSCode,
git config --global [Link] vscode -> default diff tool
git config --global [Link] "code --wait --diff $LOCAL $REMOTE"
where wait-> wait till we don't close the vscode, diff-> for difference, $LOCAL -> old copy place and $REMOTE for
new copy place
git config --global -e -> allows us to edit the global file(.gitconfig) in default editor
JM-0 Page 3
git config --global -e -> allows us to edit the global file(.gitconfig) in default editor
git difftool -> to launch the difftool comparing with working directory -> unstaging area
git difftool --staged -> launch with comparing staging area
Viewing the history:
git log -> views history of commits
Main/master/truck -> main branch
Head-> reference to current branch
git log --oneline -> to show the summary of logs (short description) id-> max 7 characters
git log --oneline --reverse -> to show in reverse order (old to new commits)
Viewing commits:
git show <id> / git show HEAD~ <steps> no of steps to go back, Head -> points to last commit
git show HEAD~1:<path of file> exact version stored in that commit
To see all the files and directories of the commits with meta data -> git ls-tree HEAD~1
Files are represented as blob and directories are represented as tree
git show <id> -> used to view the objects
Git Objects can be commits, Blobs(files), Trees (Directories), Tags
Unstaging Files:
Previous commands -> git reset --hard/--soft
New command -> git restore --staged [Link] [Link] or simply . -> used to remove file from staging area to working directory
Discarding local changes:
git restore [Link] or simply . For all
To clean all untracked file -> git clean -> options are -h,-f,-d where f-> force deletion, d-> directory deletion
Restoring a file to an Earlier version:
git restore --source-HEAD~1 [Link] -> f1 file was deleted, if it was in staging then moves to working, if it is repository then
moves to staging
To move commit from one branch to other branch : git cherry-pick <commit-hash>
Deleting a branch : git branch -d <branch-name> -> -D for force delete
Adding a remote repository -> git remote add origin <url>
Pushing changes -> git push origin <branch-name>
Pulling changes -> git pull origin <branch-name>
Fetching Updates (to view changes in remote without merging) -> git fetch
Discarding unstaged changes -> git checkout -- <file>
Resetting Commits
Undo commits while keeping changes:
git reset --soft HEAD~1 # Undo last commit but keep changes staged
git reset --mixed HEAD~1 # Undo last commit and unstage changes
git reset --hard HEAD~1 # Undo last commit and discard changes
Stash changes ( save uncommitted work temporarily) -> git stash
Apply stashed Changes -> git stash apply
View Stash list -> git stash list
Rewriting History
Amending the Last commit -> git commit --amend -m "Updated"
git rebase -i HEAD~n
Purpose: Rewrites the commit history interactively (e.g., clean up commit messages, squash commits).
• n is the number of commits from HEAD you'd like to rebase.
• Example: git rebase -i HEAD~3 lets you interactively edit the last 3 commits.
You’ll see a list of commits in an editor, where you can change pick to squash, reword, etc.
git squash
Purpose: Combine multiple commits into a single one (used during rebase).
• Used in interactive rebase by replacing pick with squash or s.
• Example:
pick abc123 Initial commit
squash def456 Added README
squash ghi789 Minor fix
This merges all 3 into one commit.
JM-0 Page 4
This merges all 3 into one commit.
git blame
Purpose: Shows who changed what and when in each line of a file.
• Syntax: git blame <filename>
• Example: git blame [Link]
• Great for debugging and understanding history.
Git Fast-forward Merge
Scenario: Happens when your branch is directly ahead of the target branch.
• Example: If main hasn't moved and feature has new commits, merging feature into main is fast-forward.
• Command: git merge feature
• No merge commit is created, just a pointer move.
Resolving Git Merge Conflicts
1. git revert
• Used to undo changes by creating a new commit that reverses the effects.
• Syntax: git revert <commit_hash>
• Does not change history, safe for shared branches.
2. git merge --abort
• Used to abort an in-progress merge if conflicts arise.
• Syntax: git merge --abort
• Returns you to the state before the merge began.
For a rebase conflict: Use git rebase --abort.
Git init -> sets local repository
• The staging area is a file called index inside your .git folder on your local machine’s disk.
• Git reads from and writes to this file to keep track of what’s staged.
Git Flow Strategies
1. git flow
A branching model by nvie:
• main: Production-ready code
• develop: Integration branch for features
• feature/*: Feature branches
• release/*: Pre-release testing
• hotfix/*: Urgent fixes on main
Commands require the git-flow extension:
• Start a feature: git flow feature start <name>
• Finish feature: git flow feature finish <name>
2. Trunk-Based Development
• All developers commit to a single shared branch (usually main or trunk).
• Encourages short-lived feature branches or feature flags.
• Promotes CI/CD, automation, and small incremental changes.
Lightweight and fast-moving; commonly used in DevOps, microservices, etc.
3. (Add-on) GitHub Flow
• Only main and short-lived feature branches.
• Create feature → Push to remote → Open PR → Review & merge.
JM-0 Page 5
Maven
08 January 2025 21:15
Maven is a powerful project management tool that is based on POM (project object model). It is used for
projects build, dependency and documentation. It simplifies the build process like ANT. But it is too much
advanced than ANT.
In short, maven is a tool that can be used for building and managing any Java-based project. Maven makes
the day-to-day work of Java developers easier and generally help with the comprehension of any Java-based
project.
Maven project creation :
mvn archetype:generate -DgroupId=ToolsQA -DartifactId=<project_name> -DarchetypeArtifactId=maven-archetype-
quickstart -DinteractiveMode=false
Project Structure:
The src/main/java directory contains the project source code, the src/test/java directory contains the test source, and
the [Link] file is the project's Project Object Model, or POM
[Link]:
The [Link] file is the core of a project's configuration in Maven. It is a single configuration file that contains the
majority of information required to build a project in just the way you want. The POM is huge and can be daunting in its
complexity, but it is not necessary to understand all of the intricacies just yet to use it effectively.
JM-0 Page 6
You executed the Maven goal archetype:generate, and passed in various parameters to that goal. The
prefix archetype is the plugin that provides the goal. If you are familiar with Ant(Apache Ant is a Java library and
command-line tool whose mission is to drive processes described in build files as targets and extension points
dependent upon each other. The main known usage of Ant is the build of Java applications.), you may conceive of this
as similar to a task. This archetype:generate goal created a simple project based upon a maven-archetype-
quickstart archetype. Suffice it to say for now that a plugin is a collection of goals with a general common purpose. For
example the jboss-maven-plugin, whose purpose is "deal with various jboss items".
Build the project : mvn package
A phase is a step in the build lifecycle, which is an ordered sequence of phases. When a phase is given, Maven executes
every phase in the sequence up to and including the one defined.
Maven Phases
Although hardly a comprehensive list, these are the most common default lifecycle phases executed.
• validate: validate the project is correct and all necessary information is available
• compile: compile the source code of the project
• test: test the compiled source code using a suitable unit testing framework. These tests should not require the
code be packaged or deployed
• package: take the compiled code and package it in its distributable format, such as a JAR.
• integration-test: process and deploy the package if necessary into an environment where integration tests
can be run
JM-0 Page 7
• verify: run any checks to verify the package is valid and meets quality criteria
• install: install the package into the local repository, for use as a dependency in other projects locally
• deploy: done in an integration or release environment, copies the final package to the remote repository for
sharing with other developers and projects.
There are two other Maven lifecycles of note beyond the default list above. They are
• clean: cleans up artifacts created by prior builds
• site: generates site documentation for this project
Maven Commands:
Some basic Maven commands includes:
• mvn clean: Cleans the project and removes all files generated by the previous build.
• mvn compile: Compiles source code of the project.
• mvn test-compile: Compiles the test source code.
• mvn test: Runs tests for the project.
• mvn package: Creates JAR or WAR file for the project to convert it into a distributable format.
• mvn install: Deploys the packaged JAR/ WAR file to the local repository.
• mvn site: generate the project documentation.
• mvn validate: validate the project’s POM and configuration.
• mvn idea:idea: generate project files for IntelliJ IDEA or Eclipse.
• mvn release:perform: Performs a release build.
• mvn deploy: Copies the packaged JAR/ WAR file to the remote repository after compiling, running tests and
building the project.
• mvn archetype:generate: This command is used to generate a new project from an archetype, which is a
template for a project. This command is typically used to create new projects based on a specific pattern or
structure.
• mvn dependency:tree: This command is used to display the dependencies of the project in a tree format.
Used in troubleshooting.
Generally when we run any of the above commands in combine form,
mvn clean install
mvn -X install -> if we want to run the step in debug mode for more detailed build information and logs
mvn install -DskipTests->if we do not want to run the tests while packaging or installing the Java project.
JM-0 Page 8
Core Java
09 January 2025 10:44
You can use simply java [Link] for compiling and executing in one step.
Creating first java Class
JM-0 Page 9
byte - 1 Byte (-128 to 127) signed two's complement integer - 0
short - 2 Byte (-32,768 to 32,767) signed two's complement integer - 0
int - default type - 4 Byte (-2^31 to (2^31)-1) - 0
signed two's complement integer
long - 8 byte (-2^63 to (2^63)-1) signed two's complement integer - 0L
float - 4 byte single-precision - 0.0f
double - default type - 8 byte - 0.0d
boolean - 1 bit (true/false) - false
char - 2 byte (\u0000-0 to \uffff-65,535) - \u0000
String - any object has default null reference.
Decimal - Base 10 (0-9)
Hexadecimal - Base 16 (0-9,A-F)
Binary - Base 2 (0,1)
Octal - Base 8 (0-7) if number starts with 0 then its considered as octal number
Special escape sequence for char and string literals are \b->backspace, \t->tab, \n-> linefeed, \f-> formfeed, \r->
carriage return, \"-> double quote, \'-> single quote, \\ backslash.
any number of underscore characters (_) can appear anywhere between digits in a numerical literal.
You can place underscores only between digits; you cannot place underscores in the following places:
• At the beginning or end of a number
• Adjacent to a decimal point in a floating point literal
• Prior to an F or L suffix
• In positions where a string of digits is expected
3. Creating arrays in your programs
An array is a container object that holds a fixed number of values of a single type. Indexing begins with 0.
Creating, Initiating, Accessing an Array:
int[] arr=new int[size];
Copying Arrays : System class has an arraycopy()
public static void arraycopy(Object src, int srcPos,
Object dest, int destPos, int length)
Array Manipulators : [Link]
- binarySearch()
- equals()
- fill()
- sort()
- parallelSort()
- stream()
- toString()
4. Using the var type Identifier
var type identifier to declare a local variable.
var message="hfd"
var path=[Link]("[Link]")
Restrictions of using var:
JM-0 Page 10
Restrictions of using var:
- Can be used as local variable in method, constructors, and initializer blocks.
- Cannot be used for fields, method or constructor parameters.
- Compiler must be able to choose a type when it is declared.
5. Using operators in your programs
Assignment operator : =
Arithmetic operator : +, -, *, /, %
Unary operator : +, -, ++, --, !
Relational/Equality operator : ==, !=, >, >=, <, <=
Conditional operator : &&, || -> exhibit short-circuiting
Ternary operator : ?:
Type Comparison operator : instanceof -> obj1 instanceof obj2
Bitwise operator : ~, <<, >>, >>>, &, |, ^
6. Summary of operators
7. Expressions, statements and blocks
An expression is a construct made up of variables, operators, and method invocations, which are constructed according
to the syntax of the language, that evaluates to a single value
Example : double d1 = 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1; d1!=1.0
A statement forms a complete unit of execution.
Types of expressions can be made into a statement by terminating the expression with a semicolon (;).
Example : a value=345;
A block is a group of zero or more statements between balanced braces and can be used anywhere a single statement is
allowed.
8. Control flow statements
Conditional statement ->If-then, if-then-else, nested if-else, switch
Looping statement -> while, do-while, for
branching statement -> break(labeled and unlabeled), continue, return, yield - The yield statement exits from the
current switch expression it is in. A yield statement is always followed by an expression that must produce a value. This
expression must not be void.
9. Branching with switch statements
The type of your selector variable among the following types:
byte, short, char, and int primitive data types
Character, Byte, Short, and Integer wrapper types
enumerated types
the String type.
The selector variable of a switch statement can be an object, so this object can be null. will throw a
NullPointerException.
10. Branching with switch expressions
In Java SE 14 you can use another, more convenient syntax for the switch keyword,
The syntax of switch label is now case L ->. Only the code to the right of the label is executed if the label is matched.
JM-0 Page 11
Collection Framework
09 January 2025 10:45
Collection Methods:
Iterator Interface:
An iterator in Java is an interface that provides a way to access elements of a collection (like lists, sets, or maps) one at a
time, without exposing the underlying details of the collection's structure. It allows you to traverse through the elements
JM-0 Page 12
time, without exposing the underlying details of the collection's structure. It allows you to traverse through the elements
in a collection sequentially in forward direction only.
It has some important methods:
- hasNext(): Checks if there are more elements to iterate over and returns a boolean value.
- next(): Returns the next element in the collection.
- remove(): Removes the last element returned by next().
Iterator<String> iterator = [Link]();
List Interface:
JM-0 Page 13
List Interface:
The List interface represents an ordered collection of elements. It allows duplicate elements and provides methods to
access, insert, update, and remove elements at specific positions within the list.
ArrayList : An ArrayList in Java is a dynamic and ordered collection that can grow or shrink in size as needed. It is used to
store and manage a list of elements. ArrayList allows for easy insertion, retrieval, and removal of elements, making it a
versatile data structure for working with collections of data in Java programs. It provides the benefits of an array with
the added flexibility of automatic resizing, making it a popular choice for many programming tasks.
JM-0 Page 14
LinkedList : A Linked List is a linear data structure in Java that consists of a sequence of elements, where each element
points to the next one in the sequence. It's made up of nodes, where each node holds both data and a reference (or link)
to the next node in the list. Unlike an array, a Linked List can efficiently insert or remove elements at any position in the
list, making it a flexible choice for certain data manipulation tasks. Linked Lists are often used when dynamic data
storage and efficient insertions and deletions are required in Java programs.
JM-0 Page 15
Vector : A Vector in Java is a dynamic, resizable array-like data structure .It's similar to an ArrayList but is synchronized,
which means it is thread-safe. Vectors can grow or shrink in size as needed, making them suitable for situations where
the size of the collection may change dynamically. They are primarily used when you need a collection that can be
accessed by multiple threads without the risk of data corruption.
Stack : A stack in Java is a linear data structure that follows the Last-In-First-Out (LIFO) principle. It is the subclass of
Vector and operates like a collection of items where you can only add or remove elements from the top, similar to a
stack of plates. Elements are added to the top of the stack and removed from the top as well. This means that the last
element added to the stack is the first one to be removed. Stacks are often used for tasks that require keeping track of
the order of elements, such as managing function calls in recursion, undo functionality in applications, or browser history
navigation.
Queue Interface :
The Queue interface in Java represents a collection that holds elements in a linear order and allows adding elements at
one end (enqueue) and removing elements from the other end (dequeue). It follows the "first-in-first-out" (FIFO)
principle, similar to a real-world queue. Queues are often used for tasks like managing tasks in a printer queue or
processing tasks in a concurrent system.
JM-0 Page 16
PriorityQueue Class :
The PriorityQueue class in Java is an implementation of the Queue interface that provides a priority-based ordering of
elements. Elements in a PriorityQueue are ordered based on their natural order or according to a specified comparator.
The element with the highest priority (according to the defined order) is always at the front and will be the first to be
removed when dequeued. This makes PriorityQueue suitable for tasks like task scheduling, job processing, or managing
elements with priorities.
Deque Interface :
The Deque (pronounced as "deck") interface in Java stands for "Double Ended Queue." It is a linear collection that
supports adding and removing elements from both ends, i.e., both the front and the rear. A Deque interface extends the
Queue interface, adding methods for operations at both ends of the queue, making it versatile for various data
manipulation scenarios.
ArrayDeque : (Stack+Queue)
An ArrayDeque in Java is a double-ended queue (Deque) implemented as a resizable array. It allows you to add and
remove elements from both ends efficiently, making it a versatile choice for various data structure operations. Unlike a
traditional array, an ArrayDeque can dynamically resize itself to accommodate elements as they are added. This data
structure is often used in scenarios where you need a queue or stack-like behaviour, and it provides constant time (O(1))
performance for basic operations like adding and removing elements from both ends.
Set Interface :
The Set interface represents an unordered collection of unique elements. Unlike lists, sets do not allow duplicate values,
making them ideal for scenarios where you need to ensure distinct elements. The Set interface includes several methods
for adding, removing, and checking the presence of elements. Popular implementations of the Set interface are HashSet,
LinkedHashSet, and TreeSet, each with its own characteristics and use cases. By using Set, you can efficiently manage
collections of elements without worrying about duplicates, making it a valuable tool in Java programming.
JM-0 Page 17
Hash Set :
HashSet provides a collection of unique elements without any specific order. This means that you can store elements in
a HashSet, and it will automatically ensure that duplicates are not allowed. It is highly efficient for checking the presence
of elements and adding or removing elements from the set. While elements are not stored in a particular sequence, this
data structure is particularly useful when you need to maintain a collection of items where uniqueness is a priority, and
the order of elements doesn't matter.
LinkedHashSet :
LinkedHashSet combines the features of both HashSet and LinkedHashMap, offering a collection of unique elements
with predictable iteration order. Unlike HashSet, LinkedHashSet maintains the order in which elements were inserted
into the set. This means that when you iterate over a LinkedHashSet, the elements will be returned in the order they
were added. This can be useful in situations where you need both uniqueness and a specific order for your elements.
TreeSet :
A TreeSet is a sorted collection in Java that implements the Set interface. Unlike a HashSet, which does not guarantee
any specific order of elements, a TreeSet maintains elements in sorted order. This sorting is typically in ascending order,
but you can customize it by providing a comparator during TreeSet creation. TreeSet uses a Red-Black Tree data
structure internally for efficient sorting and retrieval operations.
Map Interface:
The Map interface in Java represents a collection of key-value pairs, where each key is unique and maps to a specific
value. It allows for efficient data retrieval based on keys, making it useful for tasks like looking up values by identifiers.
Java provides various implementations of the Map interface, such as HashMap, TreeMap, and LinkedHashMap, each
suited for different use cases. Maps are commonly used to store and manage data where the relationship between keys
and values is critical. They enable quick and direct access to values based on their associated keys, enhancing the
efficiency of data retrieval and manipulation in Java programs.
JM-0 Page 18
HashMap:
A HashMap in Java is a fundamental data structure that facilitates the storage and retrieval of data using key-value pairs.
It is a part of the Java Collections Framework and provides efficient access to values based on their associated keys.
HashMaps use a hash function to compute an index into an array where the values are stored, making retrieval swift
even for large datasets. They do not allow duplicate keys and permit one null key along with multiple null values. Java
developers frequently use HashMaps to implement data structures like dictionaries and associative arrays, where data is
organized and accessed by unique keys, enabling efficient and fast data retrieval in various applications.
HashTable :
A HashTable is similar to a HashMap but has several differences. A HashTable is a synchronized collection, which means
it is thread-safe and can be used in multi-threaded applications without the need for external synchronization. It uses a
hash function to map keys to values, allowing for efficient key-value retrieval. However, HashTable has become
somewhat outdated, and it is recommended to use HashMap in most cases, as it offers similar functionality but is not
synchronized, making it more efficient for single-threaded applications. Additionally, HashTable does not allow null keys
or values, whereas HashMap permits one null key and multiple null values.
LinkedHashMap :
A LinkedHashMap in Java is a class that combines the features of a hash table and a linked list to store key-value pairs. It
maintains the order of elements based on the insertion sequence, allowing predictable iteration. This means that when
you iterate through a LinkedHashMap, the elements are returned in the order in which they were added. It provides
efficient access to elements via hashing and preserves the order of insertion, making it useful for scenarios where you
JM-0 Page 19
efficient access to elements via hashing and preserves the order of insertion, making it useful for scenarios where you
need both quick access to elements and a predictable iteration order.
TreeMap:
A TreeMap is a class in Java that implements the Map interface and extends the AbstractMap class. It is part of the Java
Collections Framework and provides a Red-Black tree-based implementation of the Map interface. TreeMap stores its
elements in a sorted and balanced tree structure, which allows for efficient operations like insertion, deletion, and
retrieval of elements.
Internal Structure of HashMap :
HashMap is an associative array data structure. Stores data in the form of key-value pair.
HashMap works an the basis of hashing.
Hashing uses the hashCode() which is coming from the Object class.
Default bucket size created when the HashMap is declared is 16.
JM-0 Page 20
Exception handling
09 January 2025 10:45
Errors: An error is a severe condition that can occur only at run time and is irrecoverable. It prevents a program from
executing and cannot be handled by the programmer. An error belongs to the [Link] class.
Exceptions: A programmer can catch and handle exceptions in his program code. When an exception occurs within a
method, an object called the exception object is created. This object contains information about the exception, such as its
name and description and the state of the program when the exception occurred.
JM-0 Page 21
There are two types of built-in exceptions in Java:
1. Checked Exception
Checked exceptions are classes that inherit directly from the Throwable class, with the exception of RuntimeException
and Error. Examples include IOException, SQLException, and so on. Checked exceptions are checked at compilation time.
They must be either caught by the code or declared in the method signature using the throws keyword.
2. Unchecked Exception
Classes that inherit the RuntimeException class are known as unchecked exceptions. Examples include
ArithmeticException, NullPointerException, and ArrayIndexOutOfBoundsException. Unchecked exceptions are not
checked at compile-time but rather at runtime by JVM. They do not need to be explicitly caught or declared.
User-Defined Exceptions :
User-defined exceptions are also known as custom exceptions derived from the Exception class from [Link] package.
The user creates these exceptions according to different situations. Such exceptions are handled using five keywords: try,
catch, throw, throws, and finally.
JM-0 Page 22
Try :
A try block consists of all the doubtful statements that can throw exceptions.
A try block cannot be executed on itself; it requires at least one catch block or finally block.
If an exception occurs, the control flows from the try-to-catch block.
When an exception occurs in a try block, the appropriate exception object is redirected to the catch block. This catch
block handles the exception according to its statements and continues the execution.
Catch:
The catch block handles the exception raised in the try block.
The catch block or blocks follow every try block.
The catch block catches the thrown exception as its parameter and executes the statements inside it.
The declared exception must be the parent class exception, the generated exception type in the exception class hierarchy,
or a user-defined exception.
Finally :
The finally block in Java always executes even if there are no exceptions. This is an optional block. It is used to execute
important statements such as closing statements, releasing resources, and releasing memory. There could be one final
block for every try block. This finally block executes after the try...catch block.
JM-0 Page 23
Throw :
The throw keyword is used to explicitly throw a checked or an unchecked exception.
The exception that is thrown needs to be of type Throwable or a subclass of Throwable.
We can also define our own set of conditions for which we can throw an exception explicitly using the throw keyword.
The program's execution flow stops immediately after the throw statement is executed, and the nearest try block is
checked to see if it has a catch statement that matches the type of exception.
Throws:
The throws keyword is used in the method signature to indicate that a method in Java can throw particular exceptions.
This notifies the method that it must manage or propagate these exceptions to the caller.
JM-0 Page 24
It allows the program to run continuously without any disruption.
It provides the ability to catch the specific exception that occurred in the program.
It also helps the developers to write cleaner code and learn how to handle exceptions.
JM-0 Page 25
Generics
09 January 2025 10:45
Generics in Java are a powerful feature that enables developers to write flexible, reusable, and type-safe code.
Generics allow types (classes and interfaces) to be parameters when defining classes, interfaces, and methods. This
helps in creating code that works with any type and ensures type safety at compile-time.
Primitive Types: Java generics cannot use primitive types. For example, you must use Integer instead of int.
Type Safety: Generics provide compile-time type checking, reducing runtime errors.
Type Inference: Java can often infer the type parameter from the context, making the code cleaner.
Generic Classes
Generic classes enable you to create classes that can operate on any type specified at instantiation.
Type Parameters: Define the type parameter in angle brackets (<T>).
Multiple Type Parameters: You can define multiple type parameters (<K, V>).
Type Erasure: The compiler replaces generic types with their bounds or Object during compilation.
Generic Methods
Generic methods allow you to create methods that can operate on any type.
Type Parameters: Define the type parameter before the return type (<T>).
Static Methods: Generic type parameters can be used in static methods.
Varargs: Use @SafeVarargs annotation to suppress warnings when using varargs with generics.
JM-0 Page 26
Bounded Type Parameters
Bounded type parameters restrict the types that can be used as generics, providing more control.
Upper Bounds: Use <T extends Class> to restrict to subclasses of a specific class.
Multiple Bounds: Use <T extends Class1 & Interface1> for multiple bounds.
Lower Bounds: Use the super keyword in wildcards for lower bounds
Generic Interfaces
Generic interfaces allow you to define interfaces that can be implemented by any class with a specific type.
Type Parameters: Define the type parameter in the interface.
Implementation: Implementing classes must specify or inherit the type parameter.
Multiple Interfaces: A class can implement multiple generic interfaces.
JM-0 Page 27
Wildcards in Generics
Wildcards provide flexibility in generics, especially when working with collections of unknown types.
Unbounded Wildcards: Use <?> when the type is unknown.
Upper Bounded Wildcards: Use <? extends T> to specify an upper bound.
Lower Bounded Wildcards: Use <? super T> to specify a lower bound.
Implementing a Generic Cache
A generic cache can store objects of any type and provide efficient retrieval.
Type Safety: Ensure that the cache maintains type safety.
Key-Value Pairs: Use appropriate type parameters for keys and values.
Thread Safety: Consider thread safety for concurrent access.
Using Generics with Comparator
Generics can be used with Comparator to create flexible sorting logic.
Comparable Interface: Use the Comparable interface for natural ordering.
Custom Comparators: Implement custom comparators for specific ordering.
Type Safety: Ensure type safety in comparisons.
Multi-Level Generics
Generics can be used in complex scenarios involving multiple levels.
Nested Generics: Understand the nesting of generics in class hierarchies.
Type Parameter Propagation: Ensure type parameters are correctly propagated.
Flexibility: Multi-level generics provide enhanced flexibility and reusability.
Generic Utilities for BigDecimal
Generics can be particularly useful when dealing with financial calculations, where BigDecimal is often used.
Precision: Ensure precision is maintained with BigDecimal.
Type Safety: Utilize generics to maintain type safety in financial utilities.
Reusability: Generic utilities enhance reusability across different financial calculations.
JM-0 Page 28
String/StringBuilder/StringBuffer
09 January 2025 10:46
Strings are immutable in Java. This means we cannot manipulate the value of a String object. If we modify the value
of a String object in Java, a new String object with the modified value will be created in the heap memory.
StringBuilder and StringBuffer classes are used to provide us with the functionality of mutable Strings in Java.
StringBuffer provides us with strings that are safe to use with multiple threads but this added functionality also
makes it slower. StringBuilder lacks thread safety but because it does not have this added functionality, it has faster
implementation.
Strings in Java
Java program makes I/O operations only with strings. A string is a sequence of characters like “apple”, “1234”.
String class enables us to declare and define a string [Link] objects are immutable in nature. Whenever a
String object is manipulated it does not affect the original object rather it creates a new object and assigns the new
manipulated value to it.
JM-0 Page 29
Performance :
String methods:
JM-0 Page 30
JM-0 Page 31
Annotation
16 January 2025 11:18
Categories of Annotations
1. Marker Annotations
2. Single value Annotations
3. Full Annotations
4. Type Annotations
5. Repeating Annotations
Marker Annotations
The only purpose is to mark a declaration. These annotations contain no members and do not consist of any data. Thus, its
presence as an annotation is sufficient. Since the marker interface contains no members, simply determining whether it is
present or absent is sufficient. @Override is an example of Marker Annotation.
Example - @TestAnnotation()
Full Annotations
These annotations consist of multiple data members, names, values, pairs.
JM-0 Page 32
These annotations consist of multiple data members, names, values, pairs.
Example - @TestAnnotation(owner=”Rahul”, value=”Class Geeks”)
Type Annotations
These annotations can be applied to any place where a type is being used. These are declared annotated with @Target
annotation.
Example - @Target(ElementType.TYPE_USE)
Repeating Annotations
These are the annotations that can be applied to a single item more than once. For an annotation to be repeatable it must
be annotated with the @Repeatable annotation, which is defined in the [Link] package. Its value field
specifies the container type for the repeatable annotation. The container is specified as an annotation whose value field is
an array of the repeatable annotation type. Hence, to create a repeatable annotation, firstly the container annotation is
created, and then the annotation type is specified as an argument to the @Repeatable annotation.
JM-0 Page 33
@deprecated tag has higher priority than @Deprecated annotation when both are together used.
@Override
It is a marker annotation that can be used only on methods. A method annotated with @Override must override a method
from a superclass. If it doesn’t, a compile-time error will result. It is used to ensure that a superclass method is actually
overridden, and not simply overloaded.
@SuppressWarnings
It is used to inform the compiler to suppress specified compiler warnings. The warnings to suppress are specified by name,
in string form. This type of annotation can be applied to any type of declaration.
Java groups warnings under two categories. They are deprecated and unchecked. Any unchecked warning is generated
when a legacy code interfaces with a code that uses generics.
@Documented
It is a marker interface that tells a tool that an annotation is to be documented. Annotations are not included in ‘Javadoc’
comments. The use of @Documented annotation in the code enables tools like Javadoc to process it and include the
annotation type information in the generated document.
@Target
It is designed to be used only as an annotation to another annotation. @Target takes one argument, which must be
constant from the ElementType enumeration. This argument specifies the type of declarations to which the annotation
can be applied.
@Retention
It determines where and how long the annotation is retent. The 3 values that the @Retention annotation can have:
SOURCE: Annotations will be retained at the source level and ignored by the compiler.
JM-0 Page 34
SOURCE: Annotations will be retained at the source level and ignored by the compiler.
CLASS: Annotations will be retained at compile-time and ignored by the JVM.
RUNTIME: These will be retained at runtime.
@Inherited
@Inherited is a marker annotation that can be used only on annotation declaration. It affects only annotations that will be
used on class declarations. @Inherited causes the annotation for a superclass to be inherited by a subclass. Therefore,
when a request for a specific annotation is made to the subclass, if that annotation is not present in the subclass, then its
superclass is checked. If that annotation is present in the superclass, and if it is annotated with @Inherited, then that
annotation will be returned.
User-defined (Custom)
User-defined annotations can be used to annotate program elements, i.e. variables, constructors, methods, etc. These
annotations can be applied just before the declaration of an element (constructor, method, classes, etc).
Syntax:
[Access Specifier] @interface <AnnotationName>
{
DataType <Method Name>() [default value];
}
JM-0 Page 35
Optional Class
16 January 2025 11:37
Optional is a generic class defined in the [Link] package, that got introduced in Java 8.
It facilitates the handling of potentially absent values in a more concise and expressive manner.
It provides a container-like structure to wrap objects, indicating the possibility of a value being present or absent.
Its primary purpose is to provide a safer alternative to handling null values, thereby reducing the risk of NullPointerException.
By explicitly acknowledging the possibility of an absent value, Optional encourages developers to write more robust and error-
resistant
Creating optional instances:
- [Link](T value)
2. T get():
Returns the value wrapped by the Optional if present.
Throws: NoSuchElementException if the Optional is empty.
3. T orElse(T defaultValue):
Returns the value wrapped by the Optional if present.
Returns: defaultValue if the Optional is empty.
JM-0 Page 36
5. T orElseThrow(Supplier<? Extends X> exceptionSupplier):
Returns the value wrapped by the Optional if present.
Throws an exception produced by the exceptionSupplier if the Optional is empty.
JM-0 Page 37
Comparator and Comparable
16 January 2025 12:10
Comparator Interface:
Comparator interface in java is used to order the objects of user-defined classes. A comparator object is capable of comparing
two objects of same class.
Syntax - public int compare(Object obj1,Object obj2)
Alternative method - [Link]([Link](Class::Field1).thenComparing(Class::Field2));
int compare(T o1, T o2)
static Comparator<T> comparing(Function<? super T,? extends U> keyExtractor)
static Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor)
static Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor)
static Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor)
boolean equals(Object obj)
static Comparator<T> naturalOrder()
static Comparator<T> nullsFirst(Comparator<? super T> comparator)
static Comparator<T> nullsLast(Comparator<? super T> comparator)
default Comparator<T> reversed() - returns comparator that contains reverse ordering of the provided comparator.
static Comparator<T> reverseOrder() - returns comparator that contains reverse of natural ordering.
default Comparator<T> thenComparing(Comparator<? super T> other) - returns a lexicographic-order comparator with
another comparator.
default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor)
default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor)
default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor)
Comparable Interface:
The Comparable interface in Java is used to define the natural ordering of objects for a user-defined class. It is part of the
[Link] package and it provides a compareTo() method to compare instances of the class. A class has to implement a
Comparable interface to define its natural ordering.
Syntax -
public interface Comparable<T> {
int compareTo(T obj);
}
It compares the current object with the specified object.
It returns:
Negative, if currentObj < specifiedObj.
Zero, if currentObj == specifiedObj.
Positive, if currentObj > specifiedobj.
JM-0 Page 38
JM-0 Page 39
Collections Class
20 May 2025 12:08
Java's Collections class (in [Link]) is a utility class that provides static methods to operate on or return collections
like List, Set, and Map.
🧰 Commonly Used Collections Methods
🔁 Sorting & Shuffling
[Link](list); // Sorts list in natural order
[Link](list, comparator); // Sorts with custom comparator
[Link](list); // Reverses the order of list
[Link](list); // Randomly shuffles the list
🔍 Searching
[Link](list, key); // Binary search (must be sorted)
[Link](collection); // Max element
[Link](collection); // Min element
🔒 Synchronization (Thread-Safe Wrappers)
[Link](list);
[Link](set);
[Link](map);
🧱 Immutability
Collec [Link]fiableList(list);
Collec [Link]fiableSet(set);
Collec [Link]fiableMap(map);
♻ Filling, Copying, Replacing
[Link](list, value); // Replace all with value
[Link](destList, srcList); // Copy source into dest (dest must be same size or bigger)
[Link](list, oldVal, newVal); // Replace all oldVal with newVal
🆕 Singletons, Empty Collections
[Link](); // Returns empty list
[Link]("A"); // Returns an immutable singleton set
[Link]("A"); // Singleton list
🔄 Frequency & Disjoint
[Link](list, value); // Count of value
[Link](list1, list2); // True if no common elements
JM-0 Page 40
Functional Interface
20 January 2025 14:51
A functional Interface is an interface that contains only one abstract method (SAM - Single Abstract Method). Functional
Interface serves as the target type for lambda expressions and method references.
Syntax - @FunctionalInterface
interface <Name>{
<method>;
}
Built-in functional Interface:
- Consumer : A consumer is a functional interface that represents an operation that takes a single input and performs
some action on it. It does not return any value.
@FunctionalInterface
interface Consumer<T>{
void accept(T t);
}
- Supplier : A supplier is a functional interface that represents an operation that supplies a result. It does not take any
input
@FunctionalInterface
interface Supplier<T>{
T get();
}
- Function : A function is a functional interface that represents an operation that takes an input of type 'T' and produces
an output of type 'R'
@FunctionalInterface
interface Function<T,R>{
JM-1 Page 1
interface Function<T,R>{
R apply(T t);
}
Methods:
1. apply : abstract method and instance method
the primary method of the Function interface. It takes one argument and returns a result.
2. andThen : Instance and default method
method returns a composed function that first applies this function to its input, and then applies the after function to
the result.
3. compose : instance and default method
method returns a composed function that first applies the before function to its input, and then applies this function
to the result.
4. Identity : static and default method
method returns a function that always returns its input argument.
JM-1 Page 2
}
JM-1 Page 3
Lambda Expressions
27 January 2025 14:29
JM-1 Page 4
Optional
21 January 2025 09:29
Purpose of the class is to provide a type-level solution for representing optional values instead of a null references.
Creating Optional Objects:
- To create an empty Optional object, need to use its empty() static method
- We can also create an Optional object with the static method of().
But if we expect some null values then we can use the ofNullable() method.
JM-1 Page 5
Conditional Action :
If we use traditional code to check the null value, then this can result in a NullPointerException at runtime if a null value finds its way
into that code.
To handle this we use the Optional class
In typical functional programming style, we can execute perform an action on an object that is actually present
Default Value :
- orElse() : The orElse() is used to retrieve the value wrapped inside an Optional instance. It takes one parameter, which acts as a
default value. It takes object as input.
- orElseGet() : orElseGet() method is similar to orElse(). However, instead of taking a value to return if the Optional value is not
present, it takes a supplier functional interface, which is invoked and returns the value of the invocation.
If a value is present, returns the value, otherwise returns the result produced by the supplying function.
when using orElseGet() to retrieve the wrapped value, the getMyDefault() method is not even invoked since the contained value
is present. However, when using orElse(), whether the wrapped value is present or not, the default object is created. So in this
case, we have just created one redundant object that is never used.
JM-1 Page 6
- Exceptions with orElseThrow()
Instead of returning a default value when the wrapped value is not present, it throws an exception. Method can also be used
without arguments default exception-> NoSuchElementException.
- get() : get() can only return a value if the wrapped object is not null; otherwise, it throws a NoSuchElementException.
Syntax : public T get()
- filter() : It takes a predicate as an argument and returns an Optional object. If the wrapped value passes testing by the predicate,
then the Optional is returned as-is
Syntax : public Optional<T> filter(Predicate<? super T> predicate)
Throws NullPointerException -> if filter is null
- isPresent : returns true if there is a value or else false
Syntax : public boolean isPresent()
- ifPresent : if a value is present, invoke the specified consumer with the value, otherwise do nothing.
Throws NullPointerException -> if consumer is null
Syntax : public void ifPresent(Consumer<? super T> consumer)
- Map : If a value is present, apply the provided mapping function to it, and if the result is non-null, return an optional describing
the result.
Throws NullPointerException -> if mapping in null
Syntax : public <U> Optional<U> map(Function<? super T,? extends U> mapper)
- toString : returns a non-empty string representation of this optional suitable for debugging.
- Equals : overrides equals in class Object
Syntax : public boolean equals(Object obj)
JM-1 Page 7
Streams
24 January 2025 16:34
JM-1 Page 8
Abstract Methods / Instance Methods / :
1. allMatch(Predicate) : returns whether all the elements of this stream match the provided predicate.
boolean allMatch(Predicate<? super T> predicate)
2. anyMatch(Predicate) : returns whether any elements of this stream match the provided predicate.
Boolean anyMatch(Predicate<? super T> predicate)
3. collect(Collector) : performs a mutable reduction operation on the elements of this stream using collector
<R,A> R collect(Collector<? super T,A,R> collector)
4. Collect(Supplier, BiConsumer, BiConsumer) : performs mutable reduction operation.
<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)
5. Count() : returns the count of elements in this stream
Long count()
6. Distinct() : returns a stream consisting of the distinct elements
Stream<T> distinct() -> [Link](Object)
7. Filter(Predicate) : returns a stream consisting of the elements of this stream that matches the given predicate.
Stream<T> filter(Predicate<? Super T> predicate)
8. findAny() : returns an Optional describing some element of the stream, or any empty Optional if the stream is empty.
Optional<T> findAny()
9. findFirst() : returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty.
Optional<T> findFirst()
10. flatMap(Function) : returns a stream consisting of the results of replacing each element of this stream
<R> Stream<R> flatMap(Function)
DoubleStream flatMapToDouble(function)
IntStream flatMapToInt()
LongStream flatMapToLong()
11. forEach(Consumer) -> void
12. forEachOrdered(Consumer) -> void
13. Limit(long maxSize) -> Stream<T>
14. Map(Function) -> <R> Stream<R>
mapToDouble(Function)
mapToInt(Function)
mapToLong(Function)
15. Max(Comparator) -> Optional<T>
JM-1 Page 9
15. Max(Comparator) -> Optional<T>
16. Min(Comparator) -> Optional<T>
17. noneMatch(Predicate) -> boolean
18. Peek(Consumer) -> Stream<T>
19. Reduce(BinaryOperator) -> Optional<T>
Reduce(T identity, BinaryOperator) -> T
Reduce(U identity, BiFunction, BinaryOperator) -> <U> U
20. Skip(long) -> Stream<T>
21. Sorted() -> Stream<T>
Sorted(<Comparator>) -> Stream<T>
22. toArray() -> Object[]
toArray(IntFunction) -> <A> A[]
Static Methods / Default Methods:
1. Builder() : <T> [Link]<T>
2. Concat(Stream, Stream) : <T> Stream<T>
3. Empty() : <T> Stream<T>
4. Generate(Supplier) : <T> Stream<T>
5. Iterate(T seed, UnaryOperator) : <T> Stream<T>
6. Of(T… values) : <T> Stream<T>
Terminal and Intermediate Operators:
JM-1 Page 10
Record Class
29 January 2025 10:55
Record class by default extends [Link] class which is a common super abstract class of all record classes.
Introduced in java 14 but as integrated in java 16 as standard class.
Record classes are the special kind of classes, help to model plain data aggregates with less ceremony than normal classes.
In record, accessors, constructor, equals, hashCode, toString methods are created automatically.
Record are final and cannot extends any class, record but they can implements interface.
Record can be private but only in nested class or in a class which can be accessed within the class.
All fields are private and final by default and it can contain static variables.
The constructor can be modified in the record -> Canonical parameterized constructor
All methods are public and Records can be passed as a parameter to a method
We can also declare static fields, static initializers and static methods in record and behave same as normal class.
Cannot declare instance variables or instance initializers in record class.
All the methods and fields are by default public final.
Java allows method overloading, and method overloading depends on the method signature.
We can declare the instance methods in a record class, independent of whether you implement your own accessor methods.
We can also declare nested classes and interfaces in a record class, including nested record classes( which is implicitly static)
Features of Record classes :
1. Can create a generic record class
2. Can declare a record class that implements one or more interfaces.
3. Can annotate a record class and its individual components
Why use Records ?
- Immutability
- Efficiency
- Preservation of core logic rather than boiler codes
The class [Link] has two methods related to record classes:
- RecordComponent[] getRecordComponents(): Returns an array of [Link] objects, which
correspond to the record class's components.
- boolean isRecord(): Similar to isEnum() except that it returns true if the class was declared as a record class.
JM-1 Page 11
Sealed Classes
29 January 2025 10:21
A sealed class is a class that cannot be inherited by other classes. It is used to restrict the inheritance of a class, ensuring that no
other class can derive from it.
By sealing a class, we can specify which classes are permitted to extend it and prevent any other arbitrary class from doing so.
Declaring sealed classes:
Add the sealed modifier to its declaration. Then after any extends and implements clauses, add the permits clause.
If you have declared the permits class within the same file then you can omit the permits clause.
JM-1 Page 12
conversion may require a test at run time to validate that a value of type S is a legitimate value of type T.
The class UtahTeapot is final, it's impossible for a class to be a descendant of both Polygon and UtahTeapot. Therefore, Polygon and
UtahTeapot are disjoint, and the cast statement Polygon p = (Polygon) u isn't allowed.
APIs Related to Sealed Classes and Interfaces
The class [Link] has two new methods related to sealed classes and interfaces:
- [Link][] permittedSubclasses(): Returns an array containing [Link] objects
representing all the permitted subclasses of the class if it is sealed; returns an empty array if the class is not sealed
- boolean isSealed(): Returns true if the given class or interface is sealed; returns false otherwise
JM-1 Page 13
Collectors
29 January 2025 12:32
JM-1 Page 14
Clean Code
30 January 2025 12:02
Bloaters:
Bloaters are code, methods and classes that have increased to such gargantuan proportions that they
are hard to work with.
Includes
- Long Method : method contains too many lines of code, longer than 10 lines of code.
- Primitive Obsession : use of primitives instead of small objects for simple tasks, use of constants
for coding information, use of string constants as field names for use in data arrays.
- Data Clumps : repeating data comprises the fields of a class, use extract class to move the fields to
their own class, introduce parameter object and preserve whole object.
- Large Class : when a class is wearing too many functional behavior then split it into extract class,
extract subclass and extract interface and keeping the data consistent by duplicating it and
observing the changes.
- Long Parameter List : replace parameter with method call, preserve whole object and introduce
parameter object.
Object-Orientation Abusers
Incorrect application of object-oriented programming principles.
Includes
- Alternative Classes with different interfaces : different classes with same method functionality, to
solve we can add the interface of classes and rename methods, move method, add parameter and
parameterize method, use of super if part of functionality is duplicate.
- Refused Bequest : if subclass uses only some of the methods and properties inherited from its
super class - Replace inheritance with delegation, extract all fields and methods needed by the
subclass from parent class, put them in new super class and set the both class to inherit new super
class.
- Temporary field : replace method with method object and introduce null object
- Switch statements
Change Preventers
It means if you need to change something in one place in your code, you have to make many changes in
other places too. Program development becomes much more complicated and expensive as a result.
Includes
- Divergent Change : split up the behavior of class and if same behavior combine them through
inheritance
- Parallel Inheritance Hierarchies :
Whenever you create a subclass for a class, you find yourself needing to create a
subclass for another class. - remove the inheritance and make the instance of one
hierarchy refer to instances of another hierarchy.
- Shotgun Surgery : making any modifications requires that you make many small changes to many
different classes. - use inline class and by creating new class with existing behavior.
Dispensables:
A dispensable is something pointless and unneeded whose absence would make the code cleaner, more
efficient and easier to understand.
Includes
- Comments : "The best comment is a good name for a method or a class." splitting the complex
expression into subexpression and use of assertion and renaming the method.
- Data Class :
A data class refers to a class that contains only fields and crude methods for accessing them
(getters and setters). These class are not independently operatable - encapsulate field, use of
collection, use records
- Lazy Class : If a class doesn't do enough to earn your attention, it should be deleted. - near-useless
should be used in inline Class
JM-2 Page 1
should be used in inline Class
- Duplicate Code - use same method in all calls, if same code exists in two subclasses then write the
method code in super class, Pull-up field, pull constructor body, form template method use
substitute algorithm for different algorithms, consolidate conditional expression.
- Dead Code : variable, parameter, field, method or class is no longer used.
- Speculative Generality : for future use
Couplers:
This group contribute to excessive coupling between the classes or show what happens if coupling is
replaced by excessive delegation.
Includes
- Feature Envy : if a method access the another object data more than its own data - move , extract
method
- Incomplete Library Class : library is read-only - introduce foreign method , use of local extension.
- Middle Man : if a class performs only one action, delegating work to another class - Remove
middle man , elimination of message chains.
- Inappropriate Intimacy : One class uses the internal fields and methods of another class - move
method and move field, extract class and hide delegate, change bidirectional association to
unidirectional, replace delegation with inheritance.
- Message Chains : a()->b()->c()->d() - hide delegates, move and extract delegate.
JM-2 Page 2
Principles of Software development
04 February 2025 11:31
JM-2 Page 3
These principles guide developers in creating more readable, flexible, and sustainable software
systems. These are not rules, but rather suggestions that will facilitate the life cycle of an
application and code.
• S) Single-responsibility principle (SRP): Each object, class, and method needs to have a single
responsibility.
• O) Open–closed principle (OCP): Software entities should be open to extension but closed to
modification.
• L) Liskov substitution principle (LSP): Objects of a superclass should be substitutable by objects of
their subclasses, and the application should still function as expected.
• I) Interface segregation principle (ISP): Software should be divided into several independent
parts.
• D) Dependency inversion principle (DIP): We should rely on abstractions, not concrete
implementations.
JM-2 Page 4
Design Patterns
06 February 2025 11:11
Design patterns represent the best practices used by the experienced object-oriented software
developers. Design patterns are solutions to general problems that software developers faced during
software development. These solutions were obtained by trial and error by numerous software
developers over quite a substantial period of time.
Types:
1. Creational patterns:
These patterns provide various object creation mechanisms, which increase flexibility and reuse of
existing code.
- Factory Method * : It is a pattern that provides an interface for creating objects in a superclass,
but allows subclasses to alter the type of objects that will be created. - creating an interface. It is
used when all the object creation and its business logic we need to keep at one place.
- Abstract Factory * : It is a pattern that lets you produce families of related objects without
specifying their concrete classes. - creating an abstract class and by creating a reference for
abstract class.
JM-2 Page 5
- Builder * : It is a pattern that lets you construct complex objects step by step. The pattern allows
you to produce different types and representations of an object using the same construction
code. - creating a separate builder interface for the input handling
JM-2 Page 6
-
- Prototype : It is a pattern that lets you copy existing objects without making your code dependent
on their classes, since object creation is expensive.
- Singleton * : It is a pattern that lets you ensure that a class has only one instance, while providing
a global access point to this instance. - By providing the private constructor and creating a static
method that pass the private constructor as a parameter.
4 ways to achieve:
-> Eager : by creating private constructor and during loading only object is created and since
object is of static type so only one copy exists.
JM-2 Page 7
-> Synchronized Method :
Problem : it is very expensive if I have 100 threads then if 1 accessing the method then it acquire
then and so on for all threads. Since Locking is expensive method. To overcome this we use
Double locking
-> Double Locking : before acquiring lock first we check and then in the synchronized block we are
checking again which make sure lock is not acquired to complete method.
-> Enum : Thread-safe, Serialization-safe, Reflection-safe, Best way to enforce a true singleton
-> Bill Pugh : clever way to implement lazy-loaded, thread-safe singletons without
JM-2 Page 8
-> Bill Pugh : clever way to implement lazy-loaded, thread-safe singletons without
synchronization overhead — using a static inner class.
2. Structural Patterns :
These patterns explain how to assemble objects and classes into larger structures while keeping
these structures flexible and efficient.
- Adapter : It allows object with incompatible interfaces to collaborate - It is special object that
converts the interface of one object so that another object can understand it.
Types : Object and class
- Bridge : It is that lets you split a large class or set of closely related classes into two separate
hierarchies - abstraction and implementation - which can be developed independently of each
other.
- Composite : It is that lets you compose objects into tree structures and then work with these
structures as if they were individual object.
- Decorator * : It is that lets you watch new behaviors to objects by placing these objects inside
special wrapper objects that contain the behaviors.
- Facade : It is that provides a simplified interface to a library, a framework, or any other complex
set of classes.
- Flyweight : It is that lets you fit more objects into the available amount of RAM by sharing
common parts of state between multiple objects instead of keeping all of the data in each object.
- Proxy : It is that lets us provide a substitute or placeholder for another object. A proxy controls
access to the original object, allowing us to perform something either before or after the request
gets through to the original object.
3. Behavioral patterns :
These patterns are concerned with algorithms and the assignment of responsibilities between
objects.
- Chain of responsibility : It is that lets us pass requests along a chain of handlers. Upon receiving a
request, each handler decides either to process the request or to pass it to the next handler in the
chain.
- Command : It is that turns a request into a stand-alone object that contains all information about
the request. This transformation lets us pass requests as a method arguments, delay or queue a
request's execution, and support undoable operations.
- Iterator : It is that lets you traverse elements of a collection without exposing its underlying
representation (list).
- Mediator : It is that lets you reduce chaotic dependencies between objects. The pattern restricts
direct communications between the objects and forces them to collaborate only via a mediator
JM-2 Page 9
direct communications between the objects and forces them to collaborate only via a mediator
object.
- Memento : It is that lets you save and restore the previous state of an object without revealing
the details of its implementation.
- Observer : It is that lets you define a subscription mechanism to notify multiple objects about any
events that happen to the object they're observing.
- State : It is that lets an object alter its behavior when its internal state changes. It appears as if the
object changed its class.
- Strategy * : It is that lets you define a family of algorithms, put each of them into a separate class,
and make their object interchangeable.
- Template Method : It is that defines the skeleton of an algorithm in the superclass but lets
subclasses override specific steps of the algorithm without changing its structure.
- Visitor : It is that lets you separate algorithms from the objects an which they operate.
JM-2 Page 10
Spring Framework
12 February 2025 11:09
Spring is use to create Java Enterprise applications. It provides to embrace the java language in an
enterprise environment, with support for Groovy and Kotlin as alternative languages on the JVM. It can
be used to create many kinds of architectures depending on an application's needs .
As of Spring Framework 6.0, Spring requires Java 17+.
Spring is open source. It has a large and active community that provides continuous feedback based on a
diverse range of real-world use cases.
What is Spring Framework?
Roderick B. Johnson, an Australian computer specialist officially released the Spring Framework in 2004.
Spring is a powerful lightweight application development framework used for Java Enterprise edition
(JEE).
Spring is a complete and a modular framework for developing enterprise applications.
Spring framework can be used for all layer implementations.
It is a framework of frameworks because it provides support to various frameworks such as Struts,
Hibernate, Tapestry, EJB, JSF, etc
Spring Features :
- Lightweight : with respect to size and transparency.
- Inversion of Control (IOC) : Loose coupling is achieved using Inversion of Control. The objects give
their own dependencies instead if creating or looking for dependent objects.
All objects in Spring are called as Beans.
- Aspect Oriented Programming (AOP) : By separating application business logic from system
services, it supports Aspect Oriented Programming and enables cohesive development.
- Container : Spring framework creates and manages the lifecycle and configuration of application
objects.
- Dependency Injection : Allows you to develop loosely coupled applications. The unit testing
becomes easier with loosely coupled.
- Transaction Management : It provides a generic abstraction layer. It is not tied to J2EE
environments, and it can be used in container-less environments.
- Integration with other frameworks : It doesn't try to solve the problems that have been already
solved. It just tries to integrate them with its framework which provides a solution to greater
problems.
Advantages of using Spring Framework :
- Works on POJO (Plain Old Java Object ) which makes your application lightweight.
- Provides predefined templates for JDBC, Hibernate, JPA etc. thus reducing the effort to writing
codes
- Objects are loosely coupled -> dependency injection feature
- The development of Java Enterprise Edition (JEE) applications become faster.
- It also provides strong abstraction to JEE specifications.
JM-3 Page 1
It also provides strong abstraction to JEE specifications.
JM-3 Page 2
- making it easier to switch between different implementations
- greater modularity of a program
- greater ease in testing a program by isolating a component or mocking its dependencies, and
allowing components to communicate through contracts
Tasks performed by IoC Container are
- Instantiating the bean
- Wiring the bean together
- Configuring the beans
- Managing the bean's entire life-cycle
IoC container receives metadata from either an XML file, Java annotations, or Java code and works
accordingly. IoC adds the flexibility and control of application, and provides a central place of
configuration management for Plain Old Java Objects (POJO) of our application.
JM-3 Page 3
We can achieve Inversion of Control through various mechanisms such as: Strategy design pattern,
Service Locator pattern, Factory pattern, and Dependency Injection (DI).
Dependency Injection :
JM-3 Page 4
all of its sub-packages for components.
5. @Autowired -> Marks a constructor field, setter method, or config method as to be autowired by
dependency injection. We can mark whether the annotated dependency is required or not using
"required" attribute. By default, its value is true.
6. @Primary -> Indicates that a bean should be given preference when multiple candidates are
qualified to autowire a single-valued dependency.
7. @Qualifier -> During autowiring, if more than one bean of same type is available in the container
then container will throw runtime exception. To fix this problem, we have to specifically tell spring
that which bean has to be injected using this annotation.
To remove the dependency of a class, we need to use interface which makes class loosely coupled.
However, for specific areas, they do form a compelling argument to pick as alternatives:
Guice: Offers a robust IoC container for Java applications
Play: Quite aptly fits in as a Web framework with reactive support
Hibernate: An established framework for data access with JPA support
Other than these there are some recent additions that offer wider support than a specific domain but
still do not cover everything that Spring has to offer:
Great question! These three concepts are fundamental to writing clean, flexible, and maintainable
code—especially in Spring Boot. Let me break each down clearly and show how they relate to each
other in Spring Boot apps.
Dependency Inversion Principle (DIP)
Definition:
One of the SOLID principles of OOP. It states:
“High-level modules should not depend on low-level modules. Both should depend on abstractions
(interfaces or abstract classes). Also, abstractions should not depend on details. Details should depend
on abstractions.”
Why it matters:
Reduces coupling between components.
Makes your code easier to extend and test.
Example:
Instead of a service directly creating or using a concrete repository class, both depend on an interface:
public interface UserRepository {
User findById(Long id);
}
JM-3 Page 5
rather than the object creating them itself.
In Spring Boot:
Spring’s IoC container automatically injects dependencies for you.
Common injection types: constructor injection (preferred), setter injection, field injection.
Example in Spring Boot:
@Service
public class UserService {
// Constructor injection
public UserService(UserRepository userRepository) {
[Link] = userRepository;
}
@Repository
public class UserRepositoryImpl implements UserRepository {
// implementation
}
Spring Boot automatically injects UserRepositoryImpl into UserService when it creates the beans.
Inversion of Control (IoC)
Definition:
A broad principle where the control of creating and managing objects is inverted — instead of the
program controlling object creation, an external container/framework (like Spring) does it.
How it works in Spring Boot:
You declare components (@Component, @Service, @Repository, etc.).
Spring IoC container manages their lifecycle and dependencies.
You don’t instantiate dependencies manually.
JM-3 Page 6
SpringBoot
17 February 2025 19:20
SpringBoot makes it easy to create stand-alone, production grade spring based applications that you
can Just Run.
Problems with Spring which is solved by SpringBoot:
- Huge Framework
- Multiple setup and Configuration steps
- Multiple Build and Deploy steps
What SpringBoot is not?
- It is not an application or web server
- Does not implement any specific framework (JPA,JMS)
- Does not generate code
- Is not a replacement for spring framework
What SpringBoot is?
- Opinionated : takes default packages for the project execution
- Convention over configuration : configuration are done automatically
- Standalone : it contains all server, containers, deploy, execution
- Production Ready
SpringBoot is a tool developed on top of core spring framework which provides RAD (Rapid Application
Development).
The main aim of SpringBoot is to let developers to create spring production grade applications and
services with very less effort
Normally in real-time spring applications, it includes writing many XML configurations, server setting,
adding dependencies, etc. But with SpringBoot we can avoid all these boilerplate code, writing XML
configurations and annotations.
We can create a real-time production ready applications within minutes.
SpringBoot comes with inbuilt server, we no longer have to use any external servers like Tomcat, Glass-
fish or anything else, so don't have to deploy WAR files.
Advantages of SpringBoot :
1. SpringBoot helps in resolving dependency conflict. It identifies required dependencies and import
them for you.
2. It has information of compatible version for all dependencies. It minimizes the runtime classloader
issues.
3. It's "opinionated defaults configuration" approach helps you in configuring most important pieces
behind the scene. Override them only when you need. Otherwise everything just works, perfectly.
It helps in avoiding boilerplate code, annotations and XML configurations.
4. It provides embedded HTTP server Tomcat so that you can develop and test quickly.
5. It has excellent integration with IDEs like eclipse and intelliJ idea.
SpringBoot Templates :
It is highly dependent on the starter templates feature which is very powerful and works flawlessly.
What is Starter Templates?
SpringBoot starters are templates that contain a collection of all the relevant transitive
dependencies(A->B, B->C=A->C) that are needed to start a particular functionality. For example, If you
want to create a Spring WebMVC application then in a traditional setup, you would have included all
required dependencies yourself. It leaves the chances of version conflict which ultimately result in more
runtime exceptions.
@SpringBootApplication Annotation:
This annotation is a shortcut of applying 3 annotations in one statement.
1. @SpringBootConfiguration : is new annotation in SpringBoot 2. Previously, we have been using
@Configuration. You can use @Configuration in place of this. Both are same thing. It indicates that
a class provides SpringBoot application @Configuration. It simply means that annotated class is a
configuration class and shall be scanned for further configurations and bean definitions.
JM-3 Page 7
configuration class and shall be scanned for further configurations and bean definitions.
2. @EnableAutoConfiguration : is used to enable auto-configuration of the Spring Application
Context, attempting to guess and configure beans that you are likely to need. Auto-configuration
classes are usually applied based on your class path and what beans you have defined.
3. @ComponentScan
What is spring-boot-starter-parent dependency?
The spring-boot-starter-parent dependency is the parent POM providing dependency and plugin
management for Spring Boot-based applications. It contains the default versions of Java to use, the
default versions of dependencies that SpringBoot uses, and the default configuration of the Maven
plugins.
Spring-boot-starter Maven Templates :
Dependency management was becoming very complex task which required good amount of technical
expertise to do it correctly. With the introduction of SpringBoot starter templates, you can get a lot of
help in identifying the correct dependencies to use in project if you want to use in project if you want to
use any popular library into your project.
SpringBoot comes with over 50+ different starter modules, which provide ready-to-use integration
libraries for many different frameworks, such as database connections that are both relational and
NoSQL, web services, social network integration, monitoring libraries, logging, template rendering, and
the list just keeps going on.
JM-3 Page 8
To work with web we use WebApplicationContext
[Link] -> for logging info
JM-3 Page 9
If value is not defined in [Link] then the application won't run and throws compile-time
error as Injection of autowired dependencies failed. To avoid this we can add default value in
@Value("${[Link]:default value}")
If we have default value and [Link] also then the precedence is given to
[Link] value.
JM-3 Page 10
JPA
20 February 2025 09:39
Java Persistence API is a set of guidelines to be followed to represent Java Objects in databases.
JPA provides a set of concepts in form of interfaces and annotations to configure Java Objects.
To reduce the burden of writing codes for relational object management, a programmer follows the JPA Provider
framework, which allows easy interaction with database instance.
JPA is just a specification that facilitates object-relational mapping to manage relational data in Java applications. It
provides a platform to work directly with objects instead of using SQL statements.
ORM
ORM tools are providing implementation for JPA
Hibernate framework provides the facility to create the tables of the database automatically.
Also provides data query and retrieval facilities.
It generates the SQL calls and attempts to relieve the developer from manual result set handling and object conversion.
It keeps the application portable to all supported SQL databases with little performance overhead.
JM-3 Page 11
Session Factory, Transaction Factory, Connection Provider and Transaction are interfaces and classes .
JNDI -> Java Named Data source Interface -> managing the data source connections
JDBC -> Java DataBase Connectivity
JTA -> Java Transaction API
Adding the dependency :
Dialects :
The dialects specifies the type of database used in hibernate so that hibernate generate appropriate type of SQL
statements. For connecting any hibernate application with the database, it is required to provide the configuration of SQL
dialect.
It is used for the translation of the objects to SQL queries.
We need to provide the dialect configuration to the hibernate for the translation.
Present based upon the driver provided, the Hibernate auto configures the dialects so it is not required to define in .xml
file, but if you want to add the property you can still add but it is optional property.
Configuration of [Link]
JM-3 Page 12
[Link] = update/create -> to automatically create the tables based upon the objects provided. Create ->
it only creates the tables initially and update -> it makes sure to triggers the table for every changes and makes on
changes as per the operations.
Coding the Entity class :
In order to work with the table in database, create a class with the name of table.
Use the annotation,
- @Entity -> to map the class to the table
- @Id -> to mark the field as primary key
- @GeneratedValue -> to indicate that its value is auto generated.
Generator Class :
It is used to generate the unique identifier for the objects of persistent class. There are many generator classes defined in
the Hibernate framework.
If we want the primary key value to be generated automatically for us, we can add the @GeneratedValue annotation.
This can use 4 generation types: Auto, IDENTITY, SEQUENCE, TABLE.
If we don't specify the value explicitly, the generation type defaults to AUTO.
Mapping Hibernate :
- Many to One : Many employees belong to one department.
- One to Many : One department has many employees. Usually, it’s the inverse side of Many-to-One.
JM-3 Page 13
- One to One : One person has one passport.
JM-3 Page 14
Tx Management :
A transaction simply represents a unit of work in step way. In such case, if one steps fails, the whole transaction fails. A
transaction can be described by ACID properties (Atomicity, Consistency, Isolation and Durability)
JM-3 Page 15
HCQL (Hibernate Criteria Query Language)
HCQL is used to fetch the records based on the specific criteria. The Criteria interface provides methods to apply criteria.
It uses builder pattern internally.
HCQL provides methods to add criteria, so it is easy for the java programmer to add criteria. The java programmer is able
to add many criteria on a query.
The Criteria interface provides many methods to specify the criteria. The object of criteria can be obtained by calling the
createCriteria() method of Session interface.
JM-3 Page 16
POJO - Pain Old Java Object
A POJO is a simple Java object that follows standard conventions without depending on any special framework or library
Characteristics of a POJO:
Encapsulation – Fields are usually private, with public getters and setters.
No Special Restrictions – It does not extend any framework-specific classes or implement interfaces.
No Annotations (Optional) – A pure POJO does not use annotations, but in ORM, annotations are used to define
mappings.
Serializable (Optional) – To support serialization, it can implement Serializable.
Why Use POJOs in ORM?
Decouples business logic from persistence logic.
Makes data handling simple and maintainable.
Ensures portability between different frameworks (Hibernate, EclipseLink, etc.).
Annotations :
- @Entity ->
- @Table(name="table") -> creates table with specified name rather than with class name
- @Id -> to keep the primary key
- @Column(name="Filed")
- @GeneratedValue(strategy=type)-> GenerationType. AUTO / IDENTITY / SEQUENCE / TABLE
Connect to database :
[Link] contains factory of persistence unit / properties.
[Link] contains all the configurations of the database.
[Link] is configured at src/main/resources/META-INF/[Link] file
[Link] contains
- [Link] property
- [Link]
- [Link]
- [Link]
- [Link]
[Link]("persistenceUnitName") -> to get the specified connection from the persistence unit. It
contains the database connection details -> returns EntityManagerFactory
EntityManager -> to get the entity manger from the entityManager factory -> it interacts with database layer and
persistence layer.
After connection to database, it will generate the logs.
- Uses hibernate connection pool
By default Auto Commit is false, if we want to enable it we need to add
<property name="[Link]" value="true"/> in [Link] file
Hibernate Default connection pool size is 20 and min is 1.
To Save the add in the table -> [Link](classObject)
To do any operation with the database, we need to begin the transaction , then operation and at last commit transaction.
Between the begin and commit, whatever operation is specified will be worked on database also
Select queries doesn't require any transactions.
JM-3 Page 17
Updating values
ReadAll Values
JM-3 Page 18
JM-3 Page 19
JM-3 Page 20
SpringBoot Data JPA
20 February 2025 20:47
JM-3 Page 21
JM-3 Page 22
Annotations
21 February 2025 09:34
@SpringBootApplication :
→ This is a meta-annotation that combines:
- @Configuration (Defines this as a configuration class)
- @EnableAutoConfiguration (Automatically configures Spring Boot)
- @ComponentScan (Scans for components, services, and controllers)
@Configuration : The @Configuration annotation in Spring Boot is used to define Java-based configuration classes that register
beans in the Spring container. It is an alternative to XML-based configuration.
How @Configuration Works
A class annotated with @Configuration acts as a source of bean definitions.
Methods within the class that are annotated with @Bean define beans that Spring will manage.
@Configuration is often used along with @ComponentScan and @EnableAutoConfiguration.
When to Use @Configuration
When you manually define beans instead of relying on @Component scanning.
When you externalize configurations (e.g., defining beans using properties).
When you define third-party beans that cannot be annotated with @Component.
@ComponentScan : The @ComponentScan annotation in Spring Boot is used to automatically detect and register Spring-managed
components (beans) in the application context. It tells Spring where to look for classes annotated with @Component, @Service,
@Repository, and @Controller.
How @ComponentScan Works
By default, Spring Boot scans the package where the main application class is located and all its subpackages.
If you need to scan additional or different packages, you can specify them explicitly.
JM-3 Page 23
Only CustomService is included, even if other services exist.
When to Use @ComponentScan
When your components are outside the default package.
When you need to filter specific beans to include/exclude.
When configuring modular applications with separate packages.
@EnableAutoConfiguration : The @EnableAutoConfiguration annotation in Spring Boot enables automatic configuration based on
the classpath dependencies. It allows Spring Boot to detect and configure beans automatically without requiring explicit
@Configuration setup.
How @EnableAutoConfiguration Works
Spring Boot scans the classpath for required dependencies.
It automatically registers beans based on the dependencies present with default configurations.
Uses Spring Boot’s auto-configuration classes from the spring-boot-autoconfigure module.
It is included in @SpringBootApplication, so it is usually not required explicitly.
JM-3 Page 24
When to Use @Component
When defining utility classes or generic beans.
When using custom annotations (meta-annotations).
When manual registration using @Bean is unnecessary.
@Autowired : The @Autowired annotation in Spring Boot automatically injects dependencies (Spring beans) into a class. It
eliminates the need for manual bean instantiation, making dependency injection (DI) seamless.
How @Autowired Works
Spring automatically finds and injects the required bean from the application context.
Supports three injection types:
1. Constructor Injection (Recommended) -> Constructor-based injection is preferred because:
It ensures that the required dependencies are available when the object is created.
Makes the class immutable (safer for testing).
JM-3 Page 25
If a bean might not be available, set required = false.
JM-3 Page 26
How @Entity Works
Each entity represents a database table.
Each field corresponds to a column in the table.
The class must have a primary key (@Id).
Works with JPA (spring-boot-starter-data-jpa).
Spring Boot automatically creates the database table if [Link]-auto=update is set in [Link]
JM-3 Page 27
@Bean(destroyMethod = "methodName")
Specifies a custom destroy method for Spring beans.
Useful for manually managing cleanup logic.
@Service : The @Service annotation in Spring Boot is a specialized version of @Component, used to define business logic classes
(Service Layer) in a Spring application. It is part of the Service Layer in the MVC architecture.
Purpose of @Service
Marks a class as a Service so that Spring can detect and manage it.
Used for business logic (processing, calculations, validation, etc.).
Supports Dependency Injection with @Autowired.
Works like @Component, but semantically represents a Service Layer.
When to Use @Service?
When handling business logic in your application.
When interacting with repositories to process data before sending it to the controller.
When you need dependency injection for reusable business methods.
@Transactional : The @Transactional annotation in Spring Boot ensures that database operations (CRUD) happen within a
transaction. If an error occurs, all changes are rolled back automatically to maintain data consistency.
Why Use @Transactional?
Ensures atomicity – either all operations succeed or none.
Automatically rolls back if an exception occurs.
Manages multiple database operations in one unit of work.
Improves performance by reducing database calls.
JM-3 Page 28
Improves performance by reducing database calls.
JM-3 Page 29
Why Use @PostConstruct?
Runs initialization logic after dependency injection.
Useful for setting up resources (e.g., database connections, caches).
Ensures certain methods execute automatically when the application starts.
Avoids manual invocation of setup methods.
When to Use @PostConstruct?
When you need initial setup logic after Spring initializes a bean.
When you want to preload data in an application.
When you need to initialize caches or connections.
@PreDestroy : The @PreDestroy annotation is used to execute a method before a bean is destroyed by the Spring container. It is
mainly used for cleanup tasks, such as closing database connections, stopping background threads, or releasing resources.
Why Use @PreDestroy?
Ensures cleanup logic is executed before the application shuts down.
Prevents memory leaks by closing open resources.
Works with singleton-scoped beans (as Spring manages their lifecycle).
Runs automatically without requiring manual invocation.
@PreDestroy with Thread Management
If a service starts a background task (like a scheduled job), we can use @PreDestroy to stop it before shutdown.
JM-3 Page 30
Specify schema, indexes, and unique constraints for the table.
Helps Hibernate generate the correct table structure in the database.
JM-3 Page 31
When to Use @Column?
When renaming a column to match the database.
When setting constraints (nullable = false, unique = true).
When defining length (length = 255 for String).
When specifying decimal precision (precision = 10, scale = 2).
In Spring Boot (JPA/Hibernate), relationships between entities are defined using @OneToOne, @OneToMany, @ManyToOne,
and @ManyToMany. These annotations help establish relationships between tables in a relational database.
@ManyToMany : Many entities are related to many other entities.
Example: Many Students are enrolled in many Courses.
JM-3 Page 32
@OneToMany : One entity is related to many other entities
Example: One Department has many Employees.
JM-3 Page 33
@ManyToOne : Many entities are related to one entity (opposite of @OneToMany).
Example: Many Employees belong to one Department
JM-3 Page 34
What is orphanRemoval?
orphanRemoval = true automatically removes child entities when they are no longer referenced by the parent.
Works with @OneToOne and @OneToMany relationships.
Prevents orphan records in the database.
@GeneratedValue :
@JoinColumn :
@Override :
JM-3 Page 35
Bean Life Cycle
23 February 2025 19:18
JM-3 Page 36
The Spring Boot Lifecycle
Bean Creation: Spring Boot initializes the IoC container and creates beans based on configurations provided by @Bean,
@Component, and other annotations.
Bean Scanning: Spring Boot scans for classes annotated with @Component, @Service, @Repository, and @Controller, which is
configured in the main application class with @SpringBootApplication
@SpringBootApplication
public class MySpringBootApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}
@SpringBootApplication: Includes @Configuration, @EnableAutoConfiguration, and @ComponentScan.
Dependency Injection: After creating beans, Spring Boot performs dependency injection based on annotations like @Autowired
and @Qualifier.
Application Context Refresh: The application context is refreshed, making the application ready to handle requests or perform
tasks.
Bean Destruction: When the application context is closed, Spring Boot handles the destruction of beans. Beans with
@PreDestroy methods or those implementing DisposableBean are invoked for cleanup. This ensures resources are properly
released.
Example:
@Component
public class MyBean {
@PreDestroy
public void cleanup() {
[Link]("Cleaning up resources");
}
}
@PreDestroy: Marks a method to be called before the bean is destroyed.
BeanNameAware:
If the bean implements BeanNameAware or BeanFactoryAware or ApplicationContextAware, Spring injects the bean's name and
JM-3 Page 37
If the bean implements BeanNameAware or BeanFactoryAware or ApplicationContextAware, Spring injects the bean's name and
the bean factory into it, respectively.
It allows a bean to know its own name defined in the Spring container. This can be useful for logging or debugging.
BeanFactoryAware:
BeanFactoryAware is an interface that allows a bean to be aware of the BeanFactorythat created it. By implementing this
interface, the bean can interact with its BeanFactory directly. This can be particularly useful for dynamic bean lookups or
complex initialization logic.
BeanFactoryAware helps in scenarios where the standard dependency injection isn't flexible enough, like when you need to
create new instances of a bean on the fly.
Overusing BeanFactoryAware can lead to tight coupling with the Spring framework and make your code harder to test. Usually,
dependency injection should cover most of your needs.
Another thing to consider is to leverage other lifecycle interfaces or annotations like @PostConstruct and @PreDestroy to
manage your bean's lifecycle more cleanly. These can sometimes achieve what you need without resorting to
BeanFactoryAware.
ApplicationContextAware
This is similar to BeanFactoryAware, but it provides even more capabilities. ApplicationContext is like a superset of BeanFactory.
ApplicationContextAware enables beans to interact directly with the Spring IoC container by providing a callback interface. This
can be quite useful in scenarios where beans need to dynamically fetch other beans or access application-level resources. By
implementing the setApplicationContext method, beans can receive a reference to the ApplicationContext when they are
initialized.
ApplicationContext is the heart of Spring application. ApplicationContextAware allows beans to tap into the ApplicationContext’s
full capabilities, such as retrieving other beans by name or type, publishing events, accessing resources, and more.
It’s best to use ApplicationContextAware sparingly and only when absolutely necessary. In most cases, dependency injection
should suffice.
Pre-initialization (postProcessBeforeInitialization)
Before the bean initialization callbacks, the postProcessBeforeInitialization method of BeanPostProcessor is called. It allows
JM-3 Page 38
Before the bean initialization callbacks, the postProcessBeforeInitialization method of BeanPostProcessor is called. It allows
custom modification of new bean instances before initialization.
InitializingBean
The InitializingBean interface allows beans to perform initialization after their properties have been set. The afterPropertiesSet
method is called after dependency injection is complete.
Custom init
A custom init method is one you define and specify in the bean configuration. It provides more flexibility than
afterPropertiesSet.
Post-initialization (postProcessAfterInitialization)
After the initialization callbacks, the postProcessAfterInitialization method of BeanPostProcessor is called. This allows additional
custom modifications of new bean instances.
At this point, the bean is fully initialized and ready for use by other beans or components in the application.
Destruction Phases (DisposableBean and Custom Destroy Methods)
When the application shuts down or explicitly destroys the bean, Spring calls the destroy methods, either defined by
DisposableBean or custom methods specified by the developer.
Bean Lifecycle Stages
1. Definition -> Bean definition
2. Instantiation → Bean instance is created.
3. Populate Properties → Dependencies are injected.
4. Bean Name Aware → If the bean implements BeanNameAware, its setBeanName() method is called.
5. Bean Factory Aware → If the bean implements BeanFactoryAware, setBeanFactory() is called.
6. Pre-Initialization (BeanPostProcessor) → postProcessBeforeIni aliza on() is invoked.
7. Initialization → If the bean implements Ini alizingBean, a erProper esSet() is called OR init-method is executed.
8. Post-Initialization (BeanPostProcessor) → postProcessA erIni aliza on() is invoked.
9. Ready to Use → The bean is now available for use in the applica on.
10. Destruction → If the bean implements DisposableBean, destroy() is called OR destroy-method is executed before the bean
is removed.
JM-3 Page 39
Spring Rest
24 February 2025 09:08
JM-3 Page 40
interacting. Intermediary servers may improve system scalability by enabling load balancing and by providing shared
caches. They may also enforce security policies.
6. Code on demand (optional) : REST allows client functionality to be extended by downloading and executing code in
the form of applets or scripts. This simplifies clients by reducing the number of features required to be pre-
implemented.
Advantages:
Rest is an architectural style and not a protocol.
Fast. RESTful Web Services are fast because there is no strict specification like SOAP.
Language and platform independent : RESTful web services can be written in any programming language and executed in
any platform.
Permits different data format
REST requires less bandwidth and resource than SOAP.
REST is more preferred than SOAP.
HTTP Protocols :
RESTful web services make use of HTTP protocols as a medium of communication between client and server. A client sends a
message in form of HTTP Request and the server responds in the form of an HTTP Response. This technique is termed as
Messaging. These messages contain message data and metadata.
A HTTP Request has 5 major parts :
JM-3 Page 41
Response Header - contains metadata for the HTTP response message as key/value pairs. (content length, content type,
response date, server type)
Response Body - Response message content or resource representation.
HTTP methods :
GET- provides a read only access to a resource
POST - Used to create a new resource
DELETE - Used to remove a resource
PUT - Used to update an existing resource or replace a resource
Response Codes:
3. Level2 -> Correct HTTP verbs are used with each request.
For each of those requests, Http response code is provided.
JM-3 Page 42
For each of those requests, Http response code is provided.
4. Level3 -> The APIs support HATEOAS (Hypermedia As The Engine Of Application State)
Helps in Self-documentation.
RestController and Controller :
RestController=Controller + ResponseBody
@Controller
Used in traditional MVC applications.
Returns View (JSP, Thymeleaf, etc.) or data (if @ResponseBody is used).
If you want to return JSON/XML, you need @ResponseBody.
@RestController (@Controller + @ResponseBody)
Used in RESTful web services.
Returns data directly (JSON/XML) instead of a view.
Every method inside @RestController automatically has @ResponseBody.
ResponseEntity:
ResponseEntity<T> – Handling HTTP Responses
ResponseEntity<T> is a powerful way to send HTTP status codes, headers, and body.
It provides fine-grained control over the HTTP response.
Idemponent API :
An idempotent API is an API that produces the same result no matter how many times you call it with the same request.
If the request is executed once, twice, or multiple times, the outcome remains unchanged.
JM-3 Page 43
Rest API
24 February 2025 09:26
REST stands for Representational State Transfer and API stands for Application Program Interface. REST is a software
architectural style that defines the set of rules to be used for creating web services. Web services that follow the REST
architectural style are known as RESTful web services. It allows requesting systems to access and manipulate web resources by
using a uniform and predefined set of rules. Interaction in REST-based systems happens through the Internet’s Hypertext
Transfer Protocol (HTTP).
A Restful system consists of a:
A client who requests for the resources server who has the resources.
Architectural Constraints of RESTful API
There are six architectural constraints that makes any web service are listed below:
Uniform Interface
Stateless
Cacheable
Client-Server
Layered System
Code on Demand
The only optional constraint of REST architecture is code on demand. If a service violates any other constraint, it cannot strictly
be referred to as RESTful.
Uniform Interface
It is a key constraint that differentiates between a REST API and a Non-REST API. It suggests that there should be a uniform way
of interacting with a given server irrespective of device or type of application (website, mobile app).
There are four guidelines principles of a Uniform Interface are:
Resource-Based: Individual resources are identified in requests.
Manipulation of Resources Through Representations: The client has a representation of the resource and it contains enough
information to modify or delete the resource on the server, provided it has permission to do so.
Self-descriptive Messages: Each message includes enough information to describe how to process the message so that the
server can easily analyze the request.
Hypermedia as the Engine of Application State (HATEOAS): It need to include links for each response so that client can
discover other resources easily.
Stateless :
It means that the necessary state to handle the request is contained within the request itself and server would not store
anything related to the session. In REST, the client must include all information for the server to fulfill the request whether as a
part of query params, headers or URI. Statelessness enables greater availability since the server does not have to maintain,
update or communicate that session state. There is a drawback when the client need to send too much data to the server so it
reduces the scope of network optimization and requires more bandwidth.
Cacheable
Every response should include whether the response is cacheable or not and for how much duration responses can be cached
at the client side. Client will return the data from its cache for any subsequent request and there would be no need to send the
request again to the server. A well-managed caching partially or completely eliminates some client–server interactions, further
improving availability and performance. But sometime there are chances that user may receive stale data.
Client-Server
REST application should have a client-server architecture. A Client is someone who is requesting resources and are not
concerned with data storage, which remains internal to each server, and server is someone who holds the resources and are
JM-3 Page 44
concerned with data storage, which remains internal to each server, and server is someone who holds the resources and are
not concerned with the user interface or user state. They can evolve independently. Client doesn’t need to know anything
about business logic and server doesn’t need to know anything about frontend UI.
Layered system
An application architecture needs to be composed of multiple layers. Each layer doesn’t know any thing about any layer other
than that of immediate layer and there can be lot of intermediate servers between client and the end server. Intermediary
servers may improve system availability by enabling load-balancing and by providing shared caches.
Code on demand
It is an optional feature. According to this, servers can also provide executable code to the client. The examples of code on
demand may include the compiled components such as Java Servlets and Server-Side Scripts such as JavaScript.
Rules of REST API
There are certain rules which should be kept in mind while creating REST API endpoints.
REST is based on the resource or noun instead of action or verb based. It means that a URI of a REST API should always end
with a noun.
HTTP verbs are used to identify the action. Some of the HTTP verbs are – GET, PUT, POST, DELETE, GET, PATCH.
A web application should be organized into resources like users and then uses HTTP verbs like – GET, PUT, POST, DELETE to
modify those resources. And as a developer it should be clear that what needs to be done just by looking at the endpoint and
HTTP method used.
Always use plurals in URL to keep an API URI consistent throughout the application.
Send a proper HTTP code to indicate a success or error status.
Note: You can easily use GET and POST but in order to use PUT and DELETE you will need to install method override.
HTTP verbs
Some of the common HTTP methods/verbs are described below:
GET: Retrieves one or more resources identified by the request URI and it can cache the information receive.
POST: Create a resource from the submission of a request and response is not cacheable in this case. This method is unsafe if
no security is applied to the endpoint as it would allow anyone to create a random resource by submission.
PUT: Update an existing resource on the server specified by the request URI.
DELETE: Delete an existing resource on the server specified by the request URI. It always return an appropriate HTTP status for
every request.
GET, PUT, DELETE methods are also known as Idempotent methods. Applying an operation once or applying it multiple times
has the same effect. Example: Delete any resource from the server and it succeeds with 200 OK and then try again to delete
that resource than it will display an error message 410 GONE.
The HTTP response comes with the response code. It informs about the result of the operation. It’s especially useful for UI
developers, as they can perform appropriate action basing on the code. There are the following groups of HTTP response
codes :
1xx – informational – indicates that the request was received and the process is continued. The examples are: 100 – Continue,
101 – Switching Protocols
2xx – success – when the request was received, understood, and successfully processed. The well-known examples are 200 –
OK and 201 – Created
3xx – redirection – client needs to take additional action to fulfill the request, e.g., 300 – Multiple Choice or 301 – Moved
Permanently
4xx – client errors – indicates that there is an error on the client’s side, such as 400 – Bad Request or 401 – Unauthorized
5xx- server errors – informs that an error occurred on the server’s side, e.g., 500 – Internal Server Error, 501 – Unimplemented
JM-3 Page 45
JM-3 Page 46
JM-3 Page 47
We have three ways to use @ResponseStatus to convert an Exception to an HTTP response status:
using @ExceptionHandler
using @ControllerAdvice
marking the Exception class
ResponseEntity provides two nested builder interfaces: HeadersBuilder and its subinterface, BodyBuilder.
JM-3 Page 48
Validation Framework
27 February 2025 11:31
Spring Boot provides a powerful validation framework using Jakarta Validation (formerly Javax Validation) with
Hibernate Validator as the default implementation.
JM-3 Page 49
JM-3 Page 50
Lombok
27 February 2025 11:45
Lombok is a Java library that reduces boilerplate code by auto-generating getters, setters, constructors,
toString, equals, hashCode, and more at compile time using annotations.
Why Use Lombok?
Reduces boilerplate code
Improves code readability
Enhances developer productivity
Works with Spring Boot, Hibernate, and JPA
Lombok provides compile-time annotations to reduce boilerplate code in Java applications, especially in
Spring Boot, Hibernate, and JPA projects.
JM-3 Page 51
JM-3 Page 52
Global Exception Handler
27 February 2025 11:48
In Spring Boot, we can handle exceptions globally using @ControllerAdvice and @ExceptionHandler.
This approach helps in centralizing error handling for REST APIs, improving code readability and
maintainability.
JM-3 Page 53
Mapper
27 February 2025 11:52
JM-3 Page 54
Important
21 May 2025 15:35
[Link]
Format: Simple key-value pairs
Structure: Flat and less readable for complex nested data
Example:
[Link]=8080
[Link]=jdbc:mysql://localhost:3306/mydb
[Link]=root
[Link]=pass123
🧾 [Link] or .yaml
Format: YAML (YAML Ain't Markup Language)
Structure: Supports nested and hierarchical data, more human-readable
JM-3 Page 55
Testing
14 May 2025 13:06
Testing is the process of checking if your code works as expected, helping catch bugs before users
encounter them.
Types of Testing (Key Points):
1. Smoke Testing
○ Purpose: Quick checks for core functionality and environment assumptions.
○ When: Run early in the testing cycle.
○ Goal: Catch major issues early; stop deeper testing if smoke tests fail.
2. Unit Testing
○ Purpose: Test individual units (e.g., functions, methods) in isolation.
○ Tools: Mocks/stubs used to isolate code.
○ When: Often first after smoke tests; run on developer machines and CI servers.
3. Integration Testing
○ Purpose: Ensure different components/modules work together.
○ When: After unit tests; run by CI servers automatically.
○ Catches: Bugs in inter-component communication.
4. System Testing
○ Purpose: Validate the entire system functions as a whole.
○ Focus: External interfaces, overall system behaviour.
5. Acceptance Testing
○ Purpose: Ensure software meets business/user requirements.
○ Who: Stakeholders, internal users, or beta users.
○ Types: Automated and manual; often run in staging environments.
JM-4 Page 1
Junit 5
14 May 2025 15:21
What is JUnit?
JUnit is a Java testing framework used to write and run repeatable automated tests.
JUnit 5 is the latest version, bringing more flexibility and power than JUnit 4.
JUnit 5 Structure
JUnit 5 consists of three main components:
1. JUnit Platform
○ Launches testing frameworks on the JVM.
○ Acts as a base to run tests with IDEs, build tools, and plugins.
2. JUnit Jupiter
○ Core API for writing tests using new JUnit 5 features.
○ Introduces new annotations and lifecycle methods.
3. JUnit Vintage
○ Supports running older JUnit 3 & JUnit 4 test cases on JUnit 5.
The basics of JUnit 5 are,
-> Annotations
-> Test Life cycle methods
-> Assertions
-> Assumptions
-> Parameterized Test
-> Dynamic Tests
-> Tagging and Filtering
Annotations
The JUnit 5 framework uses different Annotations based on the test case design. Mostly in JUnit 5
@Test, @BeforeEach, @AfterEach, @BeforeAll, @AfterAll, @DisplayName, @Disabled these
annotations are used. Basically, Annotations provides supplement information about the program in
java. Annotations are always start with "@" symbol. ( reference ).
@Test: Marks a method as a test method.
@BeforeEach: Indicates that the annotated method should be executed before each test.
@AfterEach: Indicates that the annotated method should be executed after each test.
@BeforeAll: Indicates that the annotated method should be executed before all tests in the test class.
@AfterAll: Indicates that the annotated method should be executed after all tests in the test class.
@DisplayName: Provides a custom name for the test class or test method.
@Disabled: Disables the test method or class.
Annotation Purpose
@Test Marks a method as a test method
@BeforeEach Runs before each test method
@AfterEach Runs after each test method
@BeforeAll Runs once before all tests in the class
@AfterAll Runs once after all tests in the class
@DisplayName Provides a custom name for the test
@Disabled Skips/ignores the test
Test Life cycle methods:
Control when setup and teardown code runs in relation to test execution, these methods are executed
at specific point in the test life cycle. The Life cycle methods are,
@BeforeEach, This Annotated method executes before each test method in the test class.
JM-4 Page 2
@BeforeEach, This Annotated method executes before each test method in the test class.
@AfterEach, This Annotated method executes after each test method in the test class, by sending
signals to JUnit
@BeforeAll, this send signals to JUnit, Like the annotated method should be executed once before all
test cased in the class.
@AfterAll, this annotation send signal to JUnit that is this annotated method should be run after all test
cases are executed in the class.
Assertions
The JUnit 5 provides different methods in Assertions class for checking the expected Result. Assertions
are used to check if a condition is true. If the condition is false, the test fails. Common assertions
include:
assertSame and assertEquals -> == and equals()
JM-4 Page 3
JM-4 Page 4
JM-4 Page 5
Mockito
24 March 2025 21:53
Unit testing is a software testing method where individual components (or units) of a program are tested independently
to ensure they function correctly. These tests are typically automated and focus on small, isolated sections of code—
such as functions or methods—without dependencies on external systems like databases or APIs.
Key Aspects of Unit Testing:
Isolation: Tests one unit at a time without external dependencies.
Automation: Often performed using frameworks like JUnit (Java), pytest (Python), or Jest (JavaScript).
Early Detection: Helps catch bugs early in development.
Regression Prevention: Ensures new changes don’t break existing functionality.
Unit testing framework :
JUnit – Most widely used for Java.
TestNG – More advanced, supports parallel execution.
Mockito – For mocking dependencies in Java tests.
To test only service layer we don’t require database but we require data to test. In this case we use the stub class.
Stub Class : dummy implementation -> sample implementation of particular classes.
A stub class is a simplified version of a class used in software testing, specifically in unit testing. It replaces a real class to
provide controlled responses for specific method calls. Stubs help isolate the unit being tested by removing
dependencies on external systems like databases, APIs, or complex logic.
Key Features of Stub Classes:
Predefined Behavior: Returns hardcoded values when methods are called.
No Logic: Unlike the real class, it doesn’t have actual logic—just placeholder implementations.
Used for Testing: Helps test code in isolation without dependencies.
JM-4 Page 6
Typically uses JDBC, JPA, Hibernate, or another ORM.
JM-4 Page 7
JM-4 Page 8
Annotations
22 May 2025 17:25
Here are the key MockMVC annotations and their uses in Spring MVC testing:
Test Setup Annotations:
@WebMvcTest -> For testing MVC controllers specifically
@AutoConfigureMockMvc -> For auto-configuring MockMvc
@SpringBootTest -> For full integration testing
Request Mapping Annotations:
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@RequestMapping
Common MockMvc Test Annotations:
@MockBean -> Creates a mock of a bean in Spring context
@SpyBean -> Creates a spy of an existing bean
@Autowired -> Injects dependencies
MockMVC methods with descriptions and examples:
REQUEST BUILDERS
Request
[Link](get("/api/users/{id}", 1)) -> Creates GET request
Use when: Testing GET endpoints
REQUEST CUSTOMIZATION
Content Type
.contentType(MediaType.APPLICATION_JSON) -> Description: Sets request content type
Use when: Specifying request format
Accept
.accept(MediaType.APPLICATION_JSON) -> Description: Sets accepted response type
Use when: Specifying expected response format
Headers
.header("Authorization", "Bearer token") -> Adds request headers
Use when: Testing with headers
Parameters
.param("key", "value") -> Adds query parameters
Use when: Testing with query parameters
Request Body
.content([Link](object)) -> Sets request body
Use when: Testing with request body
Example:
@Test
void testCreateUser() throws Exception {
User user = new User("John");
[Link](post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content([Link](user))
.header("Authorization", "Bearer token"))
.andExpect(status().isCreated());
}
RESPONSE MATCHERS
Status Matchers
.andExpect(status().isOk()) // 200
JM-4 Page 9
.andExpect(status().isOk()) // 200
.andExpect(status().isCreated()) // 201
.andExpect(status().isBadRequest()) // 400
.andExpect(status().isUnauthorized()) // 401
.andExpect(status().isForbidden()) // 403
.andExpect(status().isNotFound()) // 404
Verifies response status
Use when: Testing HTTP status codes
Content Matchers
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) -> Verifies response content type
Use when: Testing response format
.andExpect(content().json("expected json")) -> Verifies JSON response
Use when: Testing JSON response body
.andExpect(content().string("expected string")) -> Verifies string response
Use when: Testing string response body
Example:
@Test
void testGetUser() throws Exception {
[Link](get("/api/users/1")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.name").value("John"));
}
JSON PATH MATCHERS
Value Matching
.andExpect(jsonPath("$.property").value("expectedValue")) -> Verifies JSON property value
Use when: Testing specific JSON fields
Array Matching
.andExpect(jsonPath("$.items").isArray()) -> Verifies JSON array
Use when: Testing JSON arrays
Size Matching
.andExpect(jsonPath("$.[Link]()").value(3)) -> Verifies array size
Use when: Testing collection sizes
Example:
@Test
void testJsonResponse() throws Exception {
[Link](get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].id").value(1))
.andExpect(jsonPath("$[0].name").value("John"))
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$.length()").value(2));
}
HEADER MATCHERS
Header Existence
.andExpect(header().exists("headerName")) -> Verifies header exists
Use when: Testing header presence
Header Value
.andExpect(header().string("headerName", "expectedValue")) -> Verifies header value
Use when: Testing specific header values
RESULT ACTIONS
Print Response
.andDo(print()) -> Prints request/response details
JM-4 Page 10
.andDo(print()) -> Prints request/response details
Use when: Debugging tests
Get Result
.andReturn() -> Gets test result for further assertions
Use when: Need to access response details
SECURITY TESTING
With User Authentication
@WithMockUser(username = "user", roles = {"USER"}) -> Simulates authenticated user
Use when: Testing secured endpoints
With Anonymous User
.with(anonymous()) -> Simulates anonymous access
Use when: Testing unauthenticated access
Here's a comprehensive list of Mockito annotations with explanations and examples:
@Mock -> Creates a mock instance of a class or interface
private UserRepository userRepository;
@InjectMocks -> Automatically injects mock objects into the tested class
private UserService userService;
@Spy -> Creates a real object and spies on it
private List<String> spyList = new ArrayList<>();
@Captor -> Creates an ArgumentCaptor for capturing method arguments
private ArgumentCaptor<User> userCaptor;
@ExtendWith([Link]) -> JUnit 5 extension for Mockito
public class UserServiceTest { }
@MockitoSettings -> Configures Mockito behavior for a test class
@MockitoSettings(strictness = [Link])
public class UserServiceTest { }
@MockBean (Spring Boot) -> Creates a mock bean in the Spring application context
@MockBean
private UserRepository userRepository;
@SpyBean (Spring Boot) -> Creates a spy bean in the Spring application context
@SpyBean
private UserService userService;
@WithMockUser (Spring Security) -> Simulates an authenticated user for testing
@WithMockUser(username = "admin", roles = {"ADMIN"})
public void testSecuredMethod() { }
@PrepareForTest -> Prepares classes for PowerMock testing (static methods)
@PrepareForTest([Link])
public class TestClass { }
Mockito methods with their purposes and examples:
STUBBING METHODS
Returns a specific value when the method is called
when([Link]()).thenReturn(value);
Defines what value should be returned when a specific method is called on a mock object
Use when: You need to specify the behavior of a mock method
Throws an exception when the method is called
when([Link]()).thenThrow(exception);
Makes a mock method throw an exception when called
Use when: Testing error handling scenarios
Custom response based on arguments
when([Link]()).thenAnswer(invocation -> {
Object arg = [Link](0);
return processArg(arg);
});
Provides custom logic for mock method responses
JM-4 Page 11
Provides custom logic for mock method responses
Use when: Need dynamic responses based on input parameters
VERIFICATION METHODS
Basic verification
verify(mock).method();
Verifies that a method was called exactly once
Use when: Need to ensure a method was called
Verify number of invocations
verify(mock, times(n)).method();
Verifies a method was called exactly n times
Use when: Need to check specific number of method calls
Verify method was never called
verify(mock, never()).method();
Verifies a method was never called
Use when: Need to ensure a method wasn't called
Verify at least one call
verify(mock, atLeastOnce()).method();
Verifies method was called at least once
Use when: Need to ensure minimum number of calls
Verify no more interactions
verifyNoMoreInteractions(mock);
Verifies no other methods were called on the mock
Use when: Need to ensure no unexpected method calls
ARGUMENT MATCHERS
Basic matchers
any();
anyInt();
anyString();
Matches any value of the specified type
Use when: Method arguments are not important for the test
Specific value matcher
eq(value);
Matches a specific value
Use when: Need to match exact argument values
Custom matcher
argThat(argument -> [Link]());
Creates custom matching logic
Use when: Need complex argument matching conditions
Reset mock
reset(mock);
Resets mock to clean state
Use when: Need to reset mock behavior
Clear invocations
clearInvocations(mock);
Clears recorded invocations
Use when: Need to clear interaction history
JM-4 Page 12
JM-4 Page 13
Logging
14 May 2025 13:42
JM-4 Page 14
Logging-Log4j
28 February 2025 09:18
Logging is the process of writing log messages during the execution of a program to a central place. This
logging allows you to report and persist error and warning messages as well as info messages (e.g.,
runtime statistics) so that the messages can later be retrieved and analyzed.
The object which performs the logging in applications is typically just called Logger.
Logs are required for debugging purpose
Why Logging
If we use SOP statements to print log messages, then we can run into some disadvantages like:
- SOP prints all the messages one by one in console, since it is a single threaded environments and it
is time consuming process.
- We can print log messages on the console only. So, when the console is closed, we will lose all of
those logs.
- We can't store log messages in any permanent place. These messages will print one by one on the
console because it is a single-threaded environment.
To overcome these problems, the Log4j framework came into the picture. Log4j is an open source
framework provided by Apache for Java projects.
Advantages of Logging:
- Quick debugging
- Problem Diagnosis
- Easy Maintenance
- Cost and Time savings
Log4j is a reliable, fast and flexible logging framework (APIs) written in Java, which is distributed under
the Apache Software License.
Log4j is highly configurable through external configuration files at runtime.
Log4j has 3 main components :
- Logger
- Appender
- Layout
It is thread-safe.
It is optimized for speed
It is based on a named logger hierarchy.
It supports multiple output appenders per logger.
Logging behavior can be set at runtime using a configuration file.
Logging is an important component of the software development. A well-written logging code offers
quick debugging, easy maintenance, and structured storage of an application's runtime information.
Logger :
Logger is a class in the [Link].log4j.* package. We have to initialize one logger object for each Java
class. We use Logger's methods to generate log statements. Log4j provides the factory method to get
logger objects.
Private static Logger logger=[Link]([Link])
Methods in Logger class:
- [Link]()
- [Link]()
- [Link]()
- [Link]()
- [Link]()
Levels :
Level is a class in the [Link].log4j.* package. Each level has a different priority order as below
JM-4 Page 15
Appender :
Appender is used to write messages into a file or DB or SMTP.
Log4j has different types of appenders.
• ConsoleAppender -> to write message on console -> by default
• DailyRollingFileAppender - writing message into File System
• FileAppender -> writing message into File System
• JDBCAppender -> writing message into DataBase
• SMTPAppender -> to send the messages to a configured email
• RollingFileAppender -> writing message into File System
Layout :
This is used to define the formatting in which logs will print in a repository.
We have different types of layouts.
• PatternLayout
• SimpleLayout
• XMLLayout
• HTMLLayout
To work with Log4j we required log4j-core and log4j-api dependencies.
To use the loggers we need to configure it , by default it uses console and it only prints the errors in
console if not configured since it use error level.
To configure the logger, we can use any format like xml, json, properties
Minimum properties required to configure logger
JM-4 Page 16
For log file to be html file
JM-4 Page 17
Best Practices
14 May 2025 13:54
JM-4 Page 18
Scrum
14 May 2025 12:52
What is Scrum?
Scrum is a process framework used to manage product development and other knowledge work. Scrum
is empirical in that it provides a means for teams to establish a hypothesis of how they think something
works, try it out, reflect on the experience, and make the appropriate adjustments. That is, when the
framework is used properly. Scrum is structured in a way that allows teams to incorporate practices
from other frameworks where they make sense for the team’s context.
When is Scrum Applicable?
Scrum is best suited in the case where a cross-functional team is working in a product development
setting where there is a nontrivial amount of work that lends itself to being split into more than one 2 –
4 week iteration.
Scrum Values
Teams following scrum are expected to learn and explore the following values:
Commitment
Team members personally commit to achieving team goals
Courage
Team members do the right thing and work on tough problems.
Focus
Concentrate on the work identified for the sprint and the goals of the team.
Openness
Team members and stakeholders are open about all the work and the challenges the team encounters.
Respect
Team members respect each other to be capable and independent.
Principles of Scrum
The following principles underpin the empirical nature of scrum:
Transparency
The team must work in an environment where everyone is aware of what issues other team members
are running into. Teams surface issues within the organization, often ones that have been there for a
long time, that get in the way of the team’s success.
Inspection
Frequent inspection points are built into the framework to allow the team an opportunity to reflect on
how the process is working. These inspection points include the Daily Scrum meeting and the Sprint
Review Meeting.
Adaptation
The team constantly investigates how things are going and revises those items that do not seem to
make sense.
Scrum Practices
Events
Sprint
The Sprint is a timebox of one month or less during which the team produces a potentially shippable
product Increment. Typical characteristics of Sprints:
Maintain a consistent duration throughout a development effort
A new Sprint immediately follows the conclusion of the previous Sprint
The start date and end date of Sprint are fixed
Sprint Planning
A team starts out a Sprint with a discussion to determine which items from the product backlog they will
work on during the Sprint. The end result of Sprint Planning is the Sprint Backlog.
Sprint Planning typically occurs in two parts. In the first part, the product owner and the rest of the team
agree on which product backlog items will be included in the Sprint.
In the Second Part of Sprint Planning, the team determines how they will successfully deliver the
identified product backlog items as part of the potentially shippable product increment. The team may
JM-5 Page 1
identified product backlog items as part of the potentially shippable product increment. The team may
identify specific tasks necessary to make that happen if that is one of their practices. The product
backlog items identified for delivery and tasks if applicable make up the Sprint Backlog.
Once the team and product owner establish the scope of the Sprint as described by the product backlog
items no more items can be added to the Sprint Backlog. This protects the team from scope changes
within that Sprint.
Daily Scrum
The Daily Scrum is a short (usually limited to 15 minutes) discussion where the team coordinates their
activities for the following day. The Daily Scrum is not intended to be a status reporting meeting or a
problem-solving discussion.
Sprint Review
At the end of the Sprint, the entire team (including the product owner) reviews the results of the sprint
with stakeholders of the product. The purpose of this discussion is to discuss, demonstrate, and
potentially give the stakeholders a chance to use, the increment in order to get feedback. The Sprint
Review is not intended to provide a status report. Feedback from the sprint review gets placed into the
Product Backlog for future consideration.
Sprint Retrospective
At the end of the Sprint following the sprint review, the team (including the product owner) should
reflect upon how things went during the previous sprint and identify adjustments they could make going
forward. The result of this retrospective is at least one action item included on the following Sprint’s
Sprint Backlog.
Artifacts
Product Backlog
The product backlog is an ordered list of all the possible changes that could be made to the product.
Items on the product backlog are options, not commitments in that just because they exist on the
Product Backlog does not guarantee they will be delivered. The Product Owner maintains the product
backlog on an ongoing basis including its content, availability, and ordering.
Sprint Backlog
The Sprint Backlog is the collection of product backlog items selected for delivery in the Sprint, and if the
team identifies tasks, the tasks necessary to deliver those product backlog items and achieve the Sprint
Goal.
Increment
The increment is the collection of the Product Backlog Items that meet the team’s Definition of Done by
the end of the Sprint. The Product Owner may decide to release the increment or build upon it in future
Sprints.
Definition of Done
The definition of done is a team’s shared agreement on the criteria that a Product Backlog Item must
meet before it is considered done.
Roles
The Product Owner
The product owner is a role team responsible for managing the product backlog in order to achieve the
desired outcome that the team seeks to accomplish. The product owner role exists in Scrum to address
challenges that product development teams had with multiple, conflicting directions or no direction at
all with respect to what to build.
The Scrum Master
The scrum master is the team role responsible for ensuring the team lives agile values and principles and
follows the processes and practices that the team agreed they would use. The name was initially
intended to indicate someone who is an expert at Scrum and can therefore coach others. The role does
not generally have any actual authority. People filling this role have to lead from a position of influence,
often taking a servant-leadership stance.
The Development Team
The development team consists of the people who deliver the product increment inside a Sprint. The
main responsibility of the development team is to deliver the increment that delivers value to every
Sprint. How the work is divided up to do that is left up to the team to determine based on the conditions
JM-5 Page 2
Sprint. How the work is divided up to do that is left up to the team to determine based on the conditions
at that time.
Lifecycle
Scrum is a framework that allows development teams the flexibility to respond to changing situations.
This framework has sufficient control points in place to ensure the team does not stray from the desired
outcome, and that issues can be identified and resolved and process adjustments made while the effort
is still underway.
The Scrum Lifecycle starts with a prioritized backlog but does not provide any guidance as to how that
backlog is developed or prioritized.
The Scrum Lifecycle consists of a series of Sprints, where the end result is a potentially shippable
product increment. Inside these sprints, all of the activities necessary for the development of the
product occur on a small subset of the overall product. Below is a description of the key steps in the
Scrum Lifecycle:
Establish the Product Backlog.
The product owner and development team conduct Sprint Planning. Determine the scope of the Sprint
in the first part of Sprint Planning and the plan for delivering that scope in the second half of Sprint
Planning.
As the Sprint progresses, the development team performs the work necessary to deliver the selected
product backlog items.
On a daily basis, the development team coordinates their work in a Daily Scrum.
At the end of the Sprint, the development team delivers the Product Backlog Items selected during
Sprint Planning. The development team holds a Sprint Review to show the customer the increment and
get feedback. The development team and product owner also reflect on how the Sprint has proceeded
so far and adapted their processes accordingly during a retrospective.
The Team repeats steps 2–5 until the desired outcome of the product has been met.
JM-5 Page 3
Agile Methodology
14 May 2025 12:52
Agile Software Development is an iterative and incremental approach to Software Development that
emphasizes the importance of delivering a working product quickly and frequently. It involves close
collaboration between the development team and the customer to ensure that the product meets their
needs and expectations.
Why is Agile Used?
Agile is used because it helps teams deliver value quickly and continuously. By prioritizing the delivery of
difficult results early in the project, customers benefit from seeing and using the product sooner,
allowing for quick feedback and adjustments. Agile also encourages teams to focus on what truly
matters, concentrating on tasks that add value and avoiding unnecessary work.
Agile as a Mindset: Agile represents a shift in culture that values adaptability, collaboration, and client
happiness. It gives team members more authority and promotes a cooperative and upbeat work
atmosphere.
Quick Response to Change: Agile fosters a culture that allows teams to respond swiftly to constantly
shifting priorities and requirements. This adaptability is particularly useful in sectors of the economy or
technology that experience fast changes.
Regular Demonstrations: Agile techniques place a strong emphasis on regular demonstrations of project
progress. Stakeholders may clearly see the project’s status, upcoming problems, and upcoming new
features due to this transparency.
Cross-Functional Teams: Agile fosters self-organizing, cross-functional teams that share information
effectively, communicate more effectively and feel more like a unit.
Agile Software Development Process
Agile software development, often just called Agile, focuses on being flexible and practical when
delivering software. Instead of launching everything at once, Agile delivers small, valuable updates to
users over time. This approach allows teams to adjust and improve the product along the way, verifying
that each update brings real value to the users. It’s all about making progress in manageable steps and
responding quickly to changes.
Agile Software Development
1. Requirements Gathering
This is the first step where the development team works closely with the customer to understand what
they really need from the software. The team listens carefully to the customer’s needs, then sorts and
prioritizes these requirements to make sure the most important features are developed first.
2. Planning
In this stage, the team creates a clear plan for how they’ll build the software. They decide which
JM-5 Page 4
In this stage, the team creates a clear plan for how they’ll build the software. They decide which
features to focus on in each development cycle (called an iteration). Think of it like mapping out the
journey of the project, so everyone knows what to expect and when things will be delivered.
3. Development
This is where the team starts turning their plan into reality. They work in short, focused cycles, building
small, usable pieces of the product. Each cycle builds on the last, which helps the team stay on track and
get quick feedback to keep improving.
4. Testing
As the software gets built, it’s also tested to make sure it works properly and meets the customer’s
needs. Testing ensures the product is of high quality and free from errors, so problems are caught early
on before they become bigger issues.
5. Deployment
Once everything is tested and working as expected, the software is deployed, which means it’s ready for
customers or end-users to start using. It’s the moment when all the development work comes to life.
6. Maintenance
Even after the software is released, the job isn’t done. The team keeps maintaining the software,
verifying it continues to work well and stays up-to-date with any new needs or changes from the
customer. This keeps the software relevant and helpful over time.
Agile Software Development Cycle
Step 1: In the first step, concept, and business opportunities in each possible project are identified and
the amount of time and work needed to complete the project is estimated. Based on their technical and
financial viability, projects can then be prioritized and determined which ones are worthwhile pursuing.
Step 2: In the second phase, known as inception, the customer is consulted regarding the initial
requirements, team members are selected, and funding is secured. Additionally, a schedule outlining
each team’s responsibilities and the precise time at which each sprint’s work is expected to be finished
should be developed.
Step 3: Teams begin building functional software in the third step, iteration/construction, based on
requirements and ongoing feedback. Iterations, also known as single development cycles, are the
foundation of the Agile software development cycle.
4 Core Values of Agile Software Development
The four core values of Agile software development, as outlined in the Agile Manifesto, focus on what
truly matters for creating successful software. The Agile Software Development Methodology Manifesto
describe four core values of Agile in software development.
1. Individuals and Interactions over Processes and Tools: This value stresses that the strength of the
team and how well they work together is more important than the tools or processes they use. Of
course, tools and processes help, but the real success of a project comes from good teamwork, open
communication, and collaboration.
2. Working Software over Comprehensive Documentation: Agile prefers delivering functional software
quickly rather than getting down in lengthy documentation. While some documentation is needed, the
focus is on getting a working product into the hands of the user and improving it based on feedback.
3. Customer Collaboration over Contract Negotiation: Agile values regular collaboration with customers
over sticking strictly to contracts. The idea is to involve the customer throughout the development,
verifying that the product meets their needs and making adjustments based on their feedback.
4. Responding to Change over Following a Plan: In Agile, change is expected, and the approach
encourages flexibility. Rather than rigidly following a plan that may no longer apply, Agile teams adapt
and adjust based on new information, changing market conditions, or including customer requirements.
12 Principles of Agile Software Development
There are 12 agile principles mentioned in the Agile Manifesto. Agile principles are guidelines for flexible
and efficient software development. They emphasize frequent delivery, embracing change,
collaboration, and continuous improvement. The focus is on delivering value, maintaining a sustainable
work pace, and ensuring technical excellence.
These principles include:
Ensuring customer satisfaction through the early delivery of software.
Being open to changing requirements in the stages of the development.
JM-5 Page 5
Being open to changing requirements in the stages of the development.
Frequently delivering working software with a main focus on preference for timeframes.
Promoting collaboration between business stakeholders and developers as an element.
Structuring the projects around individuals. Providing them with the necessary environment and
support.
Prioritizing face to face communication whenever needed.
Considering working software as the measure of the progress.
Fostering development by allowing teams to maintain a pace indefinitely.
Placing attention on excellence and good design practices.
Recognizing the simplicity as crucial factor aiming to maximize productivity by minimizing the work.
Encouraging self organizing teams as the approach to design and build systems.
Regularly reflecting on how to enhance effectiveness and to make adjustments accordingly.
Advantages Agile Software Development
Increased collaboration and communication: Agile Software Development Methodology emphasize
collaboration and communication among team members, stakeholders, and customers. This leads to
improved understanding, better alignment, and increased buy-in from everyone involved.
Flexibility and adaptability: Agile methodologies are designed to be flexible and adaptable, making it
easier to respond to changes in requirements, priorities, or market conditions. This allows teams to
quickly adjust their approach and stay focused on delivering value.
Improved quality and reliability: Agile methodologies place a strong emphasis on testing, quality
assurance, and continuous improvement. This helps to ensure that software is delivered with high
quality and reliability, reducing the risk of defects or issues that can impact the user experience.
Enhanced customer satisfaction: Agile methodologies prioritize customer satisfaction and focus on
delivering value to the customer. By involving customers throughout the development process, teams
can ensure that the software meets their needs and expectations.
Increased team morale and motivation: Agile methodologies promote a collaborative, supportive, and
positive work environment. This can lead to increased team morale, motivation, and engagement, which
can in turn lead to better productivity, higher quality work, and improved outcomes.
Deployment of software is quicker and thus helps in increasing the trust of the customer.
Can better adapt to rapidly changing requirements and respond faster.
Helps in getting immediate feedback which can be used to improve the software in the next increment.
People – Not Process. People and interactions are given a higher priority than processes and tools.
Continuous attention to technical excellence and good design.
Disadvantages Agile Software Development
Lack of predictability: Agile Development relies heavily on customer feedback and continuous iteration,
which can make it difficult to predict project outcomes, timelines, and budgets.
Limited scope control: Agile Development is designed to be flexible and adaptable, which means that
scope changes can be easily accommodated. However, this can also lead to scope creep and a lack of
control over the project scope.
Lack of emphasis on testing: Agile Development places a greater emphasis on delivering working code
quickly, which can lead to a lack of focus on testing and quality assurance. This can result in bugs and
other issues that may go undetected until later stages of the project.
Risk of team burnout: Agile Development can be intense and fast-paced, with frequent sprints and
deadlines. This can put a lot of pressure on team members and lead to burnout, especially if the team is
not given adequate time for rest and recovery.
Lack of structure and governance: Agile Development is often less formal and structured than other
development methodologies, which can lead to a lack of governance and oversight. This can result in
inconsistent processes and practices, which can impact project quality and outcomes.
In the case of large software projects, it is difficult to assess the effort required at the initial stages of the
software development life cycle.
Agile Development is more code-focused and produces less documentation.
Agile development is heavily dependent on the inputs of the customer. If the customer has ambiguity in
his vision of the outcome, it is highly likely that the project to get off track.
Face-to-face communication is harder in large-scale organizations.
JM-5 Page 6
Face-to-face communication is harder in large-scale organizations.
Only senior programmers are capable of making the kind of decisions required during the development
process. Hence, it’s a difficult situation for new programmers to adapt to the environment.
Practices of Agile Software Development
Scrum: Scrum is a framework for agile software development that involves iterative cycles called sprints,
daily stand-up meetings, and a product backlog that is prioritized by the customer.
Kanban: Kanban is a visual system that helps teams manage their work and improve their processes. It
involves using a board with columns to represent different stages of the development process, and
cards or sticky notes to represent work items.
Continuous Integration: Continuous Integration is the practice of frequently merging code changes into
a shared repository, which helps to identify and resolve conflicts early in the development process.
Test-Driven Development: Test-Driven Development (TDD) is a development practice that involves
writing automated tests before writing the code. This helps to ensure that the code meets the
requirements and reduces the likelihood of defects.
Pair Programming: Pair programming involves two developers working together on the same code. This
helps to improve code quality, share knowledge, and reduce the likelihood of defects.
Advantages of Agile over traditional software development approaches
Increased customer satisfaction: Agile development involves close collaboration with the customer,
which helps to ensure that the software meets their needs and expectations.
Faster time-to-market: Agile development emphasizes the delivery of working software in short
iterations, which helps to get the software to market faster.
Reduced risk: Agile development involves frequent testing and feedback, which helps to identify and
resolve issues early in the development process.
Improved team collaboration: Agile development emphasizes collaboration and communication
between team members, which helps to improve productivity and morale.
Adaptability to change: Agile Development is designed to be flexible and adaptable, which means that
changes to the project scope, requirements, and timeline can be accommodated easily. This can help
the team to respond quickly to changing business needs and market demands.
Better quality software: Agile Development emphasizes continuous testing and feedback, which helps to
identify and resolve issues early in the development process. This can lead to higher-quality software
that is more reliable and less prone to errors.
Increased transparency: Agile Development involves frequent communication and collaboration
between the team and the customer, which helps to improve transparency and visibility into the project
status and progress. This can help to build trust and confidence with the customer and other
stakeholders.
Higher productivity: Agile Development emphasizes teamwork and collaboration, which helps to
improve productivity and reduce waste. This can lead to faster delivery of working software with fewer
defects and rework.
Improved project control: Agile Development emphasizes continuous monitoring and measurement of
project metrics, which helps to improve project control and decision-making. This can help the team to
stay on track and make data-driven decisions throughout the development process.
JM-5 Page 7
CI v/s CD
14 May 2025 13:03
What are the differences between continuous integration, continuous delivery, and continuous
deployment (CI/CD)?
Continuous integration
Developers practicing continuous integration merge their changes back to the main branch as often as
possible. The developer's changes are validated by creating a build and running automated tests against
the build. By doing so, you avoid integration challenges that can happen when waiting for release day to
merge changes into the release branch.
Continuous integration puts a great emphasis on testing automation to check that the application is not
broken whenever new commits are integrated into the main branch.
Continuous delivery
Continuous delivery is an extension of continuous integration since it automatically deploys all code
changes to a testing and/or production environment after the build stage.
This means that on top of automated testing, you have an automated release process and you can
deploy your application any time by clicking a button.
In theory, with continuous delivery, you can decide to release daily, weekly, fortnightly, or whatever
suits your business requirements. However, if you truly want to get the benefits of continuous delivery,
you should deploy to production as early as possible to make sure that you release small batches that
are easy to troubleshoot in case of a problem.
Continuous deployment
Continuous deployment goes one step further than continuous delivery. With this practice, every
change that passes all stages of your production pipeline is released to your customers. There's no
human intervention, and only a failed test will prevent a new change to be deployed to production.
Continuous deployment is an excellent way to accelerate the feedback loop with your customers and
take pressure off the team as there isn't a "release day" anymore. Developers can focus on building
software, and they see their work go live minutes after they've finished working on it.
JM-5 Page 8
Microservices Architecture
17 April 2025 09:36
On-premises Datacenter : A company keeps all of their IT environment on the premises of the
organization and maintained by IT team.
Disadvantages of On-premises Datacenter:
- Privacy
- Cost - Significant upfront hardware and software costs.
- Publicly not accessible
- Managing is difficult since it requires big specialized team
- Agility and Scalability
- Security - solid security policy and in-house expertise is needed.
- Disaster recovery and backup
- IT support
Advantages of Cloud over On-Premises:
- Cost : Pat as you use
- Security : Delivery superior data security
- Recovery and backup : Regular backup takes place
- Agility and Scalability : Cloud resources can be easily adjusted
- IT support : IT team can manage more with less time and effort
Cloud Providers:
Google -> Google Cloud Provider
Microsoft -> Azure
Amazon -> AWS
Monolithic application:
All modules in single application under single server.
Advantages :
- Single server for whole application.
- One deployment is required for all the modules.
Drawbacks
- Agility : If application is too large and complex to understand, it is challenging to make changes
fast and correctly.
- Scalability : We can't scale individual modules, so we always scale entire application
- Reliability : Buy in any module (ex: memory leak) can potentially bring down the entire process.
- Tightly coupled
Microservices:
JM-6 Page 1
Advantages:
- Loosely coupled
- Agility : Services are smaller and faster development and testing
- Scalability : Each service can scale individually as per the need and requirement
- Reliability : Bug in any service (Ex : memory leak) can impact only that service
- Deployment Time : Services can be deployed independently and can start quickly
- Eliminates any long-term commitment to a technology stack.
Common Problems :
- Need to rebuild on every configuration change - Centralized
Configuration
- No self registry and discovery - Service Registry (common to all services IP address )
- No centralized way to communicate outsiders - Single server with multiple client - API Gateway
- No self-healing
- No centralized logs monitoring
- No distributed tracing
- Server-side and client-side load balancing : Microservices uses client-side load balancing as help in
traffic management
- Distributed communication
Load Balancer : Handles the traffic and routes the api's to multiple server. Handles which server to be
called from the server
JM-6 Page 2
1. Centralized Configuration
• Tool: Spring Cloud Config Server
• Purpose: Manages externalized configuration in a distributed system.
• Benefit: Centralized management of properties across all environments (Dev, QA, Prod).
2. Service Registry
• Tool: Spring Cloud Eureka Server
• Purpose: Service discovery — helps microservices find and communicate with each other.
• Benefit: Avoids hard-coding host/port; simplifies dynamic scaling.
3. API Gateway
• Tool: Spring Cloud Gateway
• Purpose: Routes API requests to appropriate microservices.
• Benefit: Adds security, monitoring, metrics, and resiliency at the entry point.
4. Fault Tolerance
• Tool: Hystrix (by Netflix)
• Purpose: Adds resilience to services by handling failures and latency gracefully.
• Benefit: Prevents cascading failures by isolating failing services.
5. Logging and Tracing
• Tools: Spring Cloud Sleuth & Zipkin
• Purpose: Distributed tracing by attaching trace IDs and span IDs to logs.
• Benefit: Helps analyse and troubleshoot latency issues in complex systems.
6. Load Balancing
• Tools: Ribbon / Spring Cloud Load Balancer
• Purpose: Client-side load balancing of HTTP/TCP traffic.
• Benefit: Direct communication with services (no extra network hops), offering fine-grained
control.
JM-6 Page 3
control.
JM-6 Page 4
Eureka Server
21 April 2025 11:10
Eureka server behaves like a private DNS for the cluster of services from the cloud
Interactions between the services is handled by the eureka
It is naming server named Netflix Eureka Server, it acts like a DNS, every information will be stored at
server side.
When the client server is started then it automatically registers itself in eureka server and passes the IP
address and port number to the eureka server.
Server will store the service name rather than storing all the IP address and port number of the service
from the application properties.
Eureka Server maintains the details of the server and client which are running.
Microservices Communication:
Microservices may need to communicate to execute some tasks - REST - one service can access the
other service with the IP address and port number of that service.
Direct communication Limitations:
- Not Practical : It is not practical to know the IP address and port number of each microservices as
there are multiple microservices to connect from client
- Dynamic Host & IP : whenever the IP address or port number get changed
Service Registration and Discovery:
When we sign in into Chat Client
- We are registered with the server - Server knows about you, that we are online
- At the same time, Server provides list of all known clients.
- Displays all our contacts who are online at that time.
Here we as a client has discovered other clients in exchange for the act of registering / login. Other side,
client has itself been discovered by other clients.
It provides lookup service that is self-maintaining because the client registers themselves and, in the
process, it discover the other registrations.
Service Registration and Discovery : Eureka
The microservices should register themselves in the centralized location (Eureka Server) with an
identifier by providing their details such as host name, IP address, port and health indicators etc. This is
known as Service Registration.
Each microservice should be able to look up the list of registered services in the centralized location and
it is known as Service Discovery
Eureka Server is an implementation for the Service Registration and Discovery pattern
The Eureka server will maintain a list of registered microservices with their provided details. Eureka
server expects continuous ping messages (known as heartbeats) from the registered microservices to
verify they are alive (up and running)
If any service fails to send the heartbeat (ping message) continuously, it will be considered as a dead
service and will be removed from the registry.
JM-6 Page 5
For server,
[Link]-with-eureka=false -> mark is as server and do not create any registry
[Link]-registry=false -> don’t try to fetch the registry from the server
JM-6 Page 6
[Link]=[Link] -> Tells this service where the
Eureka Server is located.
defaultZone is the default URL used to register with Eureka.
[Link]-ip-address=true -> Registers the service using the IP address instead of the
hostname.
Useful when running in Docker or cloud environments where DNS/hostnames are unreliable.
[Link]-with-eureka=true -> Tells the service to register itself with Eureka.
[Link]-registry=true -> Enables this service to fetch the list of other registered services from
Eureka — essential for inter-service communication.
🗄 Database Configura on (MySQL)
[Link]=jdbc:mysql://localhost:3306/microservice -> JDBC URL for the MySQL database
named microservice.
[Link]=root
[Link]=root
Credentials to connect to the MySQL database.
[Link]-class-name=[Link] -> JDBC driver class for MySQL 8+.
🛠 JPA (Java Persistence API) / Hibernate Configura on
[Link]-platform=[Link].MySQL8Dialect
Tells Hibernate to use SQL dialect specific to MySQL 8 for compatibility.
[Link]-auto=update -> Automatically creates or updates the database schema based
on your JPA entities.
Options include:
none
validate
update
create
create-drop
[Link]-sql=true -> Logs the actual SQL queries generated by Hibernate to the console — helpful
for debugging.
📝 Logging Configuration
[Link]=INFO -> Logs Spring framework-related messages at INFO level.
[Link]=DEBUG -> Logs raw SQL statements executed by Hibernate.
[Link]=TRACE -> Logs the binding of parameter
values to SQL queries (e.g., binding id=5 to SELECT * FROM ... WHERE id=?).
[Link]=%d{yyyy-MM-dd HH:mm:ss} - %msg%n -> Customizes the log output format in
the console.
Here, it shows: Date and time, Log message, New line
⚙ Advanced Spring MVC & Boot Behavior
[Link]-exception-if-no-handler-found=true -> Throws an exception instead of returning a 404
error when no controller is found for a request.
Useful for customizing error handling (e.g., global exception handlers).
[Link]-bean-definition-overriding=true -> Allows one Spring bean definition to override
another of the same name.
Useful in test setups or when custom configuration beans override defaults.
🔧 Configuration for Eureka Server
[Link]=8761
This sets the port on which the Eureka server will run.
Default port for Eureka is 8761, so this is the standard setup.
[Link]=eureka-server
This gives a name to the application.
The name is mainly used for identification/logging purposes and can appear in Eureka dashboards or
logs.
[Link]-with-eureka=false
Disables self-registration of this service with Eureka.
JM-6 Page 7
Disables self-registration of this service with Eureka.
Since this is the Eureka Server itself, it should not register with itself as a client — hence this is set to
false.
[Link]-registry=false
Disables fetching the registry from other Eureka servers.
This is because this server is acting as a standalone Eureka Server and doesn’t need to fetch service info
from others.
If you were running multiple Eureka servers in a clustered setup, you might set this to true to allow peer
discovery.
1. @SpringBootApplication: This is a convenience annotation that includes:
@Configuration: Allows Java-based Spring configuration.
@EnableAutoConfiguration: Automatically configures Spring application based on dependencies.
@ComponentScan: Scans the current package and subpackages for Spring-managed components.
Yes, it's required for all Spring Boot apps — it bootstraps the entire application.
2. @EnableEurekaServer: This annotation enables the Eureka Server in your Spring Boot application.
It brings in all the necessary configuration to expose the Eureka dashboard at [Link]
Allows other microservices (Eureka clients) to register themselves and discover each other through the
registry.
Yes, it's required to turn your Spring Boot app into a Eureka Server.
3. (Optional) @Configuration, @Component, @RestController
These annotations are not required just for a Eureka Server, but they can be used for extending or
customizing its behavior:
Annotation Purpose Example Use
@ConfigurationDeclare a Java configuration class Add custom beans
@Component Mark a class as a Spring-managed bean Custom health indicators
@RestController Create custom REST endpoints /status, custom diagnostics
JM-6 Page 8
Feign REST Client
21 April 2025 12:21
Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create
an interface and annotate it. It has pluggable annotation support including feign annotations and JAX-RS
annotations.
Reduces the boilerplate code required for the REST API.
Feign Client also known as Spring Cloud Open Feign is a Declarative REST Client in Spring Boot Web
Application. Declarative REST Client means we need to specify the client specification as an Interface
and Spring Boot will take care of the implementation for us. Writing web services with the help of Feign
Client is very easier. Feign Client is mostly used to consume REST API endpoints which are exposed by
third-party or microservice.
What is RestTemplate?
RestTemplate is a synchronous client provided by Spring for making HTTP requests. It was introduced in
Spring 3 and has been widely used for many years. However, it is being deprecated in favor of more
modern solutions like WebClient.
Key Features of RestTemplate
- Synchronous: RestTemplate is a blocking client, meaning it waits for the server to respond before
proceeding. This can result in slower performance, especially when dealing with many requests.
- Easy to Use: It provides straightforward methods to perform common HTTP operations like GET,
POST, PUT, DELETE, etc.
- Configuration: Allows configuration of headers, request parameters, and timeouts.
What is WebClient?
WebClient is a non-blocking, reactive client introduced in Spring 5 as part of the WebFlux framework. It
is designed for reactive programming and offers better performance for applications that need to
handle multiple requests concurrently.
Key Features of WebClient
- Asynchronous: WebClient is non-blocking, allowing it to handle many requests simultaneously
without waiting for each one to finish.
- Reactive: Built on top of Project Reactor, making it suitable for reactive applications.
- Modern: Recommended for new Spring applications due to its flexibility and performance.
- Streaming: Supports streaming of data, making it ideal for handling large datasets.
JM-6 Page 9
What is Feign Client?
Feign Client is a declarative HTTP client developed by Netflix and integrated with Spring Cloud. It
simplifies HTTP API consumption by allowing you to define HTTP clients using interfaces and
annotations. Feign Client is well-suited for microservices architecture and can be integrated with other
Spring Cloud components.
Key Features of Feign Client
- Declarative: Allows you to define HTTP clients using interfaces and annotations, making the code
cleaner and more readable.
- Load Balancing: Integrates seamlessly with Netflix Ribbon for client-side load balancing.
- Fault Tolerance: Can be integrated with Netflix Hystrix for circuit breaker functionality.
- Integration: Works well with other Spring Cloud components, making it ideal for microservices.
JM-6 Page 10
JM-6 Page 11
When to Use:
- RestTemplate:
Use in legacy applications where blocking operations are sufficient.
Simple use cases with straightforward HTTP operations.
- WebClient:
Use in new applications that require non-blocking and reactive operations.
Applications that need to handle many concurrent requests efficiently.
Projects that require streaming data or advanced HTTP interactions.
- Feign Client:
Use in microservices architectures to simplify HTTP API consumption.
When you want to leverage Spring Cloud features like load balancing and circuit breaking.
Declarative syntax makes it easier to manage and read.
JM-6 Page 12
API Gateway
25 April 2025 09:44
Why gateway?
- All the services has different port number if we want to use all the services in single port then api
gateway is used.
- Easy to host a single IP address rather than hosting all the service api's
API Gateway :
It acts as a single point of contact or a single entry point of contact for the clients who want to interact
with the multiple services behind the gateway. It acts as a reverse proxy (A reverse proxy is a type of
server that sits in front of one or more backend servers and forwards client (e.g., browser) requests to
those servers. It's called "reverse" because, unlike a forward proxy, which sits between clients and the
internet, a reverse proxy sits between the internet and web servers.)
- An API gateway is an API management tool that sits between a client and a collection of backend
services.
- An API gateway acts as a reverse proxy to accept all application programming interface (API) calls,
aggregate the various services required to fulfill them, and return the appropriate result.
All services can be on private IP addresses and api gateway can be on public IP address.
Without gateway :
With Gateway :
JM-6 Page 13
- Reduces the number of requests/roundtrips.
For example, the API gateway enables clients to retrieve data from multiple services with a single
round-trip. Fewer requests also means less overhead and improves the user experience. An API
gateway is essential for mobile applications.
- Simplifies the client by moving logic for calling multiple services from the client to API gateway
Security
Abstraction
Auditing
Routing
Loose Coupling
API gateway drawbacks :
- Increased complexity
The API gateway is yet another moving part that must be developed, deployed and managed
- Latency
Increased response time due to additional network hop through the API gateway - however, for
most applications the cost of an extra roundtrip is insignificant
Variation : Backends for frontends
A variation of this pattern is the backends for frontends pattern. It defines a separate API gateway for
each kind of client.
JM-6 Page 14
Filters follows the chain responsibility design patterns
Implementation :
Predicates types are path predicate, cookie predicate, header predicate, parameter predicate, request
parameter predicate
Route Predicate factories :
- After Route Predicate factory
- Before Route Predicate factory
- Between Route Predicate factory
- Cookie Route Predicate factory
- Header Route Predicate factory
- Host Route Predicate factory
- Method Route Predicate factory
- Path Route Predicate factory
- Query Route Predicate factory
- RemoteAddr Route Predicate factory
- Weight Route Predicate factory
Spring Cloud Gateway Architecture
The main components of the spring cloud gateway are:
Route: It is an important component in the spring cloud gateway. I consist of ID, destination URI,
predicates, and filters.
Predicates: It is the same as Java 8 function predicate. A Predicate simply evaluates the input against a
condition defined by the Predicate and returns true if the condition is satisfied. Here the Predicate is
used to match the HTTP requests. A route is matched if the Predicate returns true.
Filter Chain: It is a series of filters applied to incoming requests and responses. It can be used for various
purposes like authentication, requests or response transformation, and many more
Spring Cloud Gateway Implementation
There are two ways to create an API gateway.
Programmatic configuration: Here we create Spring Cloud Gateway as Java bean. The routes, predicates,
and all are created as a traditional Java program using RouteLocator
Property configuration: Here, we create components of Spring Cloud Gateway as properties in the
[Link] or [Link] file.
[Link]
General Application Configuration
[Link]=api-gateway
JM-6 Page 15
[Link]=api-gateway
Sets the name of the Spring Boot application. This is important for Eureka registration and identifying
the service.
[Link]=8080
The port number the application will run on. In this case, the gateway runs on port 8080.
🌐 Eureka Client Configuration
[Link]=[Link]
Tells the application where the Eureka server is located. It’s used for service registration and discovery.
[Link]-with-eureka=true
Indicates that this application (the gateway) should register itself with Eureka.
[Link]-registry=true
Tells the application to fetch the registry of other services from Eureka. This allows it to discover other
services like book-service, user-service, etc.
🌉 Spring Cloud Gateway (MVC Style) Configuration
[Link]=true
Enables Spring Cloud Gateway using Spring MVC instead of the reactive stack (WebFlux). This is helpful if
you're using Spring MVC throughout your project.
[Link]=/
Sets the root path of the servlet to /. This means the app handles requests from the root URL.
🛣 Routes Configura on (Gateway Routes)
These define routing rules for the gateway. Each route has an id, a uri, and one or more predicates.
📘 Route 0: Book Service
[Link][0].id=book-service
[Link][0].uri=lb://book-service
[Link][0].predicates[0].name=Path
[Link][0].predicates[0].args[pattern]=/books/**
id: Identifier for the route.
uri: Uses lb:// (load balancer) to send requests to a registered service called book-service in Eureka.
predicate: Matches any incoming requests with path starting /books/** and routes them to the book-
service.
📈 Actuator Configuration
[Link]=*
Exposes all Spring Boot Actuator endpoints (like /actuator/health, /actuator/routes, etc.) over HTTP for
monitoring and management.
📝 Logging Configuration
[Link]=DEBUG
[Link]=DEBUG
Sets detailed logging levels for troubleshooting:
[Link]=DEBUG enables debug logs for all Spring Web components.
[Link]=DEBUG enables debug logs specifically for the Gateway's internal
logic.
✅ Core Annotations for the API Gateway
@SpringBootApplication -> Main entry point for Spring Boot applications. Combines @Configuration,
@EnableAutoConfiguration, and @ComponentScan.
@EnableDiscoveryClient -> Enables the gateway to register itself with Eureka or any other discovery
service. Required if you're using Eureka for service discovery.
@EnableConfigurationProperties(optional) -> Enables support for externalized configuration classes, if
you define custom configuration properties.
@Configuration -> To define a class as a source of bean definitions for route configuration.
@Bean -> To manually define beans, e.g., route definitions using Java DSL (not always needed if using
properties).
@RestController -> If you want to expose any custom endpoints from the API Gateway (like a /status or
diagnostics endpoint).
JM-6 Page 16
diagnostics endpoint).
@RequestMapping -> For mapping HTTP paths to methods in the above controller.
JM-6 Page 17
Load Balancer
28 April 2025 10:07
Server side :
Server side load balance requires all the services to have load balancing which may increase the network
traffic.
It requires separate hardware and installation which is costly
Server-side load balancing is involved in monolithic applications.
Load Balancer has public IP and DNS
It mainly uses Round Robin or sticky session algorithms
Problems with Microservice architecture:
1. Server-side load balancing is am manual effort, and we need to add/remove instances manually to
the load balancer to work.
2. Loosing todays on demand scalability to auto-discover and configure
3. Fail-over policy to provide the client a seamless experience
4. Need a separate server to host the load balancer instance which has the impact on cost and
maintenance.
Client side:
They reside in the application as inbuilt component and bundled along with the application, so we don't
have to deploy them in separate servers.
On-demand scaling can be done with auto-discover and configure with the help of service discovery
pattern
It one microservice wants to communicate with another, it generally looks up the service registry using
discovery client and eureka server returns all the instances of that target microservice to the caller
service. Then it is the responsibility of the caller service to choose which instance to send request.
Client-side load balancing automatically handles the complexities around the situation and delegates to
proper instance in load balanced fashion.
We can specify the load balancing algorithm to use
There are two load balancer sites
1. Ribbon - Client side load balancer :
Ribbon is a client-side load balancer that gives a lot of control over the behavior of HTTP and TCP
clients.
Ribbon primarily provides client-side load balancing algorithms.
Spring cloud implements Ribbon as a wrapper over RestTemplate.
Ribbon could also be used independently by providing servers list
Default load balancing algorithm is Round-robin
Features of Ribbon :
- Service Discovery Integration :
Ribbon load balancers provide service discovery in dynamic environments like a cloud. Integration
with Eureka and Netflix service discovery component is included in the ribbon library
- Fault Tolerance :
Ribbon API can dynamically determine whether the servers are up and running in a live
environment and can detect those servers that are down
- Configurable load-balancing rules :
Ribbon supports RoundRobinRule, AvailabilityFilteringRule (circuit tripped),
WeightedResponseTimeRule and out of the box it supports defining custom rules.
JM-6 Page 18
Microservices Pattern
21 May 2025 10:34
Microservices:
1. Decomposition Patterns
These patterns help break down a monolith into microservices.
🔹 a) Decompose by Business Capability
Split services by domains like User Service, Order Service, Inventory Service.
Reflects the bounded context of Domain-Driven Design (DDD).
🔹 b) Decompose by Subdomain
Use strategic DDD to divide large domains into core, supporting, and generic subdomains.
🛠 2. Integra on Pa erns
Used for communication between services.
🔹 a) API Gateway Pattern
A single entry point for all client requests.
Handles routing, authentication, rate limiting.
Client → API Gateway → Microservices
Popular tools: Spring Cloud Gateway, Zuul, Kong
🔹 b) Aggregator Pattern
Combines multiple service calls into one response.
Useful when frontend needs data from several microservices.
🔄 3. Communication Patterns
How services talk to each other.
🔹 a) Synchronous (REST, gRPC)
Simple to implement.
Can cause tight coupling and latency.
JM-6 Page 19
Can cause tight coupling and latency.
🔹 b) Asynchronous (Event-Driven)
Uses message brokers like Kafka, RabbitMQ, etc.
Improves decoupling and resilience.
💣 4. Resilience Patterns
These patterns protect your system from failures.
🔹 a) Circuit Breaker Pattern
Prevents calling a failed service repeatedly.
Libraries: Resilience4j, Hystrix (deprecated)
🔹 b) Retry Pattern
Automatically retry a failed request after a delay.
🔹 c) Bulkhead Pattern
Isolate failures so one service doesn’t take down others.
🧠 5. Data Management Patterns
Each microservice owns its data — so coordination is tricky.
🔹 a) Database per Service
Every service has its own DB schema.
Avoids tight coupling, but needs careful coordination.
🔹 b) Saga Pattern
Manages distributed transactions.
Orchestration (central controller) or Choreography (event-driven).
🔹 c) CQRS (Command Query Responsibility Segregation)
Split read and write models for performance and scalability.
6. Observability Pa erns
Help in monitoring, logging, and tracing.
🔹 a) Log Aggregation
Collect logs from all services (e.g., ELK stack, Grafana + Loki).
🔹 b) Distributed Tracing
Track a request across multiple services.
Tools: Zipkin, Jaeger, OpenTelemetry
🔹 c) Health Check Pattern
Every service exposes a /health endpoint.
Used for monitoring and auto-scaling.
🔐 7. Security Patterns
🔹 a) Token-Based Security
Use JWT tokens for authentication.
Validate tokens at API Gateway or per service.
🔹 b) Service-to-Service Authentication
Use mTLS or tokens (e.g., OAuth2) for internal service calls.
📦 8. Deployment Patterns
🔹 a) Service Registry and Discovery
Services register themselves and discover others dynamically.
Tool: Eureka, Consul, Zookeeper
🔹 b) Sidecar Pattern
Add non-functional capabilities (e.g., logging, proxy) via a separate container in the same pod.
Used with Istio, Envoy in Kubernetes.
JM-6 Page 20
Spring Security
30 April 2025 09:55
JM-7 Page 1
JM-7 Page 2
🧾 What is the JWT Header?
It contains metadata — information about the token itself — specifically:
The type of token (which is usually JWT)
The signing algorithm used to secure the token
It’s a small JSON object that's then Base64Url-encoded.
⚙ How the Header Works
The header JSON is created during token generation (like you do in .signWith(...)).
It’s Base64Url-encoded (not regular Base64) — this means:
No padding characters (=)
URL-safe characters (- and _ instead of + and /)
<header>.<payload>.<signature>
🔐 Why the Header Matters
It tells whoever is parsing/validating the token how to interpret and verify it.
When your backend receives a token, it looks at the header to know:
What algorithm to use for verifying the signature
Whether it’s a valid JWT structure
If someone tampers with the token, the signature won’t match anymore — making the token invalid
JM-7 Page 3
📦 What Is the Payload in JWT?
The payload is the middle part of the JWT token and contains the claims, which are pieces of
information (key-value pairs) about the user or token itself.
In a JWT like this:
xxxxx.**yyyyy**.zzzzz
The yyyyy part is the payload, Base64Url-encoded.
JM-7 Page 4
🔐 What Is the Signature in JWT?
The signature is the third part of a JWT ([Link]), and its main purpose is to ensure the
integrity of the token. It makes sure that:
The token wasn't modified after being created.
The token was created by a trusted source (e.g., your server).
🧬 How the Signature Is Created
Formula (simplified):
Signature = HMACSHA256(
Base64UrlEncode(Header) + "." + Base64UrlEncode(Payload),
SecretKey
)
🛠 In Your Code:
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
You pass in the signing key and choose an algorithm (e.g., HS256).
The JWT library handles encoding the header and payload, then signing it.
JM-7 Page 5
The JWT library handles encoding the header and payload, then signing it.
⚙ Types of JWT Signature Algorithms
There are two main families of algorithms:
🔹 1. HMAC (Symmetric)
Same key is used to sign and verify.
Fast and simple.
Suitable when the same service handles both token creation and validation.
🧩 What is Base64Url?
Base64Url is a variant of the Base64 encoding scheme, which is designed to safely encode data that can
be used in URLs or filenames without causing issues.
While Base64 encoding is widely used to represent binary data as text (like in JWTs), it has some
characters (+, /, =) that are not URL-safe. Base64Url replaces these problematic characters to make the
encoding safe for URLs and HTTP headers.
🎯 Why Use Base64Url?
URL Safe: It avoids characters that could interfere with URL encoding (+, /, =, etc.).
JWT Compatibility: JWTs are designed to be URL-safe since they are often passed in HTTP headers or as
query parameters in URLs.
JM-7 Page 6
🔧 [Link] — Configuration
🔹 @Configuration & @EnableWebSecurity
Tells Spring this is a configuration class for web security.
🔹 securityFilterChain(HttpSecurity httpSecurity)
Defines how Spring Security should protect your endpoints.
csrf(AbstractHttpConfigurer::disable)
Disables CSRF since JWT makes CSRF less relevant (stateless).
authorizeHttpRequests(...)
Allows public access to:
/library/login
/library/users (for registration)
All other endpoints require authentication.
sessionManagement(...)
[Link]: No HTTP session is created. Every request must carry a valid token.
addFilterBefore(jwtAuthFilter(), [Link])
Adds your custom JWT filter before Spring’s default username/password authentication filter.
exceptionHandling(...)
If an unauthenticated user accesses a protected endpoint, it returns 401 Unauthorized.
🔹 passwordEncoder()
Uses BCrypt to hash passwords securely.
🔹 jwtAuthFilter()
Registers the custom JWT filter that you'll define in the next class.
🧱 [Link] — JWT Token Validation
🔹 Extends OncePerRequestFilter
Ensures the filter is applied once per request.
JM-7 Page 7
When a request is sent:
Spring Security Intercepts the Request First – This includes your SecurityFilterChain configuration.
JwtAuthenticationFilter Gets Triggered – It's checked before the default Spring authentication filter.
Filter Checks Path & Authorization Header:
If it's a public path (like /login or /users), it skips authentication.
If it's a protected path, it looks for the JWT token in the Authorization header.
JWT Token is Extracted & Validated:
The token is sent to JWTService, which checks if it's valid and not expired.
If valid, it sets the authentication in SecurityContextHolder.
Access is Granted or Denied Based on whether the user is authenticated.
So yes — the security filter acts like a gatekeeper, validating JWT tokens before the request reaches any
controller or endpoint logic.
JM-7 Page 8
API Gateway
13 May 2025 10:09
JM-7 Page 9
Spring Security terms
13 May 2025 20:55
JM-7 Page 10
18. AuthenticationEntryPoint
Used to handle unauthorized access (e.g., returning a 401 error).
19. OncePerRequestFilter
Ensures your custom filter (e.g., JWT filter) only runs once per request.
🧰 Session and Stateless Management
20. Stateless Authentication
No session is stored server-side. Each request must include authentication credentials (e.g., JWT).
21. Session Management
Controls how sessions are created and managed (e.g., STATELESS, ALWAYS, etc.).
🧪 Testing with Spring Security
22. @WithMockUser
Annotation used in unit tests to mock an authenticated user.
23. SecurityMockMvcRequestPostProcessors
Utilities for testing secure endpoints with MockMvc.
JWT Token Creation in Spring Boot
✅ Step 1: User Sends Login Request -> The user submits their username and password to the backend (e.g., via a login form or
API call).
🔍 Step 2: Backend Authenticates User -> Spring Security checks the submitted credentials against the database (or another
user store).
If credentials are valid, the user is considered authenticated.
🛠 Step 3: Generate the JWT Token
After successful login:
The server creates a JWT token that includes user info (usually the username) and optional data like user roles or permissions.
It adds a timestamp for when the token was created.
It adds an expiration time (e.g., valid for 1 hour).
The token is then digitally signed using a secret key so it can't be tampered with.
🎁 Step 4: Send the Token Back to the Client
The server sends the JWT token back to the client (usually in the response body or header).
The client stores it — typically in local storage or session storage (for browsers) or securely in mobile apps.
📲 Step 5: Client Uses Token in Future Requests
For all future requests, the client includes the JWT in the Authorization header like this:
Authorization: Bearer <token>
This allows the server to know who the user is without asking for a password again.
🔐 Step 6: Backend Validates the Token
For every request with a JWT:
The backend extracts the token from the request.
It checks if the token is valid:
Is it properly signed?
Has it expired?
Is the user still allowed access?
If all checks pass, the user is allowed to access the requested resource.
🚫 Step 7: Token Expiration / Renewal (Optional)
JWTs often expire after a certain time (e.g., 1 hour).
Once expired, the user needs to:
Log in again, or
Use a refresh token (optional strategy) to get a new access token without logging in.
JM-7 Page 11
Algorithms
13 May 2025 21:40
JM-7 Page 12
PasswordEncoder encoder = [Link]();
✅ Smart and flexible
Supports multiple encoders at once
Stores the encoding algorithm in the password string itself
Example stored password: {bcrypt}$2a$10$EJ4...
Super useful for migrating from one hashing algorithm to another without breaking existing passwords.
What Are Signing Algorithms?
A signing algorithm is a cryptographic method used to sign a JWT (JSON Web Token). It ensures that the
data in the token has not been tampered with and can be trusted. This is achieved by creating a digital
signature using the payload (the data part of the token) and a secret key (or private key in case of
asymmetric algorithms).
Purpose of Signing Algorithms:
Data Integrity: Ensures that the payload (data) inside the token hasn't been modified.
Authentication: Confirms that the token was issued by a trusted source (e.g., your application/server).
Types of Signing Algorithms
There are two main families of signing algorithms:
1. Symmetric Signing Algorithms (Shared Secret)
In these algorithms, the same key is used both to sign and verify the token.
Fast, simple, but less secure if the secret key is not properly managed.
Example: HMAC (Hash-based Message Authentication Code).
2. Asymmetric Signing Algorithms (Public/Private Key Pair)
In these algorithms, a private key is used to sign the token, and the corresponding public key is used to
verify it.
More secure because the private key is never exposed and can be safely kept on the server while
anyone can use the public key to verify the token.
Example: RSA, ECDSA.
Symmetric Signing Algorithms
1. HMAC (Hash-based Message Authentication Code)
HMAC is the most commonly used symmetric algorithm in JWTs.
How it works: A hash function (like SHA-256) is applied to the message (JWT header + payload), and the
result is then signed with a shared secret key.
Common Variants:
HS256: HMAC with SHA-256 (most commonly used)
HS384: HMAC with SHA-384
HS512: HMAC with SHA-512
Pros: Fast, simple to implement, and suitable for simple systems where you control both the signing and
verification.
Cons: If the secret key is exposed or leaked, anyone can generate valid tokens.
Asymmetric Signing Algorithms
2. RSA (Rivest-Shamir-Adleman)
RSA is an asymmetric cryptographic algorithm, meaning it uses two keys:
Private key for signing.
Public key for verification.
How it works: The private key signs the payload, and anyone with the public key can verify that the
signature is correct without knowing the private key.
Common Variants:
RS256: RSA with SHA-256 (most common for JWTs)
RS384: RSA with SHA-384
RS512: RSA with SHA-512
Pros: Strong security since the private key is not shared.
Cons: Slower than symmetric algorithms because of the computational cost of asymmetric encryption.
3. ECDSA (Elliptic Curve Digital Signature Algorithm)
ECDSA is a variant of RSA but based on elliptic curve cryptography.
It uses smaller key sizes than RSA for the same level of security, which makes it more efficient.
JM-7 Page 13
It uses smaller key sizes than RSA for the same level of security, which makes it more efficient.
How it works: Like RSA, ECDSA uses a private key to sign and a public key to verify the signature.
Common Variants:
ES256: ECDSA with SHA-256
ES384: ECDSA with SHA-384
ES512: ECDSA with SHA-512
Pros: More efficient than RSA, providing the same level of security with smaller key sizes.
Cons: Slightly more complex to implement compared to RSA.
How These Signing Algorithms Work in Practice:
1. Symmetric Signing (e.g., HMAC):
The server generates a JWT using a shared secret key.
The client sends the JWT back to the server in each request.
The server recalculates the signature with the same shared key and compares it to the signature in the
token.
If the signature matches, the token is valid; otherwise, it’s tampered with.
2. Asymmetric Signing (e.g., RSA, ECDSA):
The server uses a private key to sign the JWT and sends it to the client.
The client sends the JWT back in each request.
The server uses a public key to verify the signature, ensuring it was signed with the private key.
If the signature matches, the token is valid; otherwise, it’s invalid or tampered with.
JM-7 Page 14
Multi-Threading
12 May 2025 09:40
By default programming languages are sequential in nature. Code execution happens line by line in
usual scenario.
Problem with the sequential execution: In a single threaded program these instructions will be executed
one by one. The time consuming sections of the code can freeze the entire application.
Solution: Figure out the time consuming tasks and decide if they can be run separately. If yes, run such
tasks in separate threads.
Multi-Threading is the ability to CPU to perform different tasks concurrently.
Pros and Cons of Multi-threading:
Pros
- We can build responsive applications
- Better resource utilization
- Better performance applications
- CPU is not idle for more time.
Cons
- Synchronization is tricky
- Difficult to design and test MT apps
- Thread context switch is expensive
Differences between Concurrency v/s Parallelism :
JM-8 Page 1
Concurrency is fake parallelism, it deals with independent process and parallelism deals with dependent
process since it divides the process into small tasks.
JM-8 Page 2
Time Slicing Algorithm:
It is timeframe for which process is allotted to run in preemptive multitasking CPU. The scheduler runs
each process every single time-slice. The period of each time slice can be very significant and crucial to
balance CPUs performance and responsiveness.
If time slice is quite short, scheduler will take more processing time. In contrast, if the time slice is too
long, scheduler will again take more processing time.
Advantages :
Fair allocation of CPU resources.
It deals all process with equal priority.
Easily implementable on the system.
Context switching method used to save states of preempted processes
gives best performance in terms of average processing time.
Disadvantages :
If the slicing time is short, processor output will be delayed.
It spends time on context switching.
Performance depends heavily on time quantum.
Priorities can’t be fixed for processes.
No priority to more important tasks.
Finding an appropriate time quantum is quite difficult.
Thread Lifecycle:
Each program by default has main thread created by JVM which is also called as parent thread. All
program has only one thread and works sequentially until it doesn't contain multithread invocation
called by the programmers.
Thread creation :
A thread can programmatically be created by:
- Implementing the [Link] interface.
- Extending the [Link] class.
- Using Lambda Expressions
- Using ExecutorService
1. Thread Class
The Thread class provides constructors and methods for creating and operating on threads. The thread
extends the Object and implements the Runnable interface.
Method: public void start()
It starts a newly created thread. Thread moves from new state to runnable state when it gets a chance,
executes the target run() method
Use Case: Suitable for simple applications for creating a thread that performs a specific task.
✅
JM-8 Page 3
✅ Pros:
Simple and straightforward.
Good for quick experiments or small tasks.
❌ Cons:
Not flexible — you're extending a class, so you can't extend another one.
Harder to manage multiple threads or reuse.
2. Runnable Interface
Any class with instances that are intended to be executed by a thread should implement the Runnable
interface. The Runnable interface has only one method, which is called run().
Use Case: It is suitable for cases where you want to separate the task from the thread management.
Also, Runnable is a interface so allows us to perform multiple inheritance.
✅ Pros:
More flexible than extending Thread (can still extend another class).
Encourages separation of task from the thread itself.
❌ Cons:
Slightly more verbose than Thread or lambda.
Manual thread creation and management required.
3. Using Lambda Expressions
Lambda Expressions are very useful for creating the Threads in the cases when the operations to be
performed are limited.
Use Case: Used for Threads performing simple tasks.
✅ Pros:
Very concise.
Useful for short tasks or when passing behavior as parameters.
❌ Cons:
Not suitable for long or complex logic (can hurt readability).
Still requires manual thread management.
4. Using ExecutorService (for Managing Thread Pools)
The ExecutorService framework provides a higher-level way to manage threads. It allows you to create a
pool of threads and manage their execution.
Use Case: Used for concurrent execution of multiple threads.
✅ Pros:
• Best for scalability and production.
• Thread pooling = better resource management.
• Can return Future results.
• Supports scheduling, fixed-size thread pools, etc.
❌ Cons:
• Slightly more setup code.
• Need to remember to shut down the executor.
JM-8 Page 4
The execution happens sequentially,
Once the thread is started then it is available to be scheduled by the thread scheduler and once the
thread scheduler finds an available spot for a particular thread to be run in CPU then it is assigned to
CPU for running.
Join() Method :
Main Thread has highest priority.
Normally first main is executed then the other threads are executed. All threads are executed
independently.
If we want to execute the main thread after the execution child thread then we need to use [Link]().
Join() methods throws the interruptException, to handle this exception we need to use the try-catch
block or throw in method itself.
[Link] class provides the join() method which allows one thread to wait until another thread
completes its execution. If t is a Thread object whose thread is currently executing, then [Link]() will
make sure that t is terminated before the next instruction is executed by the program.
If there are multiple threads calling the join() methods that means overloading on join allows the
programmer to specify a waiting period.
However, as with sleep, join is dependent on the OS for timing, so you should not assume that join will
wait exactly as long as you specify. There are three overloaded join functions.
1. join(): It will put the current thread on wait until the thread on which it is called is dead. If a thread is
interrupted then it will throw InterruptedException.
Syntax: public final void join()
2. join(long millis): It will put the current thread on wait until the thread on which it is called is dead or
wait for the specified time (milliseconds).
Syntax: public final synchronized void join(long millis)
3. join(long millis, int nanos): It will put the current thread on wait until the thread on which it is called is
dead or wait for the specified time (milliseconds + nanos).
Syntax: public final synchronized void join(long millis, int nanos)
On basis of surface of execution threads can be of two types:
1. Daemon Threads
2. User Threads
When a Java Program starts the main thread(main() method thread) starts running immediately. We can
start child threads from the main thread. The main thread is the last thread to finish execution in normal
circumstances, because it has to perform various shutdown operations.
Daemon Threads: Daemon threads are intended to be helper threads which can run in background and
are of low priority. Example GC thread
Daemon threads are terminated by the JVM when all other user threads are terminated (done with their
execution)
So, under normal circumstances, user threads are allowed to terminate once they are done with their
execution. However, the daemon threads are shutdown by JVM once all the other threads are done
JM-8 Page 5
execution. However, the daemon threads are shutdown by JVM once all the other threads are done
executing.
By default, any thread is not a daemon thread.
Whether the daemon thread has completed its execution or not but it gets terminated as soon as the
child and main threads have completed their execution.
[Link](milliseconds) -> throws Interrupted exception
Thread Priority :
Thread scheduler is used to schedule the thread to CPU for execution.
Each thread has certain priority and under normal circumstances the thread with higher priority is
executed on CPU.
Priority Value from 1 to 10 can be assigned to any thread. 1 -> MIN_PRIORITY and 10 -> MAX_PRIORITY.
By default, the priority of thread is 5, represented as NORM_PRIORITY
Threads with same priority are executed in FIFO manner. The thread scheduler store the threads in a
queue.
Regardless of the priority main thread has the highest priority and given first preference for execution
since it is the starting point for the JVM.
Thread Synchronization:
Change in the value of counter can be using non-atomic operations
This condition is called as race-condition.
To achieve mutual exclusion, where all threads share their resources, we need to use synchronized
keyword which makes the resource to be accessed by one thread at a time.
The code in synchronized method are called as critical section code which should be handled by multi-
threaded environment
You can’t mark a field synchronized, but you can:
Synchronize methods that access the field
Use synchronized blocks
Use locks (ReentrantLock)
Use atomic variables for primitive types
Working of Synchronization:
In Java, every object has an intrinsic lock (also called a monitor lock or just monitor). When a thread
wants to execute a synchronized method or block, it must acquire the monitor lock of the associated
object.
Only one thread can hold the monitor lock for an object at a time. Others are blocked until it’s released.
JVM uses monitorenter and monitorexit bytecode instructions.
These manage the monitor lock when entering and exiting synchronized code blocks.
Problems with synchronization:
- Blocking small code, reduces concurrency and performance bottlenecks
- When used at method level we lose the fine grained control of complexity
- If a super class method is synchronized then the child class method should also be synchronized.
Synchronized keyword at block level is used for decoupling of the threads.
Wait and Notify:
These methods are interruptible methods so they might throw exception to handle them we use
exception handler.
wait(): The wait() method makes a thread voluntarily give up its lock on an object, allowing another
thread to execute code within a synchronized block. The thread that calls wait() will enter a waiting state
until another thread calls notify() or notifyAll() on the same object, allowing it to resume execution.
notify(): The notify() method wakes up one of the waiting threads on the same object. If multiple
threads wait, it is not specified which one will be awakened. The awakened thread will then compete for
the lock on the object. If notify is used in the synchronized block then after the completely the execution
of that block only the other threads will be executed.
notifyAll(): The notifyAll() method wakes up all waiting threads on the same object. This can be useful
when multiple threads are waiting, and you want them to be notified simultaneously.
Why wait(), notify() and notifyAll() are in Object Class:
- Object-level Synchronization
JM-8 Page 6
- Object-level Synchronization
- Wait and Notify Semantics
- Multiple Threads per Object
- Avoids Coupling to Thread
- Encourages better design
Wait() is used in Inter Thread Communication and synchronization
What if a thread goes a long time without invoking a method that throws InterruptedException? Then it
must periodically invoke [Link], which returns true if an interrupt has been received. For
example:
JM-8 Page 7
Volatile
05 May 2025 09:51
JM-8 Page 8
Volatile Keyword vs. Other Types of Keywords in Java
Volatile vs. Atomic
Marking a variable as volatile means declaring that multiple threads will be accessing this variable. This
makes the value of the variable visible to all threads. On the other hand, atomicity refers to an operation
being indivisible. The atomic keyword hides a process from other threads until it’s been completed,
making it appear as if it’s been accomplished in one step and preventing other threads from interfering
in the process.
JM-8 Page 9
in the process.
JM-8 Page 10
Thread Local
05 May 2025 10:10
JM-8 Page 11
- Web server Requests
Per Thread Context (Thread-safety + perf) - ThreadLocal
JM-8 Page 12
After all the operations we need to clean the resources
JM-8 Page 13
JM-8 Page 14
Parallelism
05 May 2025 10:21
Parallelism leads to overlapping of central processing units and input-output tasks in one process with
the central processing unit and input-output tasks of another process. Whereas in concurrency the
speed is increased by overlapping the input-output activities of one process with CPU process of another
process.
JM-8 Page 15
Concurrency :
Concurrency is about dealing with lot of things at once
Concurrency is applied when we have shared resource to be accessed or updated
Multiple tasks need to coordinate
Concurrency relates to an application that is processing more than one task at the same time.
Concurrency is an approach that is used for decreasing the response time of the system by using the
single processing unit. Concurrency creates the illusion of parallelism, however actually the chunks of a
task aren’t parallelly processed, but inside the application, there are more than one task is being
processed at a time. It doesn’t fully end one task before it begins ensuing.
Concurrency is achieved through the interleaving operation of processes on the central processing
unit(CPU) or in other words by the context switching. that’s rationale it’s like parallel processing. It
increases the amount of work finished at a time.
JM-8 Page 16
Interleaving of thread
JM-8 Page 17
JM-8 Page 18
Java Memory model
05 May 2025 10:43
JM-8 Page 19
This concept is applicable to
Synchronized
Locks
Concurrent collections
Thread operations (Join, start)
Final fields (special behavior)
JM-8 Page 20
Java ExecutorService
05 May 2025 11:01
Java executor framework ([Link]), released with the JDK 5, is used to run the
Runnable objects without creating new threads every time and mostly re-using the already created
threads. We all know that there are two ways to create a thread in Java. If you want to read more about
their comparison, read how to create threads in Java.
The [Link] provide factory methods that are used to create ThreadPools of
worker threads. Thread pools overcome this issue by keeping the threads alive and reusing them. Any
excess tasks flowing in that the threads in the pool can’t handle are held in a Queue. Once any of the
threads get free, they pick up the next task from this queue. This task queue is essentially unbounded
for the out-of-the-box executors provided by the JDK.
Some types of Java Executors are listed below:
Executor 1: SingleThreadExecutor
A thread pool of a single thread can be obtained by calling the static newSingleThreadExecutor() method
of the Executors class. It is used to execute tasks sequentially.
Syntax:
ExecutorService executor = [Link]();
Executor 2: FixedThreadPool(n)
As the name indicates, it is a thread pool of a fixed number of threads. The tasks submitted to the
executor are executed by the n threads, and if there are more task, they are stored on a
LinkedBlockingQueue. It uses Blocking Queue.
Syntax:
ExecutorService fixedPool = [Link](2);
Executor 3: CachedThreadPool
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads
when they are available. Calls to execute will reuse previously constructed threads if available. If no
existing thread is available, a new thread will be created and added to the pool. It uses a
SynchronousQueue queue.
ExecutorService executorService = [Link]();
Task Queue can contain one task at max. If all threads are busy a new thread is created and task is
assigned to that thread. If a thread is idle for more than 60 seconds, it's killed.
Executor 4: ScheduledExecutor
Scheduled executors are based on the interface ScheduledExecutorService which extends the
ExecutorService interface. This executor is used when we have a task that needs to be run at regular
intervals or if we wish to delay a certain task.
ScheduledExecutorService scheduledExecService = [Link](1);
The tasks can be scheduled using either of the two methods:
scheduleAtFixedRate: This executes tasks at fixed intervals, regardless of task completion time. If a task’s
execution exceeds the interval, tasks will queue.
scheduleWithFixedDelay: This will start the delay countdown only after the current task completes.
Syntax:
[Link]
(Runnable command, long initialDelay, long period, TimeUnit unit)
JM-8 Page 21
Future Object
The result of the task submitted for execution to an executor can be accessed using the
[Link]. The future object returned by the executor. Future can be thought of as a promise
made to the caller by the executor. The future interface is mainly used to get the results of Callable
results. whenever the task execution is completed, it is set in this Future object by the executor.
Syntax:
Future<String> result = [Link](callableTask);
JM-8 Page 22
Pool Size:
If you want run() to return any value then we need to use the Callable Interface which is of Generic type
JM-8 Page 23
[Link]() return the Future values which leads to the dark mode. Future will empty until the
thread pool completes its execution. Future is a blocking operation. If there is no value in Future and u
called the get() then it makes the main thread into blocked and whole process gets blocked until it gets
the value from the thread pool
JM-8 Page 24
Synchronized Collections
12 May 2025 20:14
JM-8 Page 25
ACID
20 May 2025 10:26
JM-8 Page 26