JavaMain 1
JavaMain 1
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this article, we will discuss frequently asked Java main() method interview questions with answers
As we know that Java main() method is the entry point of any Java program. Its syntax is always
Watch on
3. Can we declare the main() method as private or protected or with no access modifier?
6. Can the main() method take an argument other than String array?
If the main() method is non-static, then JVM needs to create an instance of the class, and there would
be ambiguity if the constructor of that class takes an argument – which constructor should be called
by JVM and what parameters should be passed? We know that JVM can’t instantiate a Java class
The following example demonstrates why the main() method is static in Java.
package net.javaguides.corejava;
We know that anyone can access/invoke a method having public access specifier. The main()
method is public in Java because it has to be invoked by the JVM. So, if main() is not public in Java,
the JVM won’t call it.
main(String[] args).
The diagram below demonstrates that the main() method can be overloaded:
package net.javaguides.corejava;
import java.util.Arrays;
Output:
protected or with no access modifier. This is because to make the main() method accessible to
JVM.
The below diagram shows a runtime error if you define the main() method other than public.
instantiating its class. If you remove ‘static’ from the main() method signature, the compilation will
The below diagram demonstrates that the main() method should be static otherwise JVM will throw
a runtime error:
5. Can we change the return type of the main()
method?
No, the return type of the main() method must be void only. Any other type is not acceptable.
The diagram below demonstrates that the main() method should have a void return type:
you can pass var args of string type as an argument to the main() method. Again, var args are
The below diagram demonstrates that the main() method should have an argument as String array
or var args:
Error: Main method not found in class Test, please define the main method as:
public static void main(String[] args)
or a JavaFX application class must extend javafx.application.Application
Output: (JDK 6)
Static Initalizer
The diagram below demonstrates that we can have the main method as the final in Java.
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this article, we will discuss a few frequently asked Java Array interview questions with answers for
beginners.
YouTube Video
1. What is an Array?
An Array is a data structure that defines an index-based collection of a fixed number of homogeneous
data elements. This means that all elements in the array have the same data type and Array a starts
from index 0.
For example, This is an array of 10 elements. All the elements are integers and homogeneous.
The size of an array is fixed and cannot be changed after the array has been created.
In Java, arrays are objects. Arrays can be of primitive data types or reference types.
The main use of Array is used to store multiple values in a single variable, instead of declaring
separate variables for each value.
For example:
int[] array = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };
2. What Is the Advantage and Disadvantage of
an Array?
Advantage of an Array
-> The main use of Array is used to store multiple values in a single variable, instead of
declaring separate variables for each value.
For example:
int[] array = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };
-> We can access any element randomly by using indexes provided by arrays.
For example:
Output:
Element 1 at index 0: 10
Element 2 at index 1: 20
Element 3 at index 2: 30
Element 4 at index 3: 40
Element 5 at index 4: 50
-> We can sort multiple elements of Array at the same time.
Arrays are Strongly Typed: This means that all elements in the array have the same data type. We
can not store different types of data in an Array.
2. Multidimensional Array
For example:
int[] array = { 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 };
The following program creates an array of integers, puts some values in the array, and prints each
Output:
Multidimensional Array
A multi-dimensional array in Java is an array of arrays. A two-dimensional array is an array of one-
class MultiDimArrayDemo {
// Mr. Smith
System.out.println(names[0][0] +
names[1][0]);
// Ms. Jones
System.out.println(names[0][2] +
names[1][1]);
}
}
Output:
Mr. Smith
Ms. Jones
then you will not get the compiler error. Instead, you will get the NegativeArraySizeException at run
time.
5. When ArrayIndexOutOfBoundsException
occurs?
ArrayOutOfBoundsException is thrown when an attempt is made to access the Array with an illegal
index. For example, an illegal index means if the index is either negative or greater than or equal to
the size of the Array.
For example 1: Below program tries to access the element at index 5 but the array index starts from
index 0. The index 5 is equal to the size of an Array hence throwing ArrayOutOfBoundsException :
System.out.println(element);
}
}
Output:
For example 2: Access array with negative index to Array leads to throwing
ArrayOutOfBoundsException :
System.out.println(element);
}
}
Output:
after the array has been created. ArrayList is dynamic in nature. If you add elements to an ArrayList, it
3. Java provides add() method to insert an element into ArrayList and we can use the assignment
ArrayList.add() method:
4. We can not use Generics along with Array whereas ArrayList allows you to use Generics to ensure
type safety.
5. Length of the ArrayList is provided by the size() method while Each array object has the length
Example 1: find the length of the ArrayList using the size() method:
import java.util.ArrayList;
import java.util.List;
Output:
Output:
6. The performance of Array and ArrayList depends on the operation you are performing :
resize() operation: Automatic resize of ArrayList will slow down the performance as it will use a
temporary array to copy elements from the old array to the new array.
add() or get() operation: adding an element or retrieving an element from the array or ArrayList
object has almost the same performance, as for ArrayList object these operations run in constant time.
This exception is thrown to indicate that an attempt has been made to store the wrong type of object
in an array of objects. In other words, if you want to store the integer Object in an Array of String you
Output:
you try to add an integer object to String Array, then ArrayStoreException is thrown.
ArrayOutOfBoundsException is thrown when an attempt is made to access the Array with an illegal
index. For example, an illegal index means if the index is either negative or greater than or equal to
For example:
Output:
In the example above, we've changed the first element of the array, demonstrating the mutability of
arrays in Java.
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this article, we will discuss some important Java String Interview Questions and Answers for
beginners as well as experienced candidates.
Before we get started, check out Complete guide to Java String, StringBuilder, and
StringBuffer methods
I would like to share my experience with Java String Interview questions. I have listed these most
commonly asked interview questions and answers regarding String handling in Java.
YouTube Video
Watch on
From Java API, the String is a Java Class defined in java.lang package. It’s not a primitive data
1. By string literal
2. By new keyword
For Example:
String s="javaguides";
For example, String is immutable in Java, once you created a String object then you can't modify it.
Any modification leads to a new String object being created.
For example:
In the above example, the JVM will only create one object in the string constant pool. Both str1 and
On the other hand, the equals() method is used to compare the content or values of objects, and it
Output:
false
true
3. The performance of the String is slower than StringBuilder in the case of multiple concatenation
operations. This is because the string is immutable in Java, and the concatenation of two string
4. A String class overrides the equals() method of the Object class. So you can compare the
contents of two strings by the equals() method. StringBuilder class doesn't override the
operations because every time it creates a new instance. But StringBuffer is fast and consumes
less memory when you cancat strings.
3. A String class overrides the equals() method of an Object class. So you can compare the
contents of two strings by the equals() method. StringBuffer class doesn't override the
4. String class uses a String constant pool to store the objects whereas StringBuffer class uses heap
Note that, if another String with the same contents exists in the String constant pool, then a new
object won't be created and the new reference will point to the other String.
We can call the intern() method to tell the JVM to add it to the string pool if it doesn't already exist
String s1 = "abc";
String s2 = new String("abc");
String s3 = new String("foo");
String s4 = s1.intern();
String s5 = s2.intern();
System.out.println(s3 == s4);
System.out.println(s1 == s5);
Output:
false
true
other HashMap key objects. This is why String is mostly used Object as HashMap keys.
String s2 = "javaguides";
Answer:
Two objects will be created. Here's the breakdown:
When the code encounters the string literal "javaguides", it ensures there's an instance of it in the
String Pool. If not already present, one is created. This is our first object.
Using the new keyword forces Java to create a new String object in the heap memory, regardless of
whether the content is already present in the String Pool or not. This is our second object.
For s2 , no new object is created. Instead, the reference from the String Pool (from our first object) is
simply assigned to s2 .
To summarize:
Answer:
String Literal "javaguides": When the code encounters the string literal "javaguides", it ensures
there's an instance of it in the String Pool. If not already present, one is created. This is our first
object.
new String("javaguides") for s1: Using the new keyword forces Java to create a new String object in
the heap memory, regardless of whether the content is already present in the String Pool or not. This
new String("javaguides") for s2: Again, using the new keyword causes another separate String
To summarize:
2 objects are directly stored in the heap memory (outside the StringPool).
String class.
equals(): Compares the content of two strings. Returns true if they have the same content, false
otherwise.
equalsIgnoreCase(): Compares the content of two strings, ignoring case differences.
compareTo(): Lexicographically compares two strings. Returns 0 if they are the same, a negative
integer if the first string comes before the second, or a positive integer if the first string comes after
the second.
For example:
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this blog post, we will learn what is String, how to use it, its important methods with an example,
why String is immutable, and the best practices to use Strings in Java.
1. What is a String?
In Java, a string is a sequence of characters. The String class provides methods to manipulate these
characters, like concatenating two strings, converting characters to uppercase, and so on.
Key Features of String
Immutability: Strings are immutable in Java, meaning once created, they cannot be changed. Any
modification to a string results in a new object, leaving the original string unaltered.
String Pool: Java uses a special memory area known as the String Pool to store string literals. This
helps in saving memory, as multiple references to the same string literally point to the same object in
the pool.
String Creation: Strings can be created using either string literals or the new keyword. Creating
strings with literals promotes reusing existing objects from the String Pool, whereas the new keyword
Concatenation: Strings can be concatenated using the + operator or the concat() method.
Comparison: Strings can be compared using the equals() method for content comparison or ==
for reference comparison. The equalsIgnoreCase() method can be used for case-insensitive content
comparisons.
Case Handling: Methods like t oLowerCase() and toUpperCase() allow conversion between
different cases.
Substring & Character Access: Methods like substring() , charAt() , and indexOf() help in
Trimming & Replacing: trim() is used to remove leading and trailing whitespace. replace() and
Converting to Other Types: Strings can be converted to arrays of characters using toCharArray() .
Various parsing methods like Integer.parseInt() can convert a string to numerical types.
Performance Consideration: Since strings are immutable, frequent modifications can lead to
performance issues. In scenarios with intense string manipulation, consider using StringBuilder or
StringBuffer.
2. Creating String Objects
There are two ways to create a String object:
1. By string literal
2. By new keyword
For Example:
String s="javaguides";
Each time you create a string literal, the JVM checks the string constant pool first. If the string already
exists in the pool, a reference to the pooled instance is returned. If a string doesn't exist in the pool, a
new string instance is created and placed in the pool.
For example:
String s1="javaguides";
String s2="javaguides";
//will not create new instance
To know more detail about how the String Pool works on Guide to Java String Constant Pool
It's simple, to make Java more memory efficient because no new objects are created if it exists already
in the string constant pool.
Let's create a simple example to demonstrate by creating String objects using the new keyword.
Output:
From the above example, JVM will create a new string object in normal(non-pool) heap memory, and
the literal "Java Guides" will be placed in the string constant pool. The variable str will refer to the
char chars[] = {
'a',
'b',
'c'
}
;
String s = new String(chars);
operations on strings, such as trimming, replacing, converting, comparing, and more. Let's explore the
important methods of the String class in Java and illustrates how they can be used.
This method returns the length of the string, i.e., the number of characters in it.
The charAt() method returns the character at a specific index in the string.
altered. Instead, any operation that seems to change the content of a string actually results in a new
creation. This property eliminates synchronization issues in multithreaded applications, making string
2. Performance Optimization through String Pooling: Since strings are immutable, Java can cache
them in a special memory region called the String Pool. If the same string literal is used elsewhere in
the program, both references will point to the same object in the pool. This saves memory and boosts
performance.
3. Hashcode Caching: Strings in Java often act as keys in collections like HashMap and HashSet. The
hashcode of an object, once calculated, can be cached as long as the object is not modified. Since
strings are immutable, their hashcode remains constant, allowing for efficient retrieval from
collections.
4. Integrity and Reliability: Immutability ensures that once a string object is created, it will not be
changed by any part of the code, intentionally or unintentionally. This behavior makes the code more
5. Simplifies Complex Systems: In a large and complex application, tracking and controlling object
6. Class Loading and Security Concerns: Strings are used in various parts of Java's Class Loading
mechanism, including specifying the classpath. Mutable strings could pose security risks and create
For complex string creation, the String.format provides a more readable approach:
if (str1.equals(str2)) { /*...*/ }
if (str1.equalsIgnoreCase(str2)) { /*...*/ }
if (str.isEmpty()) { /*...*/ }
StringBuffer.
Make use of methods like trim(), split(), toLowerCase(), toUpperCase(), etc., to manipulate strings
without reinventing the wheel.
Conclusion
In this blog post, we have learned what is String, key points about String, different ways to create
String objects, important String class methods with examples, we discussed why String is immutable in
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
🧠 Introduction
If you're learning Java, you’ve probably used String values like this:
But did you know this string is stored differently than using new String("Ramesh")?
✅ Simply put:
It’s a memory optimization technique that avoids creating duplicate String objects
with the same value.
🔍 How It Works
When you create a string like this:
➡️Java doesn’t create a new object — it simply points str2 to the same "Java" instance in the
pool.
➡️It creates a new object in the heap, even if "Java" already exists in the pool.
✅ Why Does Java Do This?
Strings are immutable, meaning they can’t be changed once created.
Many programs use the same string values repeatedly (like "yes", "no", "OK").
So instead of creating multiple "yes" strings, Java reuses the same one in the pool, saving
memory.
Output:
true
false
true
one.
String s4 = new String("World").intern();
String s5 = "World";
⚠️Things to Remember
Only string literals are automatically added to the pool.
new String("value") always creates a new object.
Use intern() if you want to move a runtime string into the pool.
Too many string literals in large applications can still fill up memory — use wisely!
📋 Interview Tip
Q: What's the difference between == and .equals() in String comparison?
A:
So in String Pool:
String a = "Java";
String b = "Java";
System.out.println(a == b); // true
✅ Summary
Concept Explanation
Final Thoughts
The String Constant Pool is a powerful concept that improves both performance and memory
usage in Java applications. By understanding how it works, you can write better, more efficient Java
code.
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The StringBuffer class in Java is used to create mutable strings. Unlike the String class, which
creates immutable strings, StringBuffer allows you to modify the string without creating a new
object. This makes StringBuffer useful for applications where you need to perform many
modifications to a string.
Table of Contents
1. Constructors
2. Important Methods
append()
insert()
replace()
delete()
deleteCharAt()
reverse()
capacity()
length()
charAt()
setCharAt()
substring()
4. Conclusion
1. Constructors
The StringBuffer class provides several constructors to initialize a StringBuffer object.
Examples:
Output:
sb1: , capacity: 16
sb2: java guides, capacity: 27
sb3: , capacity: 50
2. Important() Methods
append()
The append() method adds the specified string to the end of the existing string.
Syntax:
Example:
Output:
insert()
The insert() method inserts the specified string at the specified position.
Syntax:
Example:
public class StringBufferInsertExample {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
sb.insert(5, "programming ");
System.out.println("After insert: " + sb);
}
}
Output:
replace()
The replace() method replaces the characters in a substring of the string with the specified string.
Syntax:
Example:
Output:
delete()
The delete() method removes the characters in a substring of the string.
Syntax:
Example:
Output:
deleteCharAt()
Syntax:
Example:
reverse()
Syntax:
Example:
Output:
capacity()
The capacity() method returns the current capacity of the string buffer.
Syntax:
Example:
public class StringBufferCapacityExample {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("java guides");
System.out.println("Capacity: " + sb.capacity());
}
}
Output:
Capacity: 27
length()
The length() method returns the length (number of characters) of the string buffer.
Syntax:
Example:
Output:
Length: 11
charAt()
Example:
Output:
Character at index 5: g
setCharAt()
The setCharAt() method sets the character at the specified index to the given character.
Syntax:
Example:
Output:
After setCharAt: java Guides
substring()
The substring() method returns a new string that is a substring of the original string buffer. It can
take one or two arguments: the start index and optionally the end index.
Syntax:
Example:
Output:
Example Code:
public class StringBufferExample {
public static void main(String[] args) {
// Create a new StringBuffer with initial string
StringBuffer sb = new StringBuffer("java guides");
// append() method
sb.append(" tutorial");
System.out.println("After append: " + sb);
// insert() method
sb.insert(5, "programming ");
System.out.println("After insert: " + sb);
// replace() method
sb.replace(5, 16, "learning");
System.out.println("After replace: " + sb);
// delete() method
sb.delete(5, 13);
System.out.println("After delete: " + sb);
// deleteCharAt() method
sb.deleteCharAt(4);
System.out.println("After deleteCharAt: " + sb);
// reverse() method
sb.reverse();
System.out.println("After reverse: " + sb);
// capacity() method
System.out.println("Capacity: " + sb.capacity());
// length() method
System.out.println("Length: " + sb.length());
// charAt() method
char ch = sb.charAt(5);
System.out.println("Character at index 5: " + ch);
// setCharAt() method
sb.setCharAt(5, 'G');
System.out.println("After setCharAt: " + sb);
// substring() method
String substr1 = sb.substring(5);
String substr2 = sb.substring(0, 4);
System.out.println("Substring from index 5: " + substr1);
System.out.println("Substring from index 0 to 4: " + substr2);
}
}
Output:
4. Conclusion
The StringBuffer class in Java provides a variety of methods to manipulate and modify strings
efficiently. Understanding and utilizing these methods allows you to perform complex string
operations with ease. This tutorial has covered the most important methods of the StringBuffer
175K
Subscribers
Java HashMap
author: Ramesh Fadatare
JAVA.UTIL PACKAGE
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
In this article, you will learn what is a HashMap, how to create a HashMap, how to add new key-value
pairs to a HashMap, how to remove keys from a HashMap, how to iterate over a HashMap, and how
to create and store user-defined objects as keys in a HashMap, and much more.
The HashMap class in Java is part of the Java Collections Framework and implements the Map interface.
It provides the basic implementation of the Map interface of Java and is used to store data in the form
HashMap uses a technique called Hashing, which allows us to access elements directly by calculating a
unique key from their content. This unique key is the index at which the specific value is stored,
making retrieval efficient.
Key-Value Pairs
HashMap stores data in key-value pairs. The key is used as an index to store data. The value is the
HashMap allows one null key and multiple null values in a collection.
Non-Synchronized
HashMap is not synchronized, which means it is not thread-safe. If it is used in a multi-threaded
environment, then it must be synchronized externally.
The order in which keys or values are inserted into a HashMap is not necessarily the order in which
they are iterated.
Unordered
HashCode Method
The keys of HashMap are objects. Hence, these objects must implement the equals method and the
hashCode method in order to follow the contract of the Map interface.
Performance
HashMap offers constant time performance for the basic operations get and put, assuming the hash
The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity
at the time the hash table is created. Load factor is a measure of how full the hash table is allowed to
get before its capacity is automatically increased.
Implements
HashMap implements the Map interface and extends the AbstractMap class in Java.
Fail-Fast Iterator
The iterator of HashMap is fail-fast, meaning any structural modification (insertion or removal) after
the creation of the iterator, will throw ConcurrentModificationException.
Creating a HashMap
map.put("Apple", 10);
map.put("Orange", 20);
map.put("Banana", 30);
import java.util.HashMap;
System.out.println(map);
}
}
Output:
Note: The order in which entries are printed here does not represent the order in which they were
inserted into the HashMap. This is because HashMap does not preserve the order of inserted entries.
Here is an example that demonstrates how a HashMap can store null keys and null values:
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
// Creating a HashMap object
HashMap<String, String> map = new HashMap<>();
In this program, a HashMap is created and then key-value pairs are added to it. Note the use of null
as a key and null as values. The HashMap can store one null key and multiple null values.
When you run this program, you might see output like the following:
Output:
Remember, the order of the elements in a HashMap is not guaranteed, so the order of the elements
in your output may be different.
To access elements in a HashMap, you can use the get() method. The get() method takes the key
import java.util.HashMap;
Output:
This output shows the values associated with the keys "Apple", "Orange", and "Banana" in the
HashMap.
Note: If you attempt to access a key that does not exist in the HashMap using the get method, it will
return null.
import java.util.HashMap;
This program creates a HashMap, adds some key-value pairs to it, and then removes some of these
pairs. The remove() method takes a key as an argument and removes the corresponding key-value
When you run this program, you should see the following output:
Output:
HashMap Size
We can get the size of the HashMap using the size() method.
import java.util.HashMap;
Output:
4. Using an Iterator
Let's create a program that demonstrates the different ways to iterate over a HashMap in Java:
import java.util.*;
// Using an `Iterator`:
System.out.println("Using an `Iterator`:");
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue())
}
System.out.println();
Output:
Using an `Iterator`:
Key = Apple, Value = Red
Key = Orange, Value = Orange
Key = Banana, Value = Yellow
objects implement the equals() and hashCode() methods appropriately. If they do not, then your
HashMap may not function as expected because it relies on these methods to store and retrieve
objects.
class Employee {
private String id;
private String name;
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
Employee employee = (Employee) obj;
return Objects.equals(id, employee.id) &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public String toString() {
return "Employee{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
import java.util.*;
employeeMap.put(e1, e1.getName());
employeeMap.put(e2, e2.getName());
Output:
Conclusion
Congratulations folks! In this article, you learned what is a HashMap, how to create a HashMap, how to
add new key-value pairs to a HashMap, how to remove keys from a HashMap, how to iterate over a
HashMap, and how to create and store user-defined objects as keys in a HashMap.
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this blog post, let's explore the differences between String and StringBuffer in Java with examples.
We also see the performance analysis with an example.
1. Immutability
String
The String class in Java is immutable, meaning once a String object is created, it cannot be
changed. Any modification to a String results in a new String object.
StringBuffer
On the other hand, StringBuffer is mutable, meaning that its content can be changed without
creating a new object.
2. Performance
Performance differences between String and StringBuffer in Java can be significant, especially when
you're dealing with a large number of string manipulations. Let's explore this with an example that
Consider a scenario where we need to concatenate a short string to an existing string repeatedly,
many times.
Using String
Using StringBuffer
Output:
StringBuffer being mutable, simply modifies the existing object. This leads to much better
performance.
Performance Analysis
When you run these above two examples, you will typically see a substantial difference in the
execution time:
So use String for short, simple, and infrequent string manipulations where immutability is desired.
Use StringBuffer when dealing with complex or frequent string manipulations, especially in a loop, to
gain significant performance benefits.
3. Synchronization
String
String Being Immutable, synchronization is not a concern with String objects. Multiple threads can
access a String without risk of concurrent modification, as any changes will result in new, separate
objects.
StringBuffer
All the methods in StringBuffer that change the content are synchronized. This means that only one
thread at a time can execute these methods on a given StringBuffer object. If multiple threads try to
modify the same StringBuffer object concurrently, synchronization ensures that only one can do so
4. Method Availability
String and StringBuffer both provide methods for various operations, but StringBuffer has additional
methods like append() , insert() , reverse() , etc., to modify the content.
The append method is used to add content to the end of the StringBuffer.
Conclusion
While String and StringBuffer might seem interchangeable, their distinct characteristics make them
suitable for different scenarios.
Use String when you need a fixed, immutable sequence of characters, and you are sure that the
content won't change frequently.
Use StringBuffer when you need to perform frequent modifications to the text content, especially in
a multithreaded environment.
Understanding these differences will help you choose the right class for your specific use case,
balancing performance, safety, and functionality.
How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Today we’re going to talk about one of those classic Java questions that every developer faces at
some point. What is the difference between String, StringBuilder, and StringBuffer? At first glance,
they all seem to just handle text. But under the hood, they behave very differently. And understanding
those differences can help you write cleaner, faster, and more efficient code.
A String in Java is immutable. That means once a String object is created, you can’t change its value.
Any time you try to modify it, Java actually creates a brand new object. So even something as simple
as adding a word to an existing string creates a completely new one in memory. This makes Strings
thread-safe by default, but also inefficient if you’re changing them a lot.
Now compare that with StringBuilder and StringBuffer. Both of these are mutable. You can change
their content as many times as you want — no new object is created. That makes them much better
for situations where strings are modified frequently, like building large text outputs or processing
input in loops.
Thread Safety
Next up — thread safety.
String, again, is naturally thread-safe because you can’t change it. Once it exists, nothing can modify
it. So it works fine in multi-threaded environments.
StringBuilder, on the other hand, is not thread-safe. It doesn’t have any internal synchronization. This
makes it faster, but also means that if you use it across multiple threads, you might run into problems.
StringBuffer solves that by being synchronized. Every method in StringBuffer is designed to be thread-
safe. So it’s safe to use even when multiple threads are accessing it at the same time. But all that
synchronization comes at a performance cost. So it’s a trade-off between safety and speed.
Performance
And that brings us to performance.
When it comes to frequent modifications — like adding or updating text inside a loop — String is the
slowest option. Because it keeps creating new objects again and again, your memory usage goes up,
StringBuilder is usually the fastest in single-threaded programs because it's lightweight and avoids
StringBuffer is just a little slower than StringBuilder because it has to handle synchronization for
thread safety. Still, it performs well in situations where you truly need safe access across multiple
threads.
Storage
String objects are stored in a special area of memory called the String pool. This helps Java reuse
string literals and optimize memory use.
StringBuilder and StringBuffer don’t use this pool. They’re regular objects stored on the heap. So
there's no built-in memory optimization for repeated values like there is with Strings.
This might not matter much for short programs, but it becomes very important when working on
applications that handle large datasets or run for long periods.
Concatenation
StringBuilder and StringBuffer both avoid that by offering an append method. This lets you keep
adding text to the same object without creating new ones. It’s fast, efficient, and more predictable —
Use String when the text doesn’t change, or when you're working with fixed values like configuration
keys, user roles, or simple labels. It’s simple, safe, and memory-efficient — as long as you’re not
constantly modifying it.
Use StringBuilder when you’re in a single-threaded environment and need to build or update strings
frequently. It gives you great performance without the overhead of thread safety.
Use StringBuffer when you’re in a multi-threaded application and different threads might update the
same string. You pay a little performance cost, but your data stays safe and consistent.
Wrap Up
So that’s it.
Strings are simple and safe — but slow to change. StringBuilder is fast and efficient — but only safe in
single-threaded code. And StringBuffer is safe across threads — but just a little heavier to use.
Knowing these differences helps you choose the right one depending on what your code needs to do.
How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this article, we will discuss important Java Exception Handling interview questions and answers.
An exception in Java is an event that occurs during the execution of a program, disrupting the normal
flow of instructions. Exceptions are objects that encapsulate information about an error condition that
has occurred within a method or block of code.
2. How does Exception Handling Work in Java?
Java exception handling works by using a combination of try, catch, finally, throw, and throws
keywords. When an exception occurs in a try block, it is thrown to the corresponding catch block. If
the exception is not caught, it propagates up the call stack. The finally block is executed regardless
of whether an exception was thrown or caught. The throw keyword is used to explicitly throw an
exception, while the throws keyword is used to declare that a method might throw one or more
exceptions.
try
catch
finally
throw
throws
throws: Used in a method signature to declare that the method might throw one or more
exceptions.
You can handle an exception using a try-catch block. Place the code that might throw an exception
inside the try block, and handle the exception in the catch block. Optionally, you can use a finally
Example:
try {
// Code that might throw an exception
} catch (ExceptionType e) {
// Code to handle the exception
} finally {
// Code that will always execute
}
6. Explain Java Exception Hierarchy?
The exception hierarchy in Java is as follows:
java.lang.Object
└── java.lang.Throwable
├── java.lang.Exception
│ ├── java.io.IOException
│ ├── java.sql.SQLException
│ └── java.lang.RuntimeException
│ ├── java.lang.NullPointerException
│ ├── java.lang.ArrayIndexOutOfBoundsException
│ └── java.lang.ArithmeticException
└── java.lang.Error
├── java.lang.OutOfMemoryError
├── java.lang.StackOverflowError
└── java.lang.VirtualMachineError
Example:
try {
// Code that might throw multiple exceptions
} catch (IOException | SQLException e) {
// Code to handle IOException or SQLException
} catch (Exception e) {
// Code to handle other exceptions
}
throws: Used in a method signature to declare that the method might throw one or more
exceptions. Example:
recoverable conditions.
Error: Represents serious issues that a reasonable application should not try to catch. They are
usually external to the application and indicate problems with the environment, such as the Java
Virtual Machine (JVM) running out of memory.
OutOfMemoryError is an error that occurs when the Java Virtual Machine (JVM) cannot allocate an
object because it is out of memory. The JVM throws this error to indicate that the heap memory has
been exhausted.
Chained exceptions allow you to relate one exception with another, forming a chain of exceptions.
This is useful when an exception occurs as a direct result of another exception. You can create a
chained exception by passing the original exception as a parameter to the constructor of the new
exception.
Example:
public class ChainedExceptionDemo {
public static void main(String[] args) {
try {
method1();
} catch (Exception e) {
e.printStackTrace();
}
}
exceptions are useful for specific error conditions relevant to your application.
Example:
finally: A block that is executed after the try-catch block, regardless of whether an exception
finalize: A method called by the garbage collector before an object is destroyed. It is used to
perform cleanup operations.
handles it by printing the stack trace to the standard error stream and terminating the program.
The try-with-resources statement is a try statement that declares one or more resources. A
resource is an object that must be closed after the program is finished with it. The try-with-
resources statement ensures that each resource is closed at the end of the statement.
Example:
A stack trace is a list of method calls that the application was in the middle of when an exception was
thrown. It provides information about the sequence of method calls that led to the exception, helping
developers debug the error by showing the exact point where the exception occurred.
maintainability of code.
Propagating Errors Up the Call Stack: Allows a method to catch and handle exceptions thrown
by methods it calls.
Grouping and Differentiating Error Types: Provides a way to handle different types of errors
in different ways.
checked exception, the functional interface method that the lambda expression implements must
declare that it throws the exception.
Example:
@FunctionalInterface
interface ThrowingConsumer<T> {
void accept(T t) throws Exception;
}
try {
consumer.accept(-1);
} catch (Exception e) {
System.out.println("Caught exception: " + e.getMessage());
}
}
}
The overridden method can only throw the same exceptions or subclasses of the exceptions
Example:
class Parent {
public void method() throws IOException {
// Method body
}
}
conditions.
Use Finally Block for Cleanup: Ensure that resources are properly closed using the finally
block or try-with-resources.
Log Exceptions: Log exceptions with sufficient details to help with debugging.
Throw Custom Exceptions for Business Logic Errors: Create custom exceptions for specific
them.
By following these best practices, you can write robust and maintainable code that handles exceptions
effectively, ensuring your application can recover gracefully from unexpected errors.
How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Object-Oriented Programming (OOP) is a programming paradigm that uses objects and classes to
structure software in a way that is both modular and reusable. Below are some common OOP
interview questions and their answers with additional explanations and real-world examples.
What is OOP?
Answer: Object-Oriented Programming (OOP) is a programming paradigm that uses objects and
classes to create models based on real-world entities. OOP promotes better software design, making
code more modular, reusable, and maintainable.
1. Abstraction
2. Encapsulation
3. Inheritance
4. Polymorphism
What is an Object?
Answer: An object is an instance of a class that contains attributes (data) and methods (functions) to
represent real-world entities or concepts. It encapsulates both state and behavior.
Real-world example: A car is an object. It has attributes like color, model, and speed, and methods
like drive() and brake().
What is Class?
Answer: A class is a blueprint or template for creating objects. It defines the attributes and behaviors
that the objects created from the class can have.
Real-world example: A car class can have attributes like color and model, and methods like drive()
and brake().
Answer:
1. Modularity: The source code for an object can be written and maintained independently of the
source code for other objects.
2. Reusability: Objects can be reused across programs.
3. Scalability: OOP allows for programs to grow in complexity while maintaining readability and
structure.
4. Maintainability: Changes to objects can be made independently without affecting other parts
of the system.
Answer: Procedural programming is based on functions, while OOP is based on objects and classes.
Procedural programming follows a top-down approach, whereas OOP follows a bottom-up approach.
Answer: Abstraction is the process of hiding the complex implementation details and showing only
the essential features of the object.
Real-world example: A car's dashboard. The driver interacts with the steering wheel, pedals, and
buttons without needing to understand the internal mechanics of the car.
Real-world example: A capsule in medicine. It encapsulates the drug inside it and only exposes the
outer shell to the user.
What is Polymorphism?
Answer: Polymorphism allows objects to be treated as instances of their parent class rather than their
actual class. It allows one interface to be used for a general class of actions.
Real-world example: A person who can act as a student, an employee, and a customer, depending
on the context.
1. Compile-time polymorphism (Method Overloading): Methods with the same name but
different parameters.
2. Runtime polymorphism (Method Overriding): Methods with the same name and parameters
Answer: Inheritance is the mechanism by which one class (child/subclass) can inherit the attributes
and methods of another class (parent/superclass).
Real-world example: A child inherits traits from their parents, such as eye color or hair color.
Answer:
Abstraction focuses on hiding the complex implementation details and showing only the
essential features.
Encapsulation involves bundling the data and methods that operate on the data into a single
unit and restricting access to some of the object's components.
Answer: The diamond problem occurs when two classes B and C inherit from A, and class D inherits
from both B and C. If A has a method, and B and C override it, D will have two inherited versions of
the method, leading to ambiguity.
Answer: Java does not support multiple inheritance to avoid the diamond problem and to keep the
language simple and easier to understand.
What is Static Binding and Dynamic Binding?
Answer:
Static Binding: The method call is resolved at compile time. Method overloading is an example
of static binding.
Dynamic Binding: The method call is resolved at runtime. Method overriding is an example of
dynamic binding.
What is Composition?
Answer: Composition is a design principle where a class is composed of one or more objects of other
classes rather than inheriting from them. It allows for more flexible designs and code reuse.
What is Aggregation?
Answer: Aggregation is a special form of association where one class is a part of another class but
What is an Association?
Answer: Association represents a relationship between two separate classes that are set up through
their objects. It can be one-to-one, one-to-many, many-to-one, or many-to-many.
What is Cohesion?
Answer: Cohesion refers to how closely related and focused the responsibilities of a single class are.
High cohesion within classes means that the class does a well-defined job.
What is Coupling?
Answer: Coupling refers to the degree of direct knowledge that one class has of another. Low
coupling means that classes are largely independent and changes in one class are less likely to affect
other classes.
Read more: Coupling in Java with Example
What is Delegation?
Answer: Delegation is a design pattern where an object handles a request by delegating to a second
object (the delegate).
Answer: SOLID is an acronym for five principles of object-oriented programming and design:
2. Open/Closed Principle
3. Liskov Substitution Principle
responsibility.
Answer: Software entities should be open for extension but closed for modification. This means that
a class should be extendable without modifying its source code.
Answer: Objects of a superclass should be replaceable with objects of a subclass without affecting
the correctness of the program.
depend on methods it does not use. Instead of one large interface, many smaller and more specific
Answer: High-level modules should not depend on low-level modules. Both should depend on
abstractions.
Class.forName("ClassName").newInstance();
inStream.readObject();
Read more: What Are All the Different Ways to Create an Object in Java?
Conclusion
Understanding OOP principles and concepts is crucial for software development in Java. These
interview questions cover a broad range of topics that are fundamental to object-oriented
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
In Java, an object is a fundamental entity in object-oriented programming (OOP). An object is an
instance of a class that encapsulates both state (attributes) and behavior (methods). Objects interact
with one another through methods, providing a way to model real-world entities and their
interactions.
What is an Object?
An object is an instance of a class that represents a real-world entity or concept. It is created based on
the blueprint provided by the class and has its own identity, state, and behavior.
Identity: Each object has a unique identity, which differentiates it from other objects.
Key Points:
Example:
This is the most common way to create an object. It invokes the constructor of the class.
2. Using Class.forName()
This method is used for dynamic class loading. It can throw a ClassNotFoundException.
This method creates a new object by copying the existing object's data. It requires the class to
This method creates an object from a serialized form (a byte stream). It requires the class to
implement the Serializable interface.
A factory method is a static method that returns an instance of a class. It encapsulates the object
creation process.
Diagram
Class: Car
+---------------------------+
| Car |
+---------------------------+
| - color: String |
| - model: String |
| - speed: int |
+---------------------------+
| + Car(color, model) |
| + start(): void |
| + accelerate(int): void |
| + brake(): void |
| + getColor(): String |
| + getModel(): String |
| + getSpeed(): int |
+---------------------------+
Object: myCar
+---------------------------+
| myCar |
+---------------------------+
| - color: "Red" |
| - model: "Toyota Corolla" |
| - speed: 0 |
+---------------------------+
| + start() |
| + accelerate(int) |
| + brake() |
| + getColor() |
| + getModel() |
| + getSpeed() |
+---------------------------+
Let's consider a real-world example: a Car class. We will define a Car class with attributes such as
color, model, and speed, and methods such as start(), accelerate(), and brake(). Then, we will
// Methods (behavior)
public void start() {
System.out.println(model + " is starting.");
speed = 10; // Starting speed
}
// Getters
public String getColor() {
return color;
}
Explanation:
The Car class has three attributes: color, model, and speed.
It has a constructor to initialize the color and model attributes, and the speed is initially
set to 0.
The class has three methods: start(), accelerate(int increment), and brake(),
The class also includes getter methods to access the attributes of the car.
In the Main class, we create an instance of the Car class using the new keyword.
We then call the methods start(), accelerate(int increment), and brake() on the
We access the attributes of the myCar object using the getter methods and print their
values.
Conclusion
In Java, objects are instances of classes that encapsulate state and behavior. They are fundamental to
object-oriented programming and provide a way to model real-world entities and their interactions.
By creating and using objects, we can design modular and reusable code that is easier to manage and
maintain.
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
In Java, a class is a blueprint or template that defines the structure and behavior (attributes and
methods) that the objects created from the class can have. A class encapsulates data for the object
and methods to manipulate that data. It serves as the fundamental building block in object-oriented
What is a Class?
A class in Java is a user-defined data type that serves as a blueprint for creating objects. It defines the
attributes (data fields) and behaviors (methods) that the objects created from the class can possess.
Key Points:
Syntax of a Class
The basic syntax to define a class in Java is as follows:
class ClassName {
// Attributes (data fields)
dataType attributeName;
// Constructor
public ClassName(parameters) {
// Initialize attributes
}
// Methods
returnType methodName(parameters) {
// Method body
}
}
color, model, and speed, and methods such as start(), accelerate(), and brake(). Then, we will
// Methods (behavior)
public void start() {
System.out.println(model + " is starting.");
speed = 10; // Starting speed
}
// Getters
public String getColor() {
return color;
}
Explanation:
The Car class has three attributes: color, model, and speed.
It has a constructor to initialize the color and model attributes, and the speed is initially
set to 0.
The class has three methods: start(), accelerate(int increment), and brake(),
The class also includes getter methods to access the attributes of the car.
In the Main class, we create an instance of the Car class using the new keyword.
We then call the methods start(), accelerate(int increment), and brake() on the
We access the attributes of the myCar object using the getter methods and print their
values.
Text-based Diagram
Class: Car
+---------------------------+
| Car |
+---------------------------+
| - color: String |
| - model: String |
| - speed: int |
+---------------------------+
| + Car(color, model) |
| + start(): void |
| + accelerate(int): void |
| + brake(): void |
| + getColor(): String |
| + getModel(): String |
| + getSpeed(): int |
+---------------------------+
Object: myCar
+---------------------------+
| myCar |
+---------------------------+
| - color: "Red" |
| - model: "Toyota Corolla" |
| - speed: 0 |
+---------------------------+
| + start() |
| + accelerate(int) |
| + brake() |
| + getColor() |
| + getModel() |
| + getSpeed() |
+---------------------------+
Conclusion
In Java, a class is a blueprint for creating objects. It defines the attributes and methods that the
objects created from the class can possess. By using classes and objects, we can model real-world
entities and their interactions, making our code more modular, reusable, and maintainable.
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Abstraction is one of the four fundamental principles of Object-Oriented Programming (OOP). It is the
concept of hiding the complex implementation details and showing only the essential features of the
object.
Table of Contents
1. What is Abstraction?
2. Benefits of Abstraction
3. Real-World Examples of Abstraction
4. Abstract Class
5. Interface
6. Abstract Class vs Interface
7. Example: Abstraction with Abstract Class
1. What is Abstraction?
Abstraction is the process of hiding the implementation details and showing only the functionality to
the user. It focuses on what the object does instead of how it does it. Abstraction allows you to
manage complexity by breaking down complex systems into simpler components.
2. Benefits of Abstraction
Reduces complexity: By hiding unnecessary details, abstraction makes the system easier to
Facilitates code reuse: Abstract components can be reused across different parts of the
application or even in different applications.
Consider a man driving a car. The man knows what each pedal and steering wheel does, but he
doesn't know how the car does these things internally. He doesn't know about the inner mechanisms
that empower these things. This is an example of abstraction.
Another real-world example is an ATM Machine. All users perform operations on the ATM machine
like cash withdrawal, money transfer, retrieving mini-statements, etc., but they do not know the
internal details about the ATM. This is another example of abstraction.
4. Abstract Class
An abstract class in Java is a class that cannot be instantiated and may contain abstract methods,
which are methods without a body. Subclasses of the abstract class are responsible for providing
implementations for these abstract methods.
Syntax:
// Regular method
void regularMethod() {
// Method body
}
}
5. Interface
An interface in Java is a reference type, similar to a class, that can contain only constants, method
signatures, default methods, static methods, and nested types. Interfaces cannot contain instance
fields or constructors.
Syntax:
interface InterfaceName {
// Abstract method (implicitly public and abstract)
void abstractMethod();
// Default method
default void defaultMethod() {
// Method body
}
// Static method
static void staticMethod() {
// Method body
}
}
Multiple
Does not support multiple inheritance Supports multiple inheritance
Inheritance
Access Modifiers Can have any access modifier Methods are implicitly public
// Abstract class
abstract class Animal {
// Abstract method
abstract void makeSound();
// Regular method
void eat() {
System.out.println("This animal is eating.");
}
}
// Subclass
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // Output: Bark
dog.eat(); // Output: This animal is eating.
}
}
Explanation:
Animal: Abstract class with an abstract method makeSound and a regular method eat.
Dog: Subclass of Animal that provides an implementation for the makeSound method.
Example:
// Interface
interface Animal {
void makeSound();
void eat();
}
@Override
public void eat() {
System.out.println("This animal is eating.");
}
}
// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // Output: Bark
dog.eat(); // Output: This animal is eating.
}
}
Explanation:
Dog: Class that implements the Animal interface and provides implementations for the
// Abstract class
abstract class Employee {
private String name;
private int employeeId;
// Abstract method
abstract void calculatePay();
}
// FullTimeEmployee class
class FullTimeEmployee extends Employee {
private double salary;
@Override
void calculatePay() {
System.out.println("FullTimeEmployee Pay: " + salary);
}
}
// Contractor class
class Contractor extends Employee {
private double hourlyRate;
private int hoursWorked;
@Override
void calculatePay() {
System.out.println("Contractor Pay: " + (hourlyRate * hoursWorked));
}
}
// Usage
public class Main {
public static void main(String[] args) {
Employee fullTimeEmployee = new FullTimeEmployee("Alice", 101, 60000);
fullTimeEmployee.calculatePay(); // Output: FullTimeEmployee Pay: 60000.0
Explanation:
Employee: Abstract class with common properties and an abstract method calculatePay.
calculatePay method.
method.
10. Conclusion
Abstraction in Java is a powerful concept that allows you to hide the implementation details and focus
on the functionality. It can be achieved using abstract classes and interfaces. Abstract classes are used
when you want to share code among several closely related classes, while interfaces are used to
define a contract that can be implemented by any class, regardless of its position in the class
hierarchy. Real-world examples like a man driving a car or using an ATM machine illustrate the
concept of abstraction. Understanding and applying abstraction helps to manage complexity, improve
Happy coding!
REPLY
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP). It
involves bundling the data (variables) and the methods (functions) that operate on the data into a
single unit, usually a class. Encapsulation also restricts direct access to some of an object's
Table of Contents
1. What is Encapsulation?
2. Benefits of Encapsulation
3. Encapsulation in Java
4. Access Modifiers
5. Real-World Examples of Encapsulation
6. Example: Encapsulation in Java
7. Conclusion
1. What is Encapsulation?
Encapsulation is the technique of making the fields in a class private and providing access to them via
public methods. It restricts direct access to certain components of an object and protects the integrity
of the data by controlling modifications.
2. Benefits of Encapsulation
Enhanced Security: Encapsulation helps protect data from unauthorized access and
modification by restricting access to an object's internal state.
Controlled Access: Encapsulation provides control over the data by exposing only the necessary
methods to interact with it, ensuring that the data is used in a controlled manner.
Flexibility and Reusability: Encapsulation allows changes to the implementation without
affecting the users of the class, making the code more flexible and reusable.
3. Encapsulation in Java
In Java, encapsulation is achieved by:
4. Access Modifiers
Java provides four types of access modifiers to control the visibility of class members:
default (no modifier): The member is accessible only within the same package.
protected: The member is accessible within the same package and subclasses.
public: The member is accessible from any other class.
5. Real-World Examples of Encapsulation
In a hospital management system, patient data should be encapsulated to ensure that it is accessed
and modified only through authorized methods, maintaining the integrity and confidentiality of the
information.
In a banking application, account details such as account balance should be encapsulated to prevent
unauthorized access and modification, ensuring the security and consistency of the data.
Explanation:
Private Fields: name and age are private fields, meaning they cannot be accessed directly from
Public Getter and Setter Methods: Methods getName, setName, getAge, and setAge are
Validation in Setter Method: The setAge method includes validation to ensure that the age is
not set to a negative value, demonstrating encapsulation's role in maintaining data integrity.
7. Conclusion
Encapsulation in Java is a powerful concept that helps to protect an object's internal state and
provides controlled access to it. By making fields private and exposing public methods to interact with
them, encapsulation ensures that data is used in a controlled and secure manner. This approach
improves maintainability, enhances security, and promotes code reusability and flexibility.
Understanding and applying encapsulation is essential for effective Java programming and building
robust, maintainable software.
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Polymorphism is one of the core concepts of Object-Oriented Programming (OOP). It allows methods
to do different things based on the object it is acting upon, even though they share the same name.
Polymorphism provides a way to perform a single action in different forms. In Java, polymorphism can
Table of Contents
1. What is Polymorphism?
2. Types of Polymorphism
3. Method Overloading
4. Method Overriding
5. Real-World Examples of Polymorphism
6. Example: Polymorphism with Method Overloading
1. What is Polymorphism?
Polymorphism means "many shapes" or "many forms." In Java, it refers to the ability of a single
method or class to take on multiple forms. This is achieved through method overloading (compile-
time polymorphism) and method overriding (runtime polymorphism).
2. Types of Polymorphism
3. Method Overloading
Method overloading occurs when a class has multiple methods with the same name but different
parameter lists (different types or numbers of parameters).
Example:
4. Method Overriding
Method overriding occurs when a subclass provides a specific implementation of a method that is
already defined in its superclass.
Example:
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
Suppose you are in a classroom, you behave like a student. When you are in the market, you behave
like a customer. When you are at home, you behave like a son or daughter. Here, one person exhibits
different behaviors in different contexts.
Example 2: Payment Processing System
In a payment processing system, different payment methods such as credit card, debit card, and
Example:
Printer: Class with overloaded print methods to handle different types of input.
Example:
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
Explanation:
Main method: Demonstrates runtime polymorphism by calling the overridden methods on Dog
Class Diagram
Code Example:
Payment Interface:
interface Payment {
void pay();
}
CashPayment Class:
CreditPayment Class:
Client Class:
Explanation:
CashPayment and CreditPayment: Classes implementing the Payment interface and providing
Polymorphism: Client class demonstrating polymorphism by using the Payment interface to call
9. Conclusion
Polymorphism in Java is a powerful concept that allows methods to perform different tasks based on
the object they are acting upon. It enhances flexibility and maintainability in code by allowing a single
method or class to take on multiple forms. Method overloading and method overriding are two ways
to achieve polymorphism in Java. Real-world examples like different behaviors of a person in different
contexts and various payment processing methods further illustrate the usefulness of polymorphism.
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Inheritance is one of the four fundamental principles of Object-Oriented Programming (OOP). It
allows a class to inherit properties and behaviors (fields and methods) from another class. The class
that inherits the properties is called the subclass (or derived class), and the class from which
properties are inherited is called the superclass (or base class). Inheritance promotes code reusability
and establishes a natural hierarchical relationship between classes.
Table of Contents
1. What is Inheritance?
2. Benefits of Inheritance
3. Types of Inheritance
4. Single Inheritance
5. Multilevel Inheritance
6. Hierarchical Inheritance
7. Real-World Examples of Inheritance
8. Example: Single Inheritance
11. Conclusion
1. What is Inheritance?
Inheritance is a mechanism wherein a new class is derived from an existing class. The derived class
(child class) inherits the attributes and methods of the base class (parent class), allowing code reuse
and the creation of a natural hierarchy.
2. Benefits of Inheritance
Code Reusability: Inheritance allows a class to reuse the fields and methods of another class.
Method Overriding: Subclasses can provide specific implementations for methods that are
3. Types of Inheritance
multiple inheritance directly to avoid complexity and ambiguity. However, it can be achieved
using interfaces.
4. Single Inheritance
In a single inheritance, a class inherits from one superclass.
Example:
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
5. Multilevel Inheritance
Example:
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
6. Hierarchical Inheritance
In hierarchical inheritance, multiple classes inherit from a single superclass.
Example:
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
In Multiple inheritances, one class can have more than one superclass and inherit features from all
parent classes.
Please note that Java does not support multiple inheritances with classes. In Java, we can achieve
Consider a vehicle hierarchy where Vehicle is the base class. Car and Bike can be derived classes
In an employee management system, Employee can be the base class. Manager and Developer can
The Java library extensively uses inheritance. The figure below shows an inheritance hierarchy
from java.lang library. The Number class abstracts various numerical (reference) types such
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
Explanation:
Dog: Subclass that inherits from Animal and adds a method bark.
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
Explanation:
Dog: Subclass that inherits from Animal and adds a method bark.
Puppy: Subclass that inherits from Dog and adds a method weep.
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
Explanation:
Dog and Cat: Subclasses that inherit from Animal and add methods bark and meow,
respectively.
11. Conclusion
Inheritance in Java is a powerful concept that promotes code reusability and establishes a natural
hierarchical relationship between classes. By using inheritance, you can create a base class with
common properties and methods and then create derived classes that inherit these properties and
methods while adding specific features. Understanding and applying inheritance helps to build a
structured and organized codebase, making it easier to maintain and extend.
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Composition is a fundamental concept in Object-Oriented Programming (OOP) that allows a class to
contain objects of other classes to achieve code reuse and establish a has-a relationship. Unlike
inheritance, which represents an is-a relationship, composition models a relationship where one
Table of Contents
1. What is Composition?
2. Benefits of Composition
3. Composition vs Inheritance
1. What is Composition?
Composition is a design principle where a class contains references to one or more objects of other
classes. This allows the class to use the functionality of the composed objects and delegate tasks to
them. Composition is often preferred over inheritance because it promotes greater flexibility and
modularity in the design.
there is no chance of an existing dependent object; hence, these are strongly associated, and this
relationship is called composition.
2. Benefits of Composition
Reusability: Composition allows for code reuse by including instances of other classes.
Flexibility: Changes to composed objects can be made independently of the class that uses
them.
Encapsulation: Composition encapsulates the functionality of composed objects, reducing
dependencies.
Better Modeling: Composition better represents real-world relationships where objects are
made up of other objects.
3. Composition vs Inheritance
Flexibility More flexible, allows runtime behavior changesLess flexible, fixed at compile time
Coupling Loosely coupled Tightly coupled
Reusability Promotes high reusability Limited reusability
EncapsulationBetter encapsulation Exposes implementation details
Example:
Let's create a Library class that contains multiple Book objects using composition.
import java.util.ArrayList;
import java.util.List;
public class Library {
private List<Book> books;
public Library() {
this.books = new ArrayList<>();
}
library.showBooks();
// Output:
// Title: 1984, Author: George Orwell
// Title: To Kill a Mockingbird, Author: Harper Lee
}
}
Explanation:
Library: A class that uses composition to include multiple Book objects. The Library class
manages a list of books and provides methods to add and display books.
Main: A class to demonstrate the use of composition by creating Book objects and adding them
to the Library.
A Car class can use composition to include an Engine object. The Car class can delegate the starting
class Engine {
public void start() {
System.out.println("Engine started.");
}
class Car {
private Engine engine;
public Car() {
this.engine = new Engine();
}
A Computer class can use composition to include CPU, RAM, and HardDrive objects. The Computer
class CPU {
public void process() {
System.out.println("CPU processing...");
}
}
class RAM {
public void load() {
System.out.println("RAM loading...");
}
}
class HardDrive {
public void readData() {
System.out.println("HardDrive reading data...");
}
}
class Computer {
private CPU cpu;
private RAM ram;
private HardDrive hardDrive;
public Computer() {
this.cpu = new CPU();
this.ram = new RAM();
this.hardDrive = new HardDrive();
}
6. Conclusion
Composition in Java is a powerful concept that promotes code reuse and modularity by allowing a
class to contain objects of other classes. It models a has-a relationship, which is more flexible and
encapsulated than inheritance. By using composition, developers can build complex systems that are
easy to maintain and extend. Understanding and applying composition effectively is essential for
designing robust and scalable Java applications.
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Aggregation is a type of association that represents a "has-a" relationship with a whole-part hierarchy.
In aggregation, the child object can exist independently of the parent object, implying a weak
relationship between the parent and child. Aggregation allows one class to contain another class
Table of Contents
1. What is Aggregation?
2. Benefits of Aggregation
3. Aggregation vs Composition
1. What is Aggregation?
Aggregation is a special type of association that represents a whole-part relationship where the child
(part) can exist independently of the parent (whole). It is used to model relationships where the
contained objects are not strongly dependent on the lifecycle of the container object.
2. Benefits of Aggregation
Reusability: Aggregated objects can be reused across different parts of the application.
Flexibility: Aggregated objects can exist independently of the parent object, providing flexibility
in design.
enhancing maintainability.
3. Aggregation vs Composition
Example:
Let's create a Department class that aggregates multiple Employee objects using aggregation.
import java.util.ArrayList;
import java.util.List;
Explanation:
Department: A class that uses aggregation to include multiple Employee objects. The
Main: A class to demonstrate the use of aggregation by creating Employee objects and adding
A School class can aggregate multiple Student objects. The Student objects can exist independently
of the School.
Student Class
School Class
import java.util.ArrayList;
import java.util.List;
A Library class can aggregate multiple Book objects. The Book objects can exist independently of
the Library.
Book Class
Library Class
import java.util.ArrayList;
import java.util.List;
6. Conclusion
Aggregation in Java is a powerful concept that allows classes to model a whole-part relationship
where the parts can exist independently of the whole. This promotes modularity, reusability, and
maintainability in the design of software systems. By understanding and using aggregation correctly,
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Association is a relationship between two classes that establishes a connection between their objects.
It defines how objects of one class are connected to objects of another class. Association can be of
different types: unidirectional, bidirectional, one-to-one, one-to-many, many-to-one, and many-to-
Table of Contents
1. What is Association?
2. Types of Association
3. Benefits of Association
7. Conclusion
1. What is Association?
Association is a structural relationship that represents how objects of one class are related to objects
of another class. Unlike inheritance, which defines an is-a relationship, association defines a has-a
relationship. It indicates that one object uses or interacts with another object.
2. Types of Association
Unidirectional Association: One class knows about the other class, but not vice versa.
Bidirectional Association: Both classes know about each other.
One-to-One Association: One object of a class is associated with one object of another class.
One-to-Many Association: One object of a class is associated with many objects of another
class.
Many-to-One Association: Many objects of a class are associated with one object of another
class.
Many-to-Many Association: Many objects of a class are associated with many objects of
another class.
3. Benefits of Association
Reusability: Promotes code reuse by establishing relationships between classes.
Flexibility: Allows classes to interact and collaborate without being tightly coupled.
Modularity: Helps in creating modular designs by defining clear relationships between classes.
Improved Design: Facilitates better design by modeling real-world relationships.
Example:
Let's create a Library class that is associated with multiple Book objects using unidirectional
association.
import java.util.ArrayList;
import java.util.List;
public Library() {
this.books = new ArrayList<>();
}
library.showBooks();
// Output:
// Title: 1984, Author: George Orwell
// Title: To Kill a Mockingbird, Author: Harper Lee
}
}
Explanation:
Library: A class that uses unidirectional association to include multiple Book objects. The
Main: A class to demonstrate the use of unidirectional association by creating Book objects and
Example:
Let's create a Person class and an Address class with a bidirectional association.
person.setAddress(address);
Explanation:
Main: A class to demonstrate bidirectional association by creating Person and Address objects
In a university system, a University class can have multiple Student objects. This can be modeled
University Class
import java.util.ArrayList;
import java.util.List;
Student Class
In a company, a Department can have multiple Employee objects, and an Employee can belong to a
single Department.
Department Class
import java.util.ArrayList;
import java.util.List;
Employee Class
7. Conclusion
Association in Java is a powerful concept that allows modeling relationships between classes. By
understanding and using association correctly, developers can create flexible, modular, and
maintainable systems. Association can be unidirectional or bidirectional and can represent one-to-
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Cohesion is a measure of how closely related and focused the responsibilities of a single module or
class are. In Object-Oriented Programming (OOP), a highly cohesive class is one that performs a single
task or a group of related tasks, making the class easier to maintain and understand. High cohesion
often correlates with low coupling, leading to a more modular and maintainable codebase.
Table of Contents
1. What is Cohesion?
2. Benefits of High Cohesion
3. Types of Cohesion
1. What is Cohesion?
Cohesion refers to the degree to which the elements inside a module or class belong together. It
describes how well the methods and properties of a class are related to each other. High cohesion
means that a class is responsible for only one thing or a group of related things, while low cohesion
means that a class has many unrelated responsibilities.
Improved Maintainability: High cohesion makes classes easier to maintain and update
because each class has a clear and focused responsibility.
Enhanced Readability: Classes with high cohesion are easier to understand and reason about.
Increased Reusability: Highly cohesive classes are more likely to be reused in different parts of
an application or in different projects.
Simplified Testing: Testing is easier for highly cohesive classes since they perform a single task
or a group of related tasks.
3. Types of Cohesion
1. Low cohesion
2. High Cohesion
In a class with low cohesion, responsibilities are scattered and unrelated, making the class difficult to
maintain and understand.
In a class with high cohesion, responsibilities are related and focused, making the class easier to
Employee Class
SalaryCalculator Class
public class SalaryCalculator {
public double calculateAnnualSalary(Employee employee) {
return employee.getSalary() * 12;
}
}
ReportPrinter Class
EmailService Class
Explanation
LowCohesionClass: Contains methods that perform unrelated tasks such as calculating salary,
printing reports, and sending emails. This makes the class difficult to understand and maintain.
High Cohesion Example: Responsibilities are divided into separate classes: Employee,
In a library system, you can have classes like Book, LibraryMember, LibraryCatalog, and
LoanService. Each class has a specific responsibility, such as managing book details, handling
member information, maintaining the catalog, and managing book loans, respectively.
Book Class
LibraryMember Class
LibraryCatalog Class
LoanService Class
public class LoanService {
public void loanBook(LibraryMember member, Book book) {
// Logic to loan a book to a member
}
}
In an e-commerce system, you can have classes like Product, ShoppingCart, Order, and
Product Class
ShoppingCart Class
Order Class
public class Order {
private List<Product> products;
PaymentProcessor Class
6. Conclusion
Cohesion is a critical concept in software design that affects the maintainability, readability, and
reusability of a system. High cohesion within classes leads to a more modular and understandable
codebase, making it easier to manage and extend. By focusing on creating highly cohesive classes,
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Coupling refers to the degree of direct knowledge that one class has about another class. In software
design, coupling is an essential concept that impacts the modularity and maintainability of a system.
Lower coupling between classes usually leads to a system that is easier to maintain and extend, while
higher coupling can make the system more rigid and harder to manage.
Table of Contents
1. What is Coupling?
2. Types of Coupling
3. Benefits of Low Coupling
1. What is Coupling?
Coupling describes the degree of dependency between classes or modules. It indicates how closely
connected different classes or modules are, and how much they rely on each other. There are two
Tight Coupling: High dependency between classes. Changes in one class often require changes
2. Types of Coupling
Tight Coupling
Tight coupling occurs when a class is highly dependent on the specifics of another class. This often
happens when one class creates an instance of another class and directly accesses its methods and
fields.
Loose Coupling
Loose coupling occurs when classes are less dependent on the specifics of other classes. This can be
achieved by using interfaces, abstract classes, or dependency injection, allowing classes to interact
without knowing the implementation details of each other.
Improved Maintainability: Changes in one class have minimal impact on other classes.
Enhanced Reusability: Loosely coupled classes can be reused in different contexts.
Better Testability: Independent classes are easier to test in isolation.
In a tightly coupled system, changes in one class can significantly affect other classes.
Example:
class Engine {
public void start() {
System.out.println("Engine started.");
}
}
class Car {
private Engine engine;
public Car() {
this.engine = new Engine(); // Direct instantiation
}
Explanation:
The Car class directly creates an instance of Engine and calls its start method.
Any change in the Engine class, such as a change in the method signature, would require
interface Engine {
void start();
}
class Car {
private Engine engine;
The Car class can work with any implementation of the Engine interface, promoting loose
coupling.
6. Conclusion
Coupling is a critical concept in software design that affects the modularity, maintainability, and
flexibility of a system. Tight coupling leads to a system where classes are highly dependent on each
other, making it hard to maintain and extend. Loose coupling, on the other hand, reduces
dependencies, making the system easier to manage and adapt to changes. By using interfaces,
abstract classes, and dependency injection, developers can achieve loose coupling and build more
robust and flexible systems.
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Delegation is an object-oriented design pattern in which an object passes a task to another object
instead of performing it itself. This concept allows for polymorphism and code reuse, leading to more
maintainable and flexible code. Delegation helps maintain a loosely coupled system, which is easier to
Table of Contents
1. What is Delegation?
2. Benefits of Delegation
3. Example 1: Ticket Booking System
1. What is Delegation?
2. Benefits of Delegation
Enhanced Flexibility: Changes to the delegated class do not affect the delegator class.
Improved Maintainability: Easier to maintain and extend as the code is modular.
Step-by-Step Implementation
interface TravelBooking {
void bookTicket();
}
The TravelBooking interface defines a single method bookTicket(), which will be implemented by
The AirBooking class implements the TravelBooking interface and provides a specific
@Override
public void bookTicket() {
travelBooking.bookTicket();
}
}
The TicketBookingByAgent class also implements the TravelBooking interface but delegates the
actual booking task to another TravelBooking object. The delegation is achieved via the constructor
which accepts a TravelBooking object. The bookTicket() method calls the bookTicket() method
delegates the call to the appropriate booking class (either TrainBooking or AirBooking).
In this example, the TicketBookingByAgent class does not handle the actual ticket booking process.
Instead, it delegates this responsibility to the classes that implement the TravelBooking interface
Step-by-Step Implementation
The Printer interface defines a single method print(), which will be implemented by various
printer classes.
The CanonPrinter class implements the Printer interface and provides a specific implementation
The EpsonPrinter class implements the Printer interface and provides a specific implementation
The HpPrinter class implements the Printer interface and provides a specific implementation for
printing a message.
@Override
public void print(String message) {
printer.print(message);
}
}
The PrinterController class also implements the Printer interface but delegates the actual
printing task to another Printer object. The delegation is achieved via the constructor which accepts
a Printer object. The print() method calls the print() method of the delegated Printer object.
In this example, the PrinterController class does not handle the actual printing process. Instead, it
delegates this responsibility to the classes that implement the Printer interface (CanonPrinter,
EpsonPrinter, and HpPrinter). This allows PrinterController to dynamically choose which
5. Conclusion
Delegation is a powerful design pattern that allows objects to delegate tasks to other objects,
promoting code reuse and modularity. By using delegation, you can create more flexible and
maintainable systems. In this article, we explored two examples: a ticket booking system and a printer
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Single Responsibility Principle (SRP) is one of the five SOLID principles of object-oriented design.
SRP states that a class should have only one reason to change, meaning it should have only one
responsibility or job. This principle helps in creating more maintainable and understandable code by
Table of Contents
1. What is the Single Responsibility Principle?
2. Benefits of the Single Responsibility Principle
3. Example: Violation of SRP
The Single Responsibility Principle (SRP) asserts that a class should only have one reason to change,
implying it should have only one responsibility or purpose. This principle helps in building classes that
are easier to understand, test, and maintain by ensuring each class is focused on a single aspect of the
application.
Improved Maintainability: Changes to a single responsibility affect only one class, making the
codebase easier to maintain.
Enhanced Readability: Classes with a single responsibility are easier to read and understand.
Increased Reusability: Classes focused on a single responsibility can be reused in different
contexts without modification.
Simplified Testing: Testing is more straightforward for classes with a single responsibility.
In this example, a User class is responsible for both user management and email sending, violating
SRP.
Issues:
The User class is responsible for both saving the user and sending emails.
Any change in email sending logic will require changes in the User class, violating SRP.
5. Real-World Example
Book Class
Member Class
LoanService Class
Explanation:
Conclusion
The Single Responsibility Principle (SRP) is a fundamental concept in object-oriented design that
promotes high cohesion and low coupling by ensuring that each class has only one responsibility or
reason to change. By adhering to SRP, developers can create more maintainable, understandable, and
flexible code. This principle is critical for building robust and scalable applications.
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Open/Closed Principle (OCP) is one of the five SOLID principles of object-oriented design. It
states that software entities (such as classes, modules, and functions) should be open for extension
but closed for modification. This means that the behavior of a module can be extended without
Table of Contents
1. What is the Open/Closed Principle?
2. Benefits of the Open/Closed Principle
3. Example: Violation of OCP
The Open/Closed Principle (OCP) asserts that a class should be open for extension but closed for
modification. This means you should be able to add new functionality to a class by extending it,
functionality.
Improved Flexibility: New features can be added without modifying existing code.
Increased Reusability: Classes that adhere to OCP are more likely to be reusable in different
contexts.
In this example, we'll create a Shape class and a AreaCalculator class that violates OCP by requiring
Example:
class Circle {
private double radius;
class Rectangle {
private double width;
private double height;
class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
return Math.PI * circle.getRadius() * circle.getRadius();
} else if (shape instanceof Rectangle) {
Rectangle rectangle = (Rectangle) shape;
return rectangle.getWidth() * rectangle.getHeight();
}
return 0;
}
}
Issues:
The AreaCalculator class must be modified to support new shapes, violating OCP.
Adding new shapes requires changes to the calculateArea method, making the code less
maintainable.
To adhere to OCP, we can use polymorphism and interfaces to allow the AreaCalculator to work
Example:
interface Shape {
double calculateArea();
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
@Override
public double calculateArea() {
return width * height;
}
}
class AreaCalculator {
public double calculateArea(Shape shape) {
return shape.calculateArea();
}
}
Explanation:
Circle and Rectangle: Implementations of the Shape interface that provide specific area
calculations.
AreaCalculator: A class that calculates the area of any Shape without needing modification.
Main: Demonstrates the use of OCP by adding new shapes without changing the
AreaCalculator class.
5. Real-World Example
Consider a notification system where different types of notifications (e.g., email, SMS) need to be sent.
Step 1: Define the Notification Interface
interface Notification {
void send(String message);
}
class NotificationService {
private List<Notification> notifications;
public NotificationService() {
this.notifications = new ArrayList<>();
}
service.sendAll("Hello, World!");
// Output:
// Sending email: Hello, World!
// Sending SMS: Hello, World!
}
}
Explanation:
types of notifications.
Main: Demonstrates the use of OCP by adding new notification types without changing the
NotificationService class.
6. Conclusion
The Open/Closed Principle (OCP) is a fundamental concept in object-oriented design that promotes
the extension of software entities without modifying their source code. By adhering to OCP,
developers can create more maintainable, flexible, and reusable code. Understanding and applying
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Liskov Substitution Principle (LSP) is one of the five SOLID principles of object-oriented design. It
states that objects of a superclass should be replaceable with objects of a subclass without affecting
the correctness of the program. This principle ensures that a subclass can stand in for its superclass
without altering the desirable properties of the program (correctness, task performed, etc.).
Table of Contents
1. What is the Liskov Substitution Principle?
2. Benefits of the Liskov Substitution Principle
3. Example: Violation of LSP
The Liskov Substitution Principle (LSP) asserts that if S is a subtype of T, then objects of type T may be
replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without
altering any of the desirable properties of the program. This means that subclasses should extend the
classes.
Improved Maintainability: Reduces the risk of introducing bugs when extending classes.
Increased Flexibility: Allows for more flexible and modular code design.
Example:
class Bird {
public void fly() {
System.out.println("Bird is flying");
}
}
Issues:
The Penguin class violates LSP because it changes the behavior of the fly method by throwing
an exception.
This breaks the expected behavior of the Bird class and can lead to runtime errors.
To adhere to LSP, we can introduce a more appropriate class hierarchy where flying ability is modeled
differently.
Example:
Explanation:
Bird: An abstract class that provides a common interface for all bird types.
Sparrow and Penguin: Subclasses that extend Bird without changing its behavior.
Main: Demonstrates the use of LSP by allowing subclasses to be used interchangeably with the
parent class.
5. Real-World Example
Consider a payment processing system where different payment methods (e.g., credit card, PayPal)
should adhere to the Liskov Substitution Principle.
Explanation:
Payment: An abstract class that provides a common interface for all payment methods.
CreditCardPayment and PayPalPayment: Subclasses that extend Payment without changing its
behavior.
Main: Demonstrates the use of LSP by allowing different payment methods to be used
interchangeably.
6. Conclusion
The Liskov Substitution Principle (LSP) is a fundamental concept in object-oriented design that
ensures subclasses can replace their parent classes without altering the correctness of the program.
By adhering to LSP, developers can create more flexible, reusable, and maintainable code.
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Interface Segregation Principle (ISP) is one of the five SOLID principles of object-oriented design.
ISP states that no client should be forced to depend on methods they do not use. This principle
promotes the creation of smaller, more specific interfaces instead of larger, general-purpose
interfaces, ensuring that classes implement only the methods that are relevant to them.
Table of Contents
1. What is the Interface Segregation Principle?
2. Benefits of the Interface Segregation Principle
3. Example: Violation of ISP
The Interface Segregation Principle (ISP) asserts that clients should not be forced to depend on
interfaces they do not use. In other words, an interface should not include methods that are not
relevant to the implementing class. Instead, interfaces should be small and focused on specific sets of
behaviors.
Enhanced Flexibility: Changes in one part of the system are less likely to affect other parts.
Increased Reusability: Classes can implement only the interfaces they need, promoting reuse.
In this example, we'll create an interface Worker that violates ISP by including methods not relevant to
Example:
interface Worker {
void work();
void eat();
}
@Override
public void eat() {
System.out.println("Developer is eating.");
}
}
@Override
public void eat() {
// Robot does not eat
throw new UnsupportedOperationException("Robot does not eat.");
}
}
Issues:
The Robot class is forced to implement the eat method, which is not applicable to it.
This leads to a violation of ISP as the Robot class depends on a method it does not use.
To adhere to ISP, we can split the Worker interface into more specific interfaces.
Example:
interface Workable {
void work();
}
interface Eatable {
void eat();
}
@Override
public void eat() {
System.out.println("Developer is eating.");
}
}
Main: Demonstrates the use of ISP by allowing classes to implement only the methods they
need.
5. Real-World Example
Consider a document printing system where different devices have different capabilities.
interface Printable {
void print();
}
interface Scannable {
void scan();
}
interface Faxable {
void fax();
}
@Override
public void scan() {
System.out.println("Scanning document.");
}
@Override
public void fax() {
System.out.println("Faxing document.");
}
}
Explanation:
Main: Demonstrates the use of ISP by allowing devices to implement only the capabilities they
support.
6. Conclusion
The Interface Segregation Principle (ISP) is a fundamental concept in object-oriented design that
promotes the creation of small, specific interfaces rather than large, general-purpose ones. By
adhering to ISP, developers can create more flexible, maintainable, and reusable code. Understanding
and applying ISP is essential for building robust and scalable Java applications.
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Dependency Inversion Principle (DIP) is one of the five SOLID principles of object-oriented design.
It states that high-level modules should not depend on low-level modules. Both should depend on
abstractions. Furthermore, abstractions should not depend on details. Details should depend on
Table of Contents
1. What is the Dependency Inversion Principle?
High-level modules should not depend on low-level modules. Both should depend on
abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
This principle ensures that the system's high-level policy does not depend on the low-level details but
rather on an abstraction.
In this example, we'll create a LightBulb class and a Switch class that violates DIP by depending
directly on LightBulb.
Example:
class LightBulb {
public void turnOn() {
System.out.println("LightBulb is turned on");
}
Issues:
The Switch class depends directly on the LightBulb class, creating tight coupling.
Any change in the LightBulb class requires changes in the Switch class.
To adhere to DIP, we can introduce an abstraction for the LightBulb class and make the Switch class
Example:
interface Switchable {
void turnOn();
void turnOff();
}
@Override
public void turnOff() {
System.out.println("LightBulb is turned off");
}
}
class Switch {
private Switchable switchable;
Explanation:
Switch: A class that depends on the Switchable interface rather than the LightBulb class.
Main: Demonstrates the use of DIP by creating a Switch object that depends on the
Switchable interface.
5. Real-World Example
Consider a payment processing system where different payment methods (e.g., credit card, PayPal)
need to be processed.
interface PaymentProcessor {
void processPayment(double amount);
}
class PaymentService {
private PaymentProcessor paymentProcessor;
Explanation:
Main: Demonstrates the use of DIP by creating a PaymentService object that depends on the
PaymentProcessor interface.
6. Conclusion
The Dependency Inversion Principle (DIP) is a fundamental concept in object-oriented design that
promotes loose coupling between high-level and low-level modules by depending on abstractions
rather than concrete implementations. By adhering to DIP, developers can create more maintainable,
flexible, and testable code. Understanding and applying DIP is essential for building robust and
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
There are several ways to create objects in Java. In this article, we will discuss five different ways to
create objects in Java. We will understand each method with an example and its output.
Example:
public class Car {
private String color;
private String model;
Output:
2. Using Class.forName()
This method is used for dynamic class loading. It can throw a ClassNotFoundException.
Example:
public Car() {
this.color = "Blue";
this.model = "Honda Civic";
}
Output:
3. Using clone()
This method creates a new object by copying the existing object's data. It requires the class to
implement the Cloneable interface.
Example:
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
Output:
This method creates an object from a serialized form (a byte stream). It requires the class to
implement the Serializable interface.
Example:
import java.io.*;
deserializedCar.displayInfo();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Output:
creation process.
Example:
Output:
Conclusion
These are five different ways to create objects in Java. Each method has its use cases and advantages,
and understanding these methods is crucial for effective Java programming.
How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
In Java, an object is a fundamental entity in object-oriented programming (OOP). An object is an
instance of a class that encapsulates both state (attributes) and behavior (methods). Objects interact
with one another through methods, providing a way to model real-world entities and their
interactions.
What is an Object?
An object is an instance of a class that represents a real-world entity or concept. It is created based on
the blueprint provided by the class and has its own identity, state, and behavior.
Identity: Each object has a unique identity, which differentiates it from other objects.
Key Points:
Example:
This is the most common way to create an object. It invokes the constructor of the class.
2. Using Class.forName()
This method is used for dynamic class loading. It can throw a ClassNotFoundException.
This method creates a new object by copying the existing object's data. It requires the class to
This method creates an object from a serialized form (a byte stream). It requires the class to
implement the Serializable interface.
A factory method is a static method that returns an instance of a class. It encapsulates the object
creation process.
Diagram
Class: Car
+---------------------------+
| Car |
+---------------------------+
| - color: String |
| - model: String |
| - speed: int |
+---------------------------+
| + Car(color, model) |
| + start(): void |
| + accelerate(int): void |
| + brake(): void |
| + getColor(): String |
| + getModel(): String |
| + getSpeed(): int |
+---------------------------+
Object: myCar
+---------------------------+
| myCar |
+---------------------------+
| - color: "Red" |
| - model: "Toyota Corolla" |
| - speed: 0 |
+---------------------------+
| + start() |
| + accelerate(int) |
| + brake() |
| + getColor() |
| + getModel() |
| + getSpeed() |
+---------------------------+
Let's consider a real-world example: a Car class. We will define a Car class with attributes such as
color, model, and speed, and methods such as start(), accelerate(), and brake(). Then, we will
// Methods (behavior)
public void start() {
System.out.println(model + " is starting.");
speed = 10; // Starting speed
}
// Getters
public String getColor() {
return color;
}
Explanation:
The Car class has three attributes: color, model, and speed.
It has a constructor to initialize the color and model attributes, and the speed is initially
set to 0.
The class has three methods: start(), accelerate(int increment), and brake(),
The class also includes getter methods to access the attributes of the car.
In the Main class, we create an instance of the Car class using the new keyword.
We then call the methods start(), accelerate(int increment), and brake() on the
We access the attributes of the myCar object using the getter methods and print their
values.
Conclusion
In Java, objects are instances of classes that encapsulate state and behavior. They are fundamental to
object-oriented programming and provide a way to model real-world entities and their interactions.
By creating and using objects, we can design modular and reusable code that is easier to manage and
maintain.
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
In Java, a class is a blueprint or template that defines the structure and behavior (attributes and
methods) that the objects created from the class can have. A class encapsulates data for the object
and methods to manipulate that data. It serves as the fundamental building block in object-oriented
What is a Class?
A class in Java is a user-defined data type that serves as a blueprint for creating objects. It defines the
attributes (data fields) and behaviors (methods) that the objects created from the class can possess.
Key Points:
Syntax of a Class
The basic syntax to define a class in Java is as follows:
class ClassName {
// Attributes (data fields)
dataType attributeName;
// Constructor
public ClassName(parameters) {
// Initialize attributes
}
// Methods
returnType methodName(parameters) {
// Method body
}
}
color, model, and speed, and methods such as start(), accelerate(), and brake(). Then, we will
// Methods (behavior)
public void start() {
System.out.println(model + " is starting.");
speed = 10; // Starting speed
}
// Getters
public String getColor() {
return color;
}
Explanation:
The Car class has three attributes: color, model, and speed.
It has a constructor to initialize the color and model attributes, and the speed is initially
set to 0.
The class has three methods: start(), accelerate(int increment), and brake(),
The class also includes getter methods to access the attributes of the car.
In the Main class, we create an instance of the Car class using the new keyword.
We then call the methods start(), accelerate(int increment), and brake() on the
We access the attributes of the myCar object using the getter methods and print their
values.
Text-based Diagram
Class: Car
+---------------------------+
| Car |
+---------------------------+
| - color: String |
| - model: String |
| - speed: int |
+---------------------------+
| + Car(color, model) |
| + start(): void |
| + accelerate(int): void |
| + brake(): void |
| + getColor(): String |
| + getModel(): String |
| + getSpeed(): int |
+---------------------------+
Object: myCar
+---------------------------+
| myCar |
+---------------------------+
| - color: "Red" |
| - model: "Toyota Corolla" |
| - speed: 0 |
+---------------------------+
| + start() |
| + accelerate(int) |
| + brake() |
| + getColor() |
| + getModel() |
| + getSpeed() |
+---------------------------+
Conclusion
In Java, a class is a blueprint for creating objects. It defines the attributes and methods that the
objects created from the class can possess. By using classes and objects, we can model real-world
entities and their interactions, making our code more modular, reusable, and maintainable.
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Abstraction is one of the four fundamental principles of Object-Oriented Programming (OOP). It is the
concept of hiding the complex implementation details and showing only the essential features of the
object.
Table of Contents
1. What is Abstraction?
2. Benefits of Abstraction
3. Real-World Examples of Abstraction
4. Abstract Class
5. Interface
6. Abstract Class vs Interface
7. Example: Abstraction with Abstract Class
1. What is Abstraction?
Abstraction is the process of hiding the implementation details and showing only the functionality to
the user. It focuses on what the object does instead of how it does it. Abstraction allows you to
manage complexity by breaking down complex systems into simpler components.
2. Benefits of Abstraction
Reduces complexity: By hiding unnecessary details, abstraction makes the system easier to
Facilitates code reuse: Abstract components can be reused across different parts of the
application or even in different applications.
Consider a man driving a car. The man knows what each pedal and steering wheel does, but he
doesn't know how the car does these things internally. He doesn't know about the inner mechanisms
that empower these things. This is an example of abstraction.
Another real-world example is an ATM Machine. All users perform operations on the ATM machine
like cash withdrawal, money transfer, retrieving mini-statements, etc., but they do not know the
internal details about the ATM. This is another example of abstraction.
4. Abstract Class
An abstract class in Java is a class that cannot be instantiated and may contain abstract methods,
which are methods without a body. Subclasses of the abstract class are responsible for providing
implementations for these abstract methods.
Syntax:
// Regular method
void regularMethod() {
// Method body
}
}
5. Interface
An interface in Java is a reference type, similar to a class, that can contain only constants, method
signatures, default methods, static methods, and nested types. Interfaces cannot contain instance
fields or constructors.
Syntax:
interface InterfaceName {
// Abstract method (implicitly public and abstract)
void abstractMethod();
// Default method
default void defaultMethod() {
// Method body
}
// Static method
static void staticMethod() {
// Method body
}
}
Multiple
Does not support multiple inheritance Supports multiple inheritance
Inheritance
Access Modifiers Can have any access modifier Methods are implicitly public
// Abstract class
abstract class Animal {
// Abstract method
abstract void makeSound();
// Regular method
void eat() {
System.out.println("This animal is eating.");
}
}
// Subclass
class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Bark");
}
}
// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // Output: Bark
dog.eat(); // Output: This animal is eating.
}
}
Explanation:
Animal: Abstract class with an abstract method makeSound and a regular method eat.
Dog: Subclass of Animal that provides an implementation for the makeSound method.
Example:
// Interface
interface Animal {
void makeSound();
void eat();
}
@Override
public void eat() {
System.out.println("This animal is eating.");
}
}
// Usage
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // Output: Bark
dog.eat(); // Output: This animal is eating.
}
}
Explanation:
Dog: Class that implements the Animal interface and provides implementations for the
// Abstract class
abstract class Employee {
private String name;
private int employeeId;
// Abstract method
abstract void calculatePay();
}
// FullTimeEmployee class
class FullTimeEmployee extends Employee {
private double salary;
@Override
void calculatePay() {
System.out.println("FullTimeEmployee Pay: " + salary);
}
}
// Contractor class
class Contractor extends Employee {
private double hourlyRate;
private int hoursWorked;
@Override
void calculatePay() {
System.out.println("Contractor Pay: " + (hourlyRate * hoursWorked));
}
}
// Usage
public class Main {
public static void main(String[] args) {
Employee fullTimeEmployee = new FullTimeEmployee("Alice", 101, 60000);
fullTimeEmployee.calculatePay(); // Output: FullTimeEmployee Pay: 60000.0
Explanation:
Employee: Abstract class with common properties and an abstract method calculatePay.
calculatePay method.
method.
10. Conclusion
Abstraction in Java is a powerful concept that allows you to hide the implementation details and focus
on the functionality. It can be achieved using abstract classes and interfaces. Abstract classes are used
when you want to share code among several closely related classes, while interfaces are used to
define a contract that can be implemented by any class, regardless of its position in the class
hierarchy. Real-world examples like a man driving a car or using an ATM machine illustrate the
concept of abstraction. Understanding and applying abstraction helps to manage complexity, improve
Happy coding!
REPLY
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP). It
involves bundling the data (variables) and the methods (functions) that operate on the data into a
single unit, usually a class. Encapsulation also restricts direct access to some of an object's
Table of Contents
1. What is Encapsulation?
2. Benefits of Encapsulation
3. Encapsulation in Java
4. Access Modifiers
5. Real-World Examples of Encapsulation
6. Example: Encapsulation in Java
7. Conclusion
1. What is Encapsulation?
Encapsulation is the technique of making the fields in a class private and providing access to them via
public methods. It restricts direct access to certain components of an object and protects the integrity
of the data by controlling modifications.
2. Benefits of Encapsulation
Enhanced Security: Encapsulation helps protect data from unauthorized access and
modification by restricting access to an object's internal state.
Controlled Access: Encapsulation provides control over the data by exposing only the necessary
methods to interact with it, ensuring that the data is used in a controlled manner.
Flexibility and Reusability: Encapsulation allows changes to the implementation without
affecting the users of the class, making the code more flexible and reusable.
3. Encapsulation in Java
In Java, encapsulation is achieved by:
4. Access Modifiers
Java provides four types of access modifiers to control the visibility of class members:
default (no modifier): The member is accessible only within the same package.
protected: The member is accessible within the same package and subclasses.
public: The member is accessible from any other class.
5. Real-World Examples of Encapsulation
In a hospital management system, patient data should be encapsulated to ensure that it is accessed
and modified only through authorized methods, maintaining the integrity and confidentiality of the
information.
In a banking application, account details such as account balance should be encapsulated to prevent
unauthorized access and modification, ensuring the security and consistency of the data.
Explanation:
Private Fields: name and age are private fields, meaning they cannot be accessed directly from
Public Getter and Setter Methods: Methods getName, setName, getAge, and setAge are
Validation in Setter Method: The setAge method includes validation to ensure that the age is
not set to a negative value, demonstrating encapsulation's role in maintaining data integrity.
7. Conclusion
Encapsulation in Java is a powerful concept that helps to protect an object's internal state and
provides controlled access to it. By making fields private and exposing public methods to interact with
them, encapsulation ensures that data is used in a controlled and secure manner. This approach
improves maintainability, enhances security, and promotes code reusability and flexibility.
Understanding and applying encapsulation is essential for effective Java programming and building
robust, maintainable software.
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Polymorphism is one of the core concepts of Object-Oriented Programming (OOP). It allows methods
to do different things based on the object it is acting upon, even though they share the same name.
Polymorphism provides a way to perform a single action in different forms. In Java, polymorphism can
Table of Contents
1. What is Polymorphism?
2. Types of Polymorphism
3. Method Overloading
4. Method Overriding
5. Real-World Examples of Polymorphism
6. Example: Polymorphism with Method Overloading
1. What is Polymorphism?
Polymorphism means "many shapes" or "many forms." In Java, it refers to the ability of a single
method or class to take on multiple forms. This is achieved through method overloading (compile-
time polymorphism) and method overriding (runtime polymorphism).
2. Types of Polymorphism
3. Method Overloading
Method overloading occurs when a class has multiple methods with the same name but different
parameter lists (different types or numbers of parameters).
Example:
4. Method Overriding
Method overriding occurs when a subclass provides a specific implementation of a method that is
already defined in its superclass.
Example:
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
Suppose you are in a classroom, you behave like a student. When you are in the market, you behave
like a customer. When you are at home, you behave like a son or daughter. Here, one person exhibits
different behaviors in different contexts.
Example 2: Payment Processing System
In a payment processing system, different payment methods such as credit card, debit card, and
Example:
Printer: Class with overloaded print methods to handle different types of input.
Example:
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
Explanation:
Main method: Demonstrates runtime polymorphism by calling the overridden methods on Dog
Class Diagram
Code Example:
Payment Interface:
interface Payment {
void pay();
}
CashPayment Class:
CreditPayment Class:
Client Class:
Explanation:
CashPayment and CreditPayment: Classes implementing the Payment interface and providing
Polymorphism: Client class demonstrating polymorphism by using the Payment interface to call
9. Conclusion
Polymorphism in Java is a powerful concept that allows methods to perform different tasks based on
the object they are acting upon. It enhances flexibility and maintainability in code by allowing a single
method or class to take on multiple forms. Method overloading and method overriding are two ways
to achieve polymorphism in Java. Real-world examples like different behaviors of a person in different
contexts and various payment processing methods further illustrate the usefulness of polymorphism.
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Inheritance is one of the four fundamental principles of Object-Oriented Programming (OOP). It
allows a class to inherit properties and behaviors (fields and methods) from another class. The class
that inherits the properties is called the subclass (or derived class), and the class from which
properties are inherited is called the superclass (or base class). Inheritance promotes code reusability
and establishes a natural hierarchical relationship between classes.
Table of Contents
1. What is Inheritance?
2. Benefits of Inheritance
3. Types of Inheritance
4. Single Inheritance
5. Multilevel Inheritance
6. Hierarchical Inheritance
7. Real-World Examples of Inheritance
8. Example: Single Inheritance
11. Conclusion
1. What is Inheritance?
Inheritance is a mechanism wherein a new class is derived from an existing class. The derived class
(child class) inherits the attributes and methods of the base class (parent class), allowing code reuse
and the creation of a natural hierarchy.
2. Benefits of Inheritance
Code Reusability: Inheritance allows a class to reuse the fields and methods of another class.
Method Overriding: Subclasses can provide specific implementations for methods that are
3. Types of Inheritance
multiple inheritance directly to avoid complexity and ambiguity. However, it can be achieved
using interfaces.
4. Single Inheritance
In a single inheritance, a class inherits from one superclass.
Example:
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
5. Multilevel Inheritance
Example:
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
6. Hierarchical Inheritance
In hierarchical inheritance, multiple classes inherit from a single superclass.
Example:
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
In Multiple inheritances, one class can have more than one superclass and inherit features from all
parent classes.
Please note that Java does not support multiple inheritances with classes. In Java, we can achieve
Consider a vehicle hierarchy where Vehicle is the base class. Car and Bike can be derived classes
In an employee management system, Employee can be the base class. Manager and Developer can
The Java library extensively uses inheritance. The figure below shows an inheritance hierarchy
from java.lang library. The Number class abstracts various numerical (reference) types such
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
Explanation:
Dog: Subclass that inherits from Animal and adds a method bark.
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
Explanation:
Dog: Subclass that inherits from Animal and adds a method bark.
Puppy: Subclass that inherits from Dog and adds a method weep.
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
Explanation:
Dog and Cat: Subclasses that inherit from Animal and add methods bark and meow,
respectively.
11. Conclusion
Inheritance in Java is a powerful concept that promotes code reusability and establishes a natural
hierarchical relationship between classes. By using inheritance, you can create a base class with
common properties and methods and then create derived classes that inherit these properties and
methods while adding specific features. Understanding and applying inheritance helps to build a
structured and organized codebase, making it easier to maintain and extend.
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Composition is a fundamental concept in Object-Oriented Programming (OOP) that allows a class to
contain objects of other classes to achieve code reuse and establish a has-a relationship. Unlike
inheritance, which represents an is-a relationship, composition models a relationship where one
Table of Contents
1. What is Composition?
2. Benefits of Composition
3. Composition vs Inheritance
1. What is Composition?
Composition is a design principle where a class contains references to one or more objects of other
classes. This allows the class to use the functionality of the composed objects and delegate tasks to
them. Composition is often preferred over inheritance because it promotes greater flexibility and
modularity in the design.
there is no chance of an existing dependent object; hence, these are strongly associated, and this
relationship is called composition.
2. Benefits of Composition
Reusability: Composition allows for code reuse by including instances of other classes.
Flexibility: Changes to composed objects can be made independently of the class that uses
them.
Encapsulation: Composition encapsulates the functionality of composed objects, reducing
dependencies.
Better Modeling: Composition better represents real-world relationships where objects are
made up of other objects.
3. Composition vs Inheritance
Flexibility More flexible, allows runtime behavior changesLess flexible, fixed at compile time
Coupling Loosely coupled Tightly coupled
Reusability Promotes high reusability Limited reusability
EncapsulationBetter encapsulation Exposes implementation details
Example:
Let's create a Library class that contains multiple Book objects using composition.
import java.util.ArrayList;
import java.util.List;
public class Library {
private List<Book> books;
public Library() {
this.books = new ArrayList<>();
}
library.showBooks();
// Output:
// Title: 1984, Author: George Orwell
// Title: To Kill a Mockingbird, Author: Harper Lee
}
}
Explanation:
Library: A class that uses composition to include multiple Book objects. The Library class
manages a list of books and provides methods to add and display books.
Main: A class to demonstrate the use of composition by creating Book objects and adding them
to the Library.
A Car class can use composition to include an Engine object. The Car class can delegate the starting
class Engine {
public void start() {
System.out.println("Engine started.");
}
class Car {
private Engine engine;
public Car() {
this.engine = new Engine();
}
A Computer class can use composition to include CPU, RAM, and HardDrive objects. The Computer
class CPU {
public void process() {
System.out.println("CPU processing...");
}
}
class RAM {
public void load() {
System.out.println("RAM loading...");
}
}
class HardDrive {
public void readData() {
System.out.println("HardDrive reading data...");
}
}
class Computer {
private CPU cpu;
private RAM ram;
private HardDrive hardDrive;
public Computer() {
this.cpu = new CPU();
this.ram = new RAM();
this.hardDrive = new HardDrive();
}
6. Conclusion
Composition in Java is a powerful concept that promotes code reuse and modularity by allowing a
class to contain objects of other classes. It models a has-a relationship, which is more flexible and
encapsulated than inheritance. By using composition, developers can build complex systems that are
easy to maintain and extend. Understanding and applying composition effectively is essential for
designing robust and scalable Java applications.
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Aggregation is a type of association that represents a "has-a" relationship with a whole-part hierarchy.
In aggregation, the child object can exist independently of the parent object, implying a weak
relationship between the parent and child. Aggregation allows one class to contain another class
Table of Contents
1. What is Aggregation?
2. Benefits of Aggregation
3. Aggregation vs Composition
1. What is Aggregation?
Aggregation is a special type of association that represents a whole-part relationship where the child
(part) can exist independently of the parent (whole). It is used to model relationships where the
contained objects are not strongly dependent on the lifecycle of the container object.
2. Benefits of Aggregation
Reusability: Aggregated objects can be reused across different parts of the application.
Flexibility: Aggregated objects can exist independently of the parent object, providing flexibility
in design.
enhancing maintainability.
3. Aggregation vs Composition
Example:
Let's create a Department class that aggregates multiple Employee objects using aggregation.
import java.util.ArrayList;
import java.util.List;
Explanation:
Department: A class that uses aggregation to include multiple Employee objects. The
Main: A class to demonstrate the use of aggregation by creating Employee objects and adding
A School class can aggregate multiple Student objects. The Student objects can exist independently
of the School.
Student Class
School Class
import java.util.ArrayList;
import java.util.List;
A Library class can aggregate multiple Book objects. The Book objects can exist independently of
the Library.
Book Class
Library Class
import java.util.ArrayList;
import java.util.List;
6. Conclusion
Aggregation in Java is a powerful concept that allows classes to model a whole-part relationship
where the parts can exist independently of the whole. This promotes modularity, reusability, and
maintainability in the design of software systems. By understanding and using aggregation correctly,
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Association is a relationship between two classes that establishes a connection between their objects.
It defines how objects of one class are connected to objects of another class. Association can be of
different types: unidirectional, bidirectional, one-to-one, one-to-many, many-to-one, and many-to-
Table of Contents
1. What is Association?
2. Types of Association
3. Benefits of Association
7. Conclusion
1. What is Association?
Association is a structural relationship that represents how objects of one class are related to objects
of another class. Unlike inheritance, which defines an is-a relationship, association defines a has-a
relationship. It indicates that one object uses or interacts with another object.
2. Types of Association
Unidirectional Association: One class knows about the other class, but not vice versa.
Bidirectional Association: Both classes know about each other.
One-to-One Association: One object of a class is associated with one object of another class.
One-to-Many Association: One object of a class is associated with many objects of another
class.
Many-to-One Association: Many objects of a class are associated with one object of another
class.
Many-to-Many Association: Many objects of a class are associated with many objects of
another class.
3. Benefits of Association
Reusability: Promotes code reuse by establishing relationships between classes.
Flexibility: Allows classes to interact and collaborate without being tightly coupled.
Modularity: Helps in creating modular designs by defining clear relationships between classes.
Improved Design: Facilitates better design by modeling real-world relationships.
Example:
Let's create a Library class that is associated with multiple Book objects using unidirectional
association.
import java.util.ArrayList;
import java.util.List;
public Library() {
this.books = new ArrayList<>();
}
library.showBooks();
// Output:
// Title: 1984, Author: George Orwell
// Title: To Kill a Mockingbird, Author: Harper Lee
}
}
Explanation:
Library: A class that uses unidirectional association to include multiple Book objects. The
Main: A class to demonstrate the use of unidirectional association by creating Book objects and
Example:
Let's create a Person class and an Address class with a bidirectional association.
person.setAddress(address);
Explanation:
Main: A class to demonstrate bidirectional association by creating Person and Address objects
In a university system, a University class can have multiple Student objects. This can be modeled
University Class
import java.util.ArrayList;
import java.util.List;
Student Class
In a company, a Department can have multiple Employee objects, and an Employee can belong to a
single Department.
Department Class
import java.util.ArrayList;
import java.util.List;
Employee Class
7. Conclusion
Association in Java is a powerful concept that allows modeling relationships between classes. By
understanding and using association correctly, developers can create flexible, modular, and
maintainable systems. Association can be unidirectional or bidirectional and can represent one-to-
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Cohesion is a measure of how closely related and focused the responsibilities of a single module or
class are. In Object-Oriented Programming (OOP), a highly cohesive class is one that performs a single
task or a group of related tasks, making the class easier to maintain and understand. High cohesion
often correlates with low coupling, leading to a more modular and maintainable codebase.
Table of Contents
1. What is Cohesion?
2. Benefits of High Cohesion
3. Types of Cohesion
1. What is Cohesion?
Cohesion refers to the degree to which the elements inside a module or class belong together. It
describes how well the methods and properties of a class are related to each other. High cohesion
means that a class is responsible for only one thing or a group of related things, while low cohesion
means that a class has many unrelated responsibilities.
Improved Maintainability: High cohesion makes classes easier to maintain and update
because each class has a clear and focused responsibility.
Enhanced Readability: Classes with high cohesion are easier to understand and reason about.
Increased Reusability: Highly cohesive classes are more likely to be reused in different parts of
an application or in different projects.
Simplified Testing: Testing is easier for highly cohesive classes since they perform a single task
or a group of related tasks.
3. Types of Cohesion
1. Low cohesion
2. High Cohesion
In a class with low cohesion, responsibilities are scattered and unrelated, making the class difficult to
maintain and understand.
In a class with high cohesion, responsibilities are related and focused, making the class easier to
Employee Class
SalaryCalculator Class
public class SalaryCalculator {
public double calculateAnnualSalary(Employee employee) {
return employee.getSalary() * 12;
}
}
ReportPrinter Class
EmailService Class
Explanation
LowCohesionClass: Contains methods that perform unrelated tasks such as calculating salary,
printing reports, and sending emails. This makes the class difficult to understand and maintain.
High Cohesion Example: Responsibilities are divided into separate classes: Employee,
In a library system, you can have classes like Book, LibraryMember, LibraryCatalog, and
LoanService. Each class has a specific responsibility, such as managing book details, handling
member information, maintaining the catalog, and managing book loans, respectively.
Book Class
LibraryMember Class
LibraryCatalog Class
LoanService Class
public class LoanService {
public void loanBook(LibraryMember member, Book book) {
// Logic to loan a book to a member
}
}
In an e-commerce system, you can have classes like Product, ShoppingCart, Order, and
Product Class
ShoppingCart Class
Order Class
public class Order {
private List<Product> products;
PaymentProcessor Class
6. Conclusion
Cohesion is a critical concept in software design that affects the maintainability, readability, and
reusability of a system. High cohesion within classes leads to a more modular and understandable
codebase, making it easier to manage and extend. By focusing on creating highly cohesive classes,
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Coupling refers to the degree of direct knowledge that one class has about another class. In software
design, coupling is an essential concept that impacts the modularity and maintainability of a system.
Lower coupling between classes usually leads to a system that is easier to maintain and extend, while
higher coupling can make the system more rigid and harder to manage.
Table of Contents
1. What is Coupling?
2. Types of Coupling
3. Benefits of Low Coupling
1. What is Coupling?
Coupling describes the degree of dependency between classes or modules. It indicates how closely
connected different classes or modules are, and how much they rely on each other. There are two
Tight Coupling: High dependency between classes. Changes in one class often require changes
2. Types of Coupling
Tight Coupling
Tight coupling occurs when a class is highly dependent on the specifics of another class. This often
happens when one class creates an instance of another class and directly accesses its methods and
fields.
Loose Coupling
Loose coupling occurs when classes are less dependent on the specifics of other classes. This can be
achieved by using interfaces, abstract classes, or dependency injection, allowing classes to interact
without knowing the implementation details of each other.
Improved Maintainability: Changes in one class have minimal impact on other classes.
Enhanced Reusability: Loosely coupled classes can be reused in different contexts.
Better Testability: Independent classes are easier to test in isolation.
In a tightly coupled system, changes in one class can significantly affect other classes.
Example:
class Engine {
public void start() {
System.out.println("Engine started.");
}
}
class Car {
private Engine engine;
public Car() {
this.engine = new Engine(); // Direct instantiation
}
Explanation:
The Car class directly creates an instance of Engine and calls its start method.
Any change in the Engine class, such as a change in the method signature, would require
interface Engine {
void start();
}
class Car {
private Engine engine;
The Car class can work with any implementation of the Engine interface, promoting loose
coupling.
6. Conclusion
Coupling is a critical concept in software design that affects the modularity, maintainability, and
flexibility of a system. Tight coupling leads to a system where classes are highly dependent on each
other, making it hard to maintain and extend. Loose coupling, on the other hand, reduces
dependencies, making the system easier to manage and adapt to changes. By using interfaces,
abstract classes, and dependency injection, developers can achieve loose coupling and build more
robust and flexible systems.
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
Delegation is an object-oriented design pattern in which an object passes a task to another object
instead of performing it itself. This concept allows for polymorphism and code reuse, leading to more
maintainable and flexible code. Delegation helps maintain a loosely coupled system, which is easier to
Table of Contents
1. What is Delegation?
2. Benefits of Delegation
3. Example 1: Ticket Booking System
1. What is Delegation?
2. Benefits of Delegation
Enhanced Flexibility: Changes to the delegated class do not affect the delegator class.
Improved Maintainability: Easier to maintain and extend as the code is modular.
Step-by-Step Implementation
interface TravelBooking {
void bookTicket();
}
The TravelBooking interface defines a single method bookTicket(), which will be implemented by
The AirBooking class implements the TravelBooking interface and provides a specific
@Override
public void bookTicket() {
travelBooking.bookTicket();
}
}
The TicketBookingByAgent class also implements the TravelBooking interface but delegates the
actual booking task to another TravelBooking object. The delegation is achieved via the constructor
which accepts a TravelBooking object. The bookTicket() method calls the bookTicket() method
delegates the call to the appropriate booking class (either TrainBooking or AirBooking).
In this example, the TicketBookingByAgent class does not handle the actual ticket booking process.
Instead, it delegates this responsibility to the classes that implement the TravelBooking interface
Step-by-Step Implementation
The Printer interface defines a single method print(), which will be implemented by various
printer classes.
The CanonPrinter class implements the Printer interface and provides a specific implementation
The EpsonPrinter class implements the Printer interface and provides a specific implementation
The HpPrinter class implements the Printer interface and provides a specific implementation for
printing a message.
@Override
public void print(String message) {
printer.print(message);
}
}
The PrinterController class also implements the Printer interface but delegates the actual
printing task to another Printer object. The delegation is achieved via the constructor which accepts
a Printer object. The print() method calls the print() method of the delegated Printer object.
In this example, the PrinterController class does not handle the actual printing process. Instead, it
delegates this responsibility to the classes that implement the Printer interface (CanonPrinter,
EpsonPrinter, and HpPrinter). This allows PrinterController to dynamically choose which
5. Conclusion
Delegation is a powerful design pattern that allows objects to delegate tasks to other objects,
promoting code reuse and modularity. By using delegation, you can create more flexible and
maintainable systems. In this article, we explored two examples: a ticket booking system and a printer
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Single Responsibility Principle (SRP) is one of the five SOLID principles of object-oriented design.
SRP states that a class should have only one reason to change, meaning it should have only one
responsibility or job. This principle helps in creating more maintainable and understandable code by
Table of Contents
1. What is the Single Responsibility Principle?
2. Benefits of the Single Responsibility Principle
3. Example: Violation of SRP
The Single Responsibility Principle (SRP) asserts that a class should only have one reason to change,
implying it should have only one responsibility or purpose. This principle helps in building classes that
are easier to understand, test, and maintain by ensuring each class is focused on a single aspect of the
application.
Improved Maintainability: Changes to a single responsibility affect only one class, making the
codebase easier to maintain.
Enhanced Readability: Classes with a single responsibility are easier to read and understand.
Increased Reusability: Classes focused on a single responsibility can be reused in different
contexts without modification.
Simplified Testing: Testing is more straightforward for classes with a single responsibility.
In this example, a User class is responsible for both user management and email sending, violating
SRP.
Issues:
The User class is responsible for both saving the user and sending emails.
Any change in email sending logic will require changes in the User class, violating SRP.
5. Real-World Example
Book Class
Member Class
LoanService Class
Explanation:
Conclusion
The Single Responsibility Principle (SRP) is a fundamental concept in object-oriented design that
promotes high cohesion and low coupling by ensuring that each class has only one responsibility or
reason to change. By adhering to SRP, developers can create more maintainable, understandable, and
flexible code. This principle is critical for building robust and scalable applications.
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Open/Closed Principle (OCP) is one of the five SOLID principles of object-oriented design. It
states that software entities (such as classes, modules, and functions) should be open for extension
but closed for modification. This means that the behavior of a module can be extended without
Table of Contents
1. What is the Open/Closed Principle?
2. Benefits of the Open/Closed Principle
3. Example: Violation of OCP
The Open/Closed Principle (OCP) asserts that a class should be open for extension but closed for
modification. This means you should be able to add new functionality to a class by extending it,
functionality.
Improved Flexibility: New features can be added without modifying existing code.
Increased Reusability: Classes that adhere to OCP are more likely to be reusable in different
contexts.
In this example, we'll create a Shape class and a AreaCalculator class that violates OCP by requiring
Example:
class Circle {
private double radius;
class Rectangle {
private double width;
private double height;
class AreaCalculator {
public double calculateArea(Object shape) {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
return Math.PI * circle.getRadius() * circle.getRadius();
} else if (shape instanceof Rectangle) {
Rectangle rectangle = (Rectangle) shape;
return rectangle.getWidth() * rectangle.getHeight();
}
return 0;
}
}
Issues:
The AreaCalculator class must be modified to support new shapes, violating OCP.
Adding new shapes requires changes to the calculateArea method, making the code less
maintainable.
To adhere to OCP, we can use polymorphism and interfaces to allow the AreaCalculator to work
Example:
interface Shape {
double calculateArea();
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
}
@Override
public double calculateArea() {
return width * height;
}
}
class AreaCalculator {
public double calculateArea(Shape shape) {
return shape.calculateArea();
}
}
Explanation:
Circle and Rectangle: Implementations of the Shape interface that provide specific area
calculations.
AreaCalculator: A class that calculates the area of any Shape without needing modification.
Main: Demonstrates the use of OCP by adding new shapes without changing the
AreaCalculator class.
5. Real-World Example
Consider a notification system where different types of notifications (e.g., email, SMS) need to be sent.
Step 1: Define the Notification Interface
interface Notification {
void send(String message);
}
class NotificationService {
private List<Notification> notifications;
public NotificationService() {
this.notifications = new ArrayList<>();
}
service.sendAll("Hello, World!");
// Output:
// Sending email: Hello, World!
// Sending SMS: Hello, World!
}
}
Explanation:
types of notifications.
Main: Demonstrates the use of OCP by adding new notification types without changing the
NotificationService class.
6. Conclusion
The Open/Closed Principle (OCP) is a fundamental concept in object-oriented design that promotes
the extension of software entities without modifying their source code. By adhering to OCP,
developers can create more maintainable, flexible, and reusable code. Understanding and applying
Happy coding!
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Liskov Substitution Principle (LSP) is one of the five SOLID principles of object-oriented design. It
states that objects of a superclass should be replaceable with objects of a subclass without affecting
the correctness of the program. This principle ensures that a subclass can stand in for its superclass
without altering the desirable properties of the program (correctness, task performed, etc.).
Table of Contents
1. What is the Liskov Substitution Principle?
2. Benefits of the Liskov Substitution Principle
3. Example: Violation of LSP
The Liskov Substitution Principle (LSP) asserts that if S is a subtype of T, then objects of type T may be
replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without
altering any of the desirable properties of the program. This means that subclasses should extend the
classes.
Improved Maintainability: Reduces the risk of introducing bugs when extending classes.
Increased Flexibility: Allows for more flexible and modular code design.
Example:
class Bird {
public void fly() {
System.out.println("Bird is flying");
}
}
Issues:
The Penguin class violates LSP because it changes the behavior of the fly method by throwing
an exception.
This breaks the expected behavior of the Bird class and can lead to runtime errors.
To adhere to LSP, we can introduce a more appropriate class hierarchy where flying ability is modeled
differently.
Example:
Explanation:
Bird: An abstract class that provides a common interface for all bird types.
Sparrow and Penguin: Subclasses that extend Bird without changing its behavior.
Main: Demonstrates the use of LSP by allowing subclasses to be used interchangeably with the
parent class.
5. Real-World Example
Consider a payment processing system where different payment methods (e.g., credit card, PayPal)
should adhere to the Liskov Substitution Principle.
Explanation:
Payment: An abstract class that provides a common interface for all payment methods.
CreditCardPayment and PayPalPayment: Subclasses that extend Payment without changing its
behavior.
Main: Demonstrates the use of LSP by allowing different payment methods to be used
interchangeably.
6. Conclusion
The Liskov Substitution Principle (LSP) is a fundamental concept in object-oriented design that
ensures subclasses can replace their parent classes without altering the correctness of the program.
By adhering to LSP, developers can create more flexible, reusable, and maintainable code.
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Interface Segregation Principle (ISP) is one of the five SOLID principles of object-oriented design.
ISP states that no client should be forced to depend on methods they do not use. This principle
promotes the creation of smaller, more specific interfaces instead of larger, general-purpose
interfaces, ensuring that classes implement only the methods that are relevant to them.
Table of Contents
1. What is the Interface Segregation Principle?
2. Benefits of the Interface Segregation Principle
3. Example: Violation of ISP
The Interface Segregation Principle (ISP) asserts that clients should not be forced to depend on
interfaces they do not use. In other words, an interface should not include methods that are not
relevant to the implementing class. Instead, interfaces should be small and focused on specific sets of
behaviors.
Enhanced Flexibility: Changes in one part of the system are less likely to affect other parts.
Increased Reusability: Classes can implement only the interfaces they need, promoting reuse.
In this example, we'll create an interface Worker that violates ISP by including methods not relevant to
Example:
interface Worker {
void work();
void eat();
}
@Override
public void eat() {
System.out.println("Developer is eating.");
}
}
@Override
public void eat() {
// Robot does not eat
throw new UnsupportedOperationException("Robot does not eat.");
}
}
Issues:
The Robot class is forced to implement the eat method, which is not applicable to it.
This leads to a violation of ISP as the Robot class depends on a method it does not use.
To adhere to ISP, we can split the Worker interface into more specific interfaces.
Example:
interface Workable {
void work();
}
interface Eatable {
void eat();
}
@Override
public void eat() {
System.out.println("Developer is eating.");
}
}
Main: Demonstrates the use of ISP by allowing classes to implement only the methods they
need.
5. Real-World Example
Consider a document printing system where different devices have different capabilities.
interface Printable {
void print();
}
interface Scannable {
void scan();
}
interface Faxable {
void fax();
}
@Override
public void scan() {
System.out.println("Scanning document.");
}
@Override
public void fax() {
System.out.println("Faxing document.");
}
}
Explanation:
Main: Demonstrates the use of ISP by allowing devices to implement only the capabilities they
support.
6. Conclusion
The Interface Segregation Principle (ISP) is a fundamental concept in object-oriented design that
promotes the creation of small, specific interfaces rather than large, general-purpose ones. By
adhering to ISP, developers can create more flexible, maintainable, and reusable code. Understanding
and applying ISP is essential for building robust and scalable Java applications.
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Introduction
The Dependency Inversion Principle (DIP) is one of the five SOLID principles of object-oriented design.
It states that high-level modules should not depend on low-level modules. Both should depend on
abstractions. Furthermore, abstractions should not depend on details. Details should depend on
Table of Contents
1. What is the Dependency Inversion Principle?
High-level modules should not depend on low-level modules. Both should depend on
abstractions.
Abstractions should not depend on details. Details should depend on abstractions.
This principle ensures that the system's high-level policy does not depend on the low-level details but
rather on an abstraction.
In this example, we'll create a LightBulb class and a Switch class that violates DIP by depending
directly on LightBulb.
Example:
class LightBulb {
public void turnOn() {
System.out.println("LightBulb is turned on");
}
Issues:
The Switch class depends directly on the LightBulb class, creating tight coupling.
Any change in the LightBulb class requires changes in the Switch class.
To adhere to DIP, we can introduce an abstraction for the LightBulb class and make the Switch class
Example:
interface Switchable {
void turnOn();
void turnOff();
}
@Override
public void turnOff() {
System.out.println("LightBulb is turned off");
}
}
class Switch {
private Switchable switchable;
Explanation:
Switch: A class that depends on the Switchable interface rather than the LightBulb class.
Main: Demonstrates the use of DIP by creating a Switch object that depends on the
Switchable interface.
5. Real-World Example
Consider a payment processing system where different payment methods (e.g., credit card, PayPal)
need to be processed.
interface PaymentProcessor {
void processPayment(double amount);
}
class PaymentService {
private PaymentProcessor paymentProcessor;
Explanation:
Main: Demonstrates the use of DIP by creating a PaymentService object that depends on the
PaymentProcessor interface.
6. Conclusion
The Dependency Inversion Principle (DIP) is a fundamental concept in object-oriented design that
promotes loose coupling between high-level and low-level modules by depending on abstractions
rather than concrete implementations. By adhering to DIP, developers can create more maintainable,
flexible, and testable code. Understanding and applying DIP is essential for building robust and
Happy coding!
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
There are several ways to create objects in Java. In this article, we will discuss five different ways to
create objects in Java. We will understand each method with an example and its output.
Example:
public class Car {
private String color;
private String model;
Output:
2. Using Class.forName()
This method is used for dynamic class loading. It can throw a ClassNotFoundException.
Example:
public Car() {
this.color = "Blue";
this.model = "Honda Civic";
}
Output:
3. Using clone()
This method creates a new object by copying the existing object's data. It requires the class to
implement the Cloneable interface.
Example:
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
Output:
This method creates an object from a serialized form (a byte stream). It requires the class to
implement the Serializable interface.
Example:
import java.io.*;
deserializedCar.displayInfo();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Output:
creation process.
Example:
Output:
Conclusion
These are five different ways to create objects in Java. Each method has its use cases and advantages,
and understanding these methods is crucial for effective Java programming.
How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this article, we will discuss the Java design patterns interview questions asked for experienced Java
developers.
Let's discuss the most useful and frequently asked interview questions of Java/Java EE design patterns.
concrete classes.
javax.xml.parsers.DocumentBuilderFactory#newInstance()
javax.xml.transform.TransformerFactory#newInstance()
javax.xml.xpath.XPathFactory#newInstance()
Builder
Separate the construction of a complex object from its representation so that the same construction
process can create different representations.
java.lang.StringBuilder#append() (unsynchronized)
java.lang.StringBuffer#append() (synchronized)
Factory method
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory
Method lets a class defer instantiation to subclasses.
java.util.Calendar#getInstance()
java.util.ResourceBundle#getBundle()
java.text.NumberFormat#getInstance()
java.nio.charset.Charset#forName()
Prototype
Specify the kinds of objects to create using a prototypical instance, and create new objects by copying
this prototype.
Singleton
Ensure a class only has one instance, and provide a global point of access to it.
java.lang.Runtime#getRuntime()
java.awt.Desktop#getDesktop()
java.lang.System#getSecurityManager()
Read the complete list of design patterns used in standard JDK libraries at Examples of GoF Design
Patterns in Java's core libraries
Read more about each of the above design patterns in-detail at Design Patterns used in Hibernate
Framework
Factory Method Pattern allows the sub-classes to choose the type of objects to create.
It promotes the loose-coupling by eliminating the need to bind application-specific classes into
the code. That means the code interacts solely with the resultant interface or abstract class so
that it will work with any classes that implement that interface or that extend that abstract class.
classes delegate responsibility to one of several helper subclasses, and you want to localize the
knowledge of which helper subclass is the delegate
Read more about Factory design pattern at Factory Design Pattern in Java with Examples
3. Delegation Principle
become visible until later in the implementation. Reusing design patterns helps to prevent
subtle issues that can cause major problems and improves code readability for coders and
architects familiar with the patterns.
Often, people only understand how to apply certain software design techniques to certain
problems. These techniques are difficult to apply to a broader range of problems. Design
patterns provide general solutions, documented in a format that doesn't require specifics tied to
a particular problem.
1. Creational Patterns
In software engineering, creational design patterns are design patterns that deal with object creation
mechanisms, trying to create objects in a manner suitable to the situation.
2. Structural Patterns
In Software Engineering, Structural Design Patterns are Design Patterns that ease the design by
identifying a simple way to realize relationships between entities.
3. Behavioral Patterns
In software engineering, behavioral design patterns are design patterns that identify common
communication patterns between objects and realize these patterns. By doing so, these patterns
increase flexibility in carrying out this communication.
Chain of responsibility
Delegation Pattern
Presentation Tier
Business Tier
Integration Tier
Ensure a class only has one instance, and provide a global point of access to it.
there must be exactly one instance of a class, and it must be accessible to clients from a well-
known access point.
when the sole instance should be extensible by subclassing, and clients should be able to use an
extended instance without modifying their code.
Separate the construction of a complex object from its representation so that the same construction
the algorithm for creating a complex object should be independent of the parts that make up
the construction process must allow different representations for the object that's constructed.
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this article, we will discuss important Java OOPS (Object Oriented Programming) interview
questions and answers for freshers as well as experienced candidates.
The first reason is that the Object-oriented programming language should only have objects whereas
Java contains 8 primitive data types char, boolean, byte, short, int, long, float, and double which
are not objects. These primitive data types can be used without the use of any object.
For example:
Output:
10
20
30
100
100.1
100
100.1
200.0
true
R
The second reason is related to the static keyword. In a pure object-oriented language, we should
access everything by message passing (through objects). But Java contains static variables and
For example:
Object
Class
Abstraction
Encapsulation
Inheritance
Polymorphism
Composition
Aggregation
Association
Cohesion
Coupling
Delegation
package com.javaguides.corejava.basics.polymorphism;
Output:
No parameters
a: 10
a and b: 10 20
double a: 123.25
Result of ob.test(123.25): 15190.5625
The compiler will resolve the call to a correct overloaded method depending on the actual number
and/or types of the passed parameters. We can use Method overloading to achieve Java compile-
time polymorphism.
The main advantage of method overloading increases the readability of the program.
Java decided at the runtime the actual method that should be called depending upon the type of
object we create. For example:
class SuperClass {
void method1(String message) {
System.out.println(message);
}
}
class SubClass extends SuperClass {
void method1(String message) {
message = message + " in SubClass";
System.out.println(message);
}
}
Output:
hello in SubClass
Another example:
class Shape {
void draw() {
System.out.println("drawing...");
}
}
class Rectangle extends Shape {
void draw() {
System.out.println("drawing rectangle...");
}
}
class Circle extends Shape {
void draw() {
System.out.println("drawing circle...");
}
}
class Triangle extends Shape {
void draw() {
System.out.println("drawing triangle...");
}
}
class TestPolymorphism2 {
public static void main(String args[]) {
Shape s;
s = new Rectangle();
s.draw();
s = new Circle();
s.draw();
s = new Triangle();
s.draw();
}
}
Output:
drawing rectangle...
drawing circle...
drawing triangle...
Here are the main rules that govern method overriding:
1. The name and signature of the method are the same in the superclass and subclass, or in the
4. The overriding method cannot reduce the accessibility of the overridden method, but the opposite
is possible
5. The overriding method cannot throw checked exceptions that are higher in the exception
For example:
// Method overriding.
class A {
int i, j;
A(int a, int b) {
i = a;
j = b;
}
// display i and j
void show() {
System.out.println("i and j: " + i + " " + j);
}
}
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
void show() {
super.show(); // this calls A's show()
System.out.println("k: " + k);
}
}
Output:
i and j: 1 2
k: 3
Because the static methods are resolved at compile-time, while the methods that we can override are
The below diagram demonstrates that the main() method can be overloaded:
Can we override a non-static method as static
in Java?
No. we cannot override a non-static method as a static one. If we try then it leads to a compilation
error:
In the example given below, both the classes have a data member speedlimit , we are accessing the
data member by the reference variable of the Parent class which refers to the subclass object. Since
we are accessing the data member which is not overridden, hence it will access the data member of
class Bike {
int speedlimit = 90;
}
class Honda extends Bike {
int speedlimit = 150;
Output:
90
of the details. In OOP terms, we say that an object should expose to the users only a set of high-level;
Let's consider a real-life example: a man driving a car. The man knows what each pedal does and what
the steering wheel does, but he doesn't know how these things are done internally by the car. He
doesn't know about the inner mechanisms that empower these things. This is known as abstraction.
Code example: Let's create a Car interface with high-level methods:
Next, each type of car should implement the Car interface and override these methods to provide
the implementation of these methods. This implementation is hidden from the user.
@Override
public void speedUp() {
System.out.println("Speed up the electric car");
}
@Override
public void slowDown() {
System.out.println("Slow down the electric car");
}
@Override
public void turnRight() {
System.out.println("Turn right the electric car");
}
@Override
public void turnLeft() {
System.out.println("Turn left the electric car");
}
@Override
public String getCarType() {
return this.carType;
}
}
The user of this class has access to these public methods without being aware of the implementation:
functions operating on that data are combined together to form a single unit, which is referred to as a
class.
Encapsulation is the technique whereby the object's state is hidden from the outer world and a set of
public methods for accessing this state are exposed. When each object keeps its state private inside a
class, we can say that encapsulation was achieved. This is why encapsulation is also referenced as the
data-hiding mechanism.
Encapsulation has a number of important advantages such as loosely coupled, reusable, secure, and
easy-to-test code.
In Java, encapsulation is implemented via the access modifiers - public, private, and protected.
Let's consider an example: a Cat class can have its state represented by fields such as mood,
hungry, and energy. While the code external to the Cat class cannot modify any of these fields
directly, it can call public methods play() , feed() , and sleep() that modify the Cat state
internally.
The Cat class may also have private methods that are not accessible outside the class, such as
The only way to modify the state (private fields) is via the public methods play() , feed() , and
cat.feed();
cat.play();
cat.feed();
cat.sleep();
Feed ...
Meow!
Play ...
Meow!
Feed ...
Meow!
Sleep ...
Energy: 50
Mood: 53
Hungry: 49
What is Inheritance?
Inheritance is the process by which one object acquires the properties of another object.
Inheritance - IS-A relationship between a superclass and its subclasses. The process where one object
acquires the properties of another object plus it can have its own.
Let's consider a Dog, the Dog (subclass) is a type of Animal (superclass). So Dog can inherit (reuse)
members of the Animal class; plus it can have its own new behavior and properties.
In the Java library, you can see extensive use of inheritance. The below figure shows a partial
inheritance hierarchy from java.lang library. The Number class abstracts various numerical
(reference) types such as Byte , Integer , Float , Double , Short , and BigDecimal .
What is Composition?
A Composition is an association that represents a part of a whole relationship where a part cannot
exist without a whole. If a whole is deleted then all parts are deleted. It has a stronger relationship.
Read more about Composition with a complete example at Composition in Java with Example.
What is Aggregation?
Aggregation is an association that represents a part of a whole relationship where a part can exist
without a whole. It has a weaker relationship.
It is a specialized form of Association where all object has their own lifecycle but there is ownership.
This represents a “whole-part or a-part-of” relationship.
Let’s take an example of the relationship between the Department and the Teacher . A Teacher
may belong to multiple departments. Hence Teacher is a part of multiple departments. But if we
Single Responsibility Principle - A class should have only one reason to change
Open/Closed Principle - Software entities like classes, modules, and functions should be open
for extension but closed for modifications.
Liskov Substitution Principle - Derived types must be completely substitutable for their base
types.
Interface Segregation Principle - The Interface Segregation Principle states that clients should
not be forced to implement interfaces they don't use. ISP splits interfaces that are very large into
smaller and more specific ones so that clients will only have to know about the methods that are
of interest to them.
Dependency Inversion Principle - High-level modules should not depend on low-level modules.
that responsibility should be entirely encapsulated by the class. There should never be more than one
reason for a class to change.
Read more about the Single Responsibility Principle with an example at Single Responsibility
Principle.
modifications.
Read more about Open Closed Principle with an example at Open Closed Principle
Read more about Liskov Substitution Principle with an example of Liskov's Substitution Principle
clients will only have to know about the methods that are of interest to them.
Read more about Interface Segregation Principle with an example at Interface Segregation
Principle
How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?
Free Courses
on YouTube
Channel
175K
Subscribers
INTERVIEW JAVA 11
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Java 11, released in September 2018, brought a host of new features and enhancements that have
been crucial for developers. If you're preparing for a job interview that involves Java 11, it’s essential
to be familiar with its key features, improvements, and best practices. This blog post will cover some
of the most commonly asked Java 11 interview questions to help you prepare effectively.
and repeat().
HTTP Client: Standardized the HTTP Client API that was introduced in Java 9 as an incubator
module.
Nest-Based Access Control: Introduced to support the improved encapsulation of nested
classes.
Deprecation of Nashorn JavaScript Engine: Marked for removal.
Epsilon Garbage Collector: A no-op garbage collector for testing.
expressions. This means you can declare the type of lambda parameters using var, making the code
Example:
import java.util.List;
3. What are the new methods added to the String class in Java
11?
Answer: Java 11 introduced several new methods to the String class:
isBlank(): Returns true if the string is empty or contains only white space code points.
lines(): Returns a stream of lines extracted from the string, separated by line terminators.
repeat(int count): Returns a string whose value is the concatenation of this string repeated
count times.
Example:
present, performs the given action with the value, otherwise performs the given empty-based
action.
an Optional describing the value, otherwise returns an Optional produced by the supplying
function.
stream(): If a value is present, returns a sequential Stream containing only that value,
Example:
import java.util.Optional;
System.out.println(opt.isEmpty()); // false
opt.ifPresentOrElse(
value -> System.out.println("Value: " + value),
() -> System.out.println("Value is absent")
);
5. What is the HTTP Client API in Java 11, and how do you use
it?
Answer: The HTTP Client API, introduced in Java 9 as an incubator module and standardized in Java
11, provides a modern and easy-to-use HTTP client. It supports both synchronous and asynchronous
operations, and also HTTP/1.1 and HTTP/2.
Example:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
memory allocation but does not reclaim any memory. It is mainly used for performance testing and
benchmarking where garbage collection overhead needs to be minimized.
Example Usage: To enable the Epsilon Garbage Collector, you can start your Java application with the
following JVM option:
7. How do you read and write strings from/to files in Java 11?
Answer: Java 11 introduced Files.readString() and Files.writeString() methods for reading
Example:
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Answer: Nest-Based Access Control is a feature introduced in Java 11 that improves the access
control mechanism between nested classes. It allows nested classes to access private members of
Example:
class InnerClass {
private String innerField = "Inner";
true if the string is empty or contains only white space code points, otherwise false.
Example:
System.out.println(str1.isBlank()); // true
System.out.println(str2.isBlank()); // false
}
}
Answer: Java 11 improves the Optional class by adding several useful methods:
given action with the value if present, otherwise performs the given empty-based action.
or(Supplier<? extends Optional<? extends T>> supplier): If a value is present, returns
an Optional describing the value, otherwise returns an Optional produced by the supplying
function.
stream(): If a value is present, returns a sequential Stream containing only that value,
Example:
import java.util.Optional;
System.out.println
(opt.isEmpty()); // false
opt.ifPresentOrElse(
value -> System.out.println("Value: " + value),
() -> System.out.println("Value is absent")
);
readability. Understanding these features is crucial for any Java developer, especially when preparing
for an interview. This blog post covered some of the most commonly asked Java 11 interview
questions, helping you prepare effectively for your next interview. By mastering these concepts, you
will be well-equipped to tackle any Java 11-related challenges you may encounter.
How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?
Why Is Java Called Portable? Why Java Does Not Support Multiple Inheritance?
Why Is Main() Method Public Static In Java? (Here’s The Real Truth!)
Can We Overload The Main() Method In Java? (Java Interview Question And Answe
Can We Make The Main() Method Final In Java? (Java Interview Question And Answer)
175K
Subscribers
INTERVIEW JAVA
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Java 21, the latest release in the Java platform, brings numerous new features, enhancements, and
performance improvements. If you're preparing for a job interview that involves Java 21, it's essential
to understand its core concepts, new features, and best practices. This blog post covers some of the
most commonly asked Java 21 interview questions and answers to help you prepare effectively.
Pattern Matching for switch: Enhanced pattern matching capabilities in switch statements.
Sequenced Collections: A new collection type that maintains insertion order.
Virtual Threads (Project Loom): Lightweight threads for better scalability in concurrent
applications.
Record Patterns: Improved pattern matching with records.
String Templates (Preview): Simplified string interpolation for creating formatted strings.
Foreign Function & Memory API: Enhanced support for interfacing with non-Java code and
memory.
Universal Generics (Preview): Enhanced generics that can work with primitives.
Answer: Pattern Matching for a switch in Java 21 extends the switch statement and expression with
pattern matching capabilities. This allows more concise and readable code when working with
Example:
In this example, the switch statement matches the type of the shape variable and binds it to a variable
Answer: Sequenced Collections in Java 21 are a new type of collection that maintains the order of
elements based on their insertion order. They provide methods for accessing elements by their order
Example:
import java.util.SequencedCollection;
import java.util.SequencedHashSet;
Answer: Virtual Threads, introduced as part of Project Loom in Java 21, are lightweight threads that
provide better scalability for concurrent applications. Unlike traditional platform threads, virtual
threads are managed by the Java runtime and can handle a large number of concurrent tasks with
lower overhead.
Example:
5. What are Record Patterns in Java 21, and how are they used?
Answer: Record Patterns in Java 21 enhance pattern matching by allowing patterns to be used with
Answer: String Templates (introduced as a preview feature) simplify string interpolation by allowing
embedded expressions within string literals. This makes it easier to create formatted strings.
Example:
int x = 10;
int y = 20;
String message = STR."The sum of \{x} and \{y} is \{x + y}";
System.out.println(message); // Output: The sum of 10 and 20 is 30
with non-Java code and managing native memory. This API allows Java programs to call native
functions and manipulate native memory safely and efficiently.
Example:
import jdk.incubator.foreign.*;
Answer: Universal Generics (introduced as a preview feature) enhance Java generics to work with both
reference types and primitive types. This allows for more flexible and efficient generic programming.
Example:
Enhanced Pattern Matching: Improved support for pattern matching in various constructs.
Universal Generics: Enhanced generics for both reference and primitive types.
New and Enhanced APIs: Improvements to existing APIs and introduction of new APIs for
21.
3. Update Project Settings: Update your project's settings to use the Java 21 JDK.
4. Refactor Code: Refactor your code to take advantage of new features and improvements in
Java 21.
5. Run Tests: Run your project's tests to ensure compatibility and correctness.
6. Address Deprecations: Address any deprecated APIs or features that have been removed or
changed in Java 21.
<properties>
<java.version>21</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>
Conclusion
Java 21 brings many new features and enhancements that improve the language's expressiveness,
performance, and ease of use. Understanding these new features and how to leverage them in your
projects is crucial for any Java developer. This blog post covered some of the most commonly asked
Java 21 interview questions, helping you prepare effectively for your next interview. By mastering
these concepts, you will be well-equipped to tackle any Java 21-related challenges you may
encounter.
Free Courses
on YouTube
Channel
175K
Subscribers
INTERVIEW JAVA 8
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this article, we will discuss some important and frequently asked Java 8 Interview Questions and
Answers.
YouTube Video
Java 8 Interview Questions and Answers ( Demonstrated with Live Exa…
Exa…
Share
Watch on
Lambda Expressions − lambda expression is a function that can be referenced and passed
around as an object
Method References − Method references are the references that use a function as a parameter
to request a method.
Optional − This class is to provide a type-level solution for representing optional values instead
of using null references.
Default methods − give us the ability to add full implementations in interfaces besides abstract
methods
Stream API − Stream API provides a functional approach to processing collections of objects.
Nashorn, JavaScript Engine − Java-based engine for executing and evaluating JavaScript code
Along with these new features, lots of feature enhancements are done under-the-hood, at both
compiler and JVM levels.
The below diagram shows all the Java 8 features and enhancements.
2. What is a Lambda Expression?
The lambda expression is simply a function without any name. It can even be used as a parameter in a
function. Lambda Expression facilitates functional programming and simplifies development a lot.
The main use of Lambda expression is to provide an implementation for functional interfaces.
For example, Lambda expression provides an implementation for a Printable functional interface
interface Printable {
void print(String msg);
}
Output :
interface StringFunction {
String run(String str);
}
3. Reduced Lines of Code - One of the clear benefits of using lambda expression is that the
amount of code is reduced, we have already seen how easily we can create instances of a
functional interface using lambda expression rather than using an anonymous class.
4. Passing Behaviors into methods - Lambda Expressions enable you to encapsulate a single unit
of behavior and pass it to other code. For example, to other methods or constructors.
interface Addable{
int add(int a,int b);
}
Let's implement the above Addable functional interface using a lambda expression:
Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. A
functional interface can extend another interface only when it does not have any abstract method.
Java 8 provides predefined functional interfaces to deal with functional programming by using
For example:
interface Printable {
void print(String msg);
}
We can define any number of other methods like default methods, static methods.
@FunctionalInterface
interface Sayable{
void say(String msg); // abstract method
}
the more common ones include but are not limited to:
Consumer – it takes one argument and returns no result (represents a side effect)
BiConsumer - it takes two (reference type) input arguments and returns no result
BinaryOperator – it is similar to a BiFunction, taking two arguments and returning a result. The
two arguments and the result are all of the same types
Runnable : use to execute the instances of a class over another thread with no arguments and no
return value.
Callable : use to execute the instances of a class over another thread with no arguments and it
For more on functional interfaces, see the article at Java 8 Functional Interfaces
with Examples.
of lambda expression. Each time when you are using a lambda expression to just referring a method,
you can replace your lambda expression with a method reference.
can become:
Object::toString();
A method reference can be identified by a double colon separating a class or object name and the
String::new;
String::valueOf;
str::toString;
String::toString;
You can read a detailed description of method references with full examples at Java 8 Method
References.
ContainingClass::staticMethodName
containingObject::instanceMethodName
ContainingType::methodName
ClassName::new
You can read a detailed description of method references with full examples at Java 8 Method
References.
perform computations upon those elements. Streams are a core part of Java's functional
Streams can be obtained in various ways from different sources such as collections, arrays, I/O
channels, etc. They don't change the original data structure; they just provide a view of this data
Functional in Nature: An operation on a stream produces a result, but it does not modify the source.
It returns a new stream that contains the result.
Laziness-Seeking: Many stream operations are "lazy," meaning that they do not process elements
until the result is needed.
Possibly Unbounded: Streams can represent sequences that are of an infinite size.
Consumable: The elements of a stream are consumed from the data source only when queried. Once
From an Array:
Using Stream.of():
Objects). Objects).
We add elements to the Collection We can add elements to Stream Object without any prior
object only after it is computed computation. That means Stream objects are computed
completely. on demand.
The Optional class has various utility methods to facilitate code to handle values as 'available' or 'not
The purpose of the Optional class is to provide a type-level solution for representing optional values
Read more about Optional Class with examples at Java 8 Optional Class with Examples.
Read more about Optional Class with examples at Java 8 Optional Class with Examples.
We can use a default method to add new functionality to an interface while maintaining backward
String speedUp();
String slowDown();
Usually, when a new abstract method is added to an interface, all implementing classes will break until
they implement the new abstract method. In Java 8, this problem has been solved by the use of the
default method.
For example, the Collection interface does not have a forEach method declaration. Thus, adding such
Java 8 introduces the default method so that the Collection interface can have a default
implementation of the forEach method without requiring the classes implementing this interface to
implement the same.
Read more about Default Methods with examples at Java 8 Static and Default Methods in
Interface.
We can keep Helper or Utility methods specific to an interface in the same interface rather than
We do not need separate Utility Classes like Collections, Arrays, etc to keep Utility methods.
Clear separation of Responsibilities. That is we do not need one Utility class to keep all Utility
methods of Collection API like Collections etc.
interface Vehicle {
default void print() {
System.out.println("I am a vehicle!");
}
}
class Car implements Vehicle {
public void print() {
Vehicle.super.print();
}
}
interface Vehicle {
static void blowHorn() {
System.out.println("Blowing horn!!!");
}
}
class Car implements Vehicle {
public void print() {
Vehicle.blowHorn();
}
}
How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
Free Courses
on YouTube
Channel
175K
Subscribers
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
Stream API is one of the most powerful features introduced in Java 8. It allows you to work with
collections in a declarative, functional way by chaining operations like filtering, mapping, and
reducing.
In this article, we’ll dive into the top 10 Java Stream API interview questions and answers asked in
2025.
Streams also support lazy evaluation, parallel processing, and method chaining, which makes code
cleaner and faster to execute. For example, if you want to get all employee names earning more than
₹50,000:
employees.stream()
.filter(e -> e.getSalary() > 50000)
.map(Employee::getName)
.collect(Collectors.toList());
1. intermediate operations
2. terminal operations
Intermediate operations return another stream, allowing you to chain more methods. These are lazy,
meaning they don’t execute until a terminal operation is invoked.
Terminal operations end the pipeline and produce a result such as a list, a count, or even just a side
effect. Without a terminal operation, the stream pipeline won’t run at all.
Here is the table that contains differences between Java 8 Stream Intermediate Vs Terminal
Operations:
element itself is a collection or stream, and you want to flatten it into one combined stream.
// List of sentences
List<String> sentences = Arrays.asList("Java Stream", "map vs flatMap", "Core Concepts
System.out.println("Using map():");
System.out.println(mapped); // Output: [[Java, Stream], [map, vs, flatMap], [Core, Co
System.out.println("\nUsing flatMap():");
System.out.println(flatMapped); // Output: [Java, Stream, map, vs, flatMap, Core, Con
}
}
4️⃣ What is the Use of the filter() Method in Streams?
The filter() method is used to keep only those elements that satisfy a given condition. It’s a
powerful way to apply logic directly to a stream without needing an if-condition or manual removal.
For example, if you want only the even numbers from a list, you can write:
This keeps your code readable and focused on the what, not the how.
Set, or Map using collectors provided by the Collectors utility class. It offers flexibility and supports
collect(Collectors.toList()). It creates an unmodifiable list, which is ideal when you just need
operation. You define an identity value and a function, and the stream applies that function
cumulatively to the elements.
It’s great for calculations like summing numbers, multiplying them, or creating comma-separated
strings. For example:
This will return the sum of all the integers in the list.
This improves performance, especially when working with large datasets, because unnecessary
operations can be skipped. For example, this does nothing:
stream.collect(Collectors.toList());
list.stream().sorted().collect(Collectors.toList());
employees.stream()
.sorted(Comparator.comparing(Employee::getSalary))
.collect(Collectors.toList());
For example:
🔟 What are Parallel Streams and When Should You Use Them?
Parallel streams split the data into multiple chunks and process them in parallel using multiple
threads. This can boost performance for large data processing tasks.
You should use parallelStream() when the operations are independent, stateless, and CPU-
intensive. But be cautious—parallel streams may reduce performance for small data sets or IO-bound
tasks.
list.parallelStream()
.map(String::toUpperCase)
.collect(Collectors.toList());
Java provides several ways to create streams depending on your data source. You can create streams
from collections, arrays, individual values, or even from file/data generators.
// 2. From an Array
String[] fruits = {"Apple", "Banana", "Mango"};
Stream<String> stream2 = Arrays.stream(fruits);
// 3. Using Stream.of()
Stream<Integer> stream3 = Stream.of(10, 20, 30);
// 4. Using Stream.builder()
Stream<String> stream4 = Stream.<String>builder()
.add("One").add("Two").add("Three")
.build();
Each method serves a different purpose. For example, Stream.generate() and Stream.iterate()
are best for infinite sequences, while Stream.of() is great for quick static values.
13. What does the Stream map() function do? why you use it?
The map() function is an intermediate function that is used to perform map functional operations in
Java. This means it can transform one type of object into another by applying a function.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
System.out.println(listOfIntegers);
}
}
Output:
[1, 2, 3, 4, 5]
14. What does the Stream filter() method do? when you use it?
Java stream provides a filter() method to filter stream elements on the basis of a given predicate.
This method takes a predicate as an argument and returns a stream consisting of the resulting
elements.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
result.forEach(System.out::println);
}
}
Output:
java
python
Example 2: In this example, we will create a list of products and filter products whose price is greater
than 25k. We display a list of products using the forEach() method.
class Product {
private int id;
private String name;
private float price;
// getters and setters
}
In the above example, we are using the filter() method to filter products whose price is greater
than 25k:
15. What does the Stream flatmap() function do? why you
need it?
The Stream.flatMap() function, as the name suggests, is the combination of a map and a flat
operation. This means you first apply the map function and then flatten the result.
To understand what flattening a stream consists in, consider a structure like [ [1,2,3],[4,5,6],[7,8,9] ]
which has "two levels". It's basically a big List containing three more List. Flattening this means
transforming it in a "one level" structure e.g. [ 1,2,3,4,5,6,7,8,9 ] i.e. just one list.
For example, In the below program, you can see that we have three lists merged into one using a
flatMap() function.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Output:
How To Crack Java Developer Interviews Like A Pro Spring Vs Spring MVC Vs Spring Boot
Java JIT Compiler: Explained In Simple Words What Is JVM, JDK, And JRE?
Why Is Java Called Portable? Why Java Does Not Support Multiple Inheritance?
Why Is Main() Method Public Static In Java? (Here’s The Real Truth!)
Can We Overload The Main() Method In Java? (Java Interview Question And Answe
Free Courses
on YouTube
Channel
175K
Subscribers
INTERVIEW JAVA 8
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this article, we will discuss some important and frequently asked Java Lambda Expressions
Interview Questions and Answers.
A lambda expression is simply a function without any name. It can even be used as a parameter in a
function. Lambda Expression facilitates functional programming and simplifies development a lot.
The main use of Lambda expression is to provide an implementation for functional interfaces.
Parameters: A lambda expression can have zero or more parameters, enclosed in parentheses.
Arrow Token: The arrow token -> separates the parameters from the body of the lambda.
Body: The body of the lambda contains expressions or statements describing the method's
functionality.
Or
Example
@FunctionalInterface
interface MyFunction {
int apply(int x, int y);
}
Lambda expressions in Java are a powerful feature that provides several key benefits:
Conciseness: Lambda expressions allow you to write instances of anonymous classes more concisely.
This makes the code easier to read and maintain.
Functional Programming: Lambda expressions enable functional programming concepts in Java. You
can pass functions as method arguments, return them as values, and perform operations like mapping
and filtering on collections more naturally.
Readability: By reducing boilerplate code, lambda expressions can make the main logic of a program
more apparent. The concise syntax allows for clear expression of the computation or action being
performed.
Parallel Execution Support: Lambdas work well with the Stream API, which supports parallel
execution. This makes it easier to write parallel code, leveraging multicore processors without having
to deal with low-level threading details.
Less Verbose: Unlike anonymous inner classes, lambda expressions are less verbose. You don't need
to name the class, declare the method, or even type the input parameters.
Strong Typing: Lambda expressions are strongly typed. The compiler infers the types of parameters,
return values, and exceptions, which can lead to more robust code.
Scope Flexibility: Lambda expressions have access to final variables or effectively final variables from
Interoperability: Lambdas can be used wherever functional interfaces are expected, providing great
interoperability with existing code, libraries, and frameworks that use functional interfaces.
Parameters: A lambda expression can have zero or more parameters, enclosed in parentheses.
Arrow Token: The arrow token -> separates the parameters from the body of the lambda.
Body: The body of the lambda contains expressions or statements describing the method's functionality.
Or
interface Addable{
int add(int a,int b);
}
Let's implement the above Addable functional interface using a lambda expression:
B.
() -> return;
C.
(int i) -> i;
D.
Explanation
Option C is valid. The body doesn't need to use the return keyword if it only has one statement.
Creating a thread using a lambda expression in Java is straightforward and concise. You can define the
task you want the thread to perform as a lambda and pass it to the Thread constructor.
Here's an example:
Or you can simplify it further by passing the lambda expression directly to the Thread constructor:
Either way, this code creates a new thread and runs a simple loop inside it, printing a message five
times. Lambda expressions make this code cleaner and more concise by removing the need to create
A lambda expressions provide a compact and expressive way to create instances of functional
interfaces, implementing the interface's single abstract method with the body of the lambda. This
relationship promotes a more functional programming style in Java, allowing for more concise and
readable code.
For example, Lambda expression provides an implementation for a Printable functional interface:
interface Printable {
void print(String msg);
}
Output :
If the abstract method takes no parameters and returns no value, the lambda expression can be
If the abstract method takes a single parameter, you can omit the parentheses around the parameter,
and the type can be inferred:
s -> System.out.println(s);
Multiple Parameters:
If the abstract method takes multiple parameters, you must include parentheses around the
(a, b) -> a + b;
(int a, int b) -> a + b;
Return Statement:
If the body of the lambda consists of a single expression that returns a value, you can write it directly:
If the body consists of multiple statements, you must include braces and use a return statement:
(int a, int b) -> {
int sum = a + b;
return sum;
};
If the abstract method takes no parameters but returns a value, you can write it like this:
() -> 42;
You can also access local variables from the enclosing scope within the lambda expression:
int factor = 2;
(int a) -> a * factor;
anonymous classes are more verbose. Lambdas don’t create a separate class file or object.
This means the variable should not be modified after it’s used inside the lambda.
Example:
String prefix = "Hello ";
Consumer<String> c = name -> System.out.println(prefix + name);
c.accept("Ravi");
If you try to change prefix later, the compiler will throw an error.
Both lambda expressions and method references are used to provide implementations for functional
interfaces. A method reference is a shorter way to write certain lambdas that call existing methods.
175K
Subscribers
INTERVIEW JAVA 8
🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my
Udemy courses are real-time and project oriented courses.
▶️For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh
Fadatare on YouTube
In this article, we will discuss some important and frequently asked Java 8 Functional Interface
Interview Questions and Answers.
interfaces have only one abstract method, they can represent a single functionality that can be
implemented by a lambda expression, a method reference, or an anonymous class.
Introduced in Java 8, functional interfaces are a key feature that enables functional programming
concepts within the language. They allow you to use simple expressions to represent instances of
anonymous classes that implement the interface, making code more concise and readable.
method is allowed.
@FunctionalInterface Annotation: While it's not required, it's good practice to annotate a functional
interface with @FunctionalInterface. This annotation ensures that the interface meets the
requirements of a functional interface at compile time. If you try to add a second abstract method, the
compiler will raise an error.
Built-in Functional Interfaces: Java 8 introduced several built-in functional interfaces within the
expressions to provide the implementation of that method directly within the code where it's needed.
Example:
@FunctionalInterface
public interface MyFunctionalInterface {
void execute();
}
What is @FunctionalInterface?
functional interface. While it is not mandatory to use this annotation when defining a functional
interface, it's a good practice because it makes the intention clear and allows the compiler to generate
an error if the annotated interface does not satisfy the conditions of a functional interface.
Having more or fewer abstract methods will violate the functional interface contract.
Any Number of Default and Static Methods: You can have any number of default or static methods
in the functional interface.
Inheritance: A functional interface can extend another interface only if it does not have any abstract
method itself.
@FunctionalInterface
interface MyFunctionalInterface {
// Single abstract method
void execute();
// Default method
default void defaultMethod() {
System.out.println("Default method");
}
// Static method
static void staticMethod() {
System.out.println("Static method");
}
}
the more common ones include but are not limited to:
1. Function<T, R>: Represents a function that takes an argument of type T and returns a result of
type R.
2. Consumer<T>: Represents an operation that takes a single input argument of type T and
returns no result (performs a side effect).
3. Supplier<T>: Represents a supplier of results, taking no arguments but providing a result of
type T.
4. Predicate<T>: Represents a boolean-valued function of one argument of type T. Commonly
used for filtering or matching.
5. UnaryOperator<T>: Represents a function that takes a single argument of type T and returns a
result of the same type. It extends Function<T, T>.
6. BinaryOperator<T>: Represents a function that takes two arguments of type T and returns a
result of the same type. It extends BiFunction<T, T, T>.
7. BiFunction<T, U, R>: Represents a function that takes two arguments of types T and U and
returns a result of type R.
8. BiConsumer<T, U>: Represents an operation that takes two input arguments of types T and U
These functional interfaces are part of the java.util.function package, and they can be used with
lambda expressions, method references, or anonymous inner classes. They greatly enhance the ability
to write concise and functional-style code in Java.
Normal Interface:
Abstract Methods: A normal interface can have more than one abstract method. There are no
Static and Default Methods: It may contain static methods and default methods with
implementations.
Purpose: A normal interface serves the traditional role of defining a contract that implementing
classes must follow. It's used for multiple inheritance and polymorphism.
Usage with Lambda Expressions: You cannot use normal interfaces (with more than one abstract
method) with lambda expressions.
Functional Interface:
Abstract Methods: A functional interface has exactly one abstract method. This abstract method is
Static and Default Methods: Like normal interfaces, functional interfaces can also contain static and
Purpose: Functional interfaces are designed to facilitate functional programming in Java, allowing
methods to be used as first-class citizens, passed as arguments, and returned as values.
Usage with Lambda Expressions: Functional interfaces can be implemented using lambda
expressions, providing a concise way to implement the single abstract method.
@FunctionalInterface. This annotation ensures that the interface will not compile if more than one
and returns an object (object of type R). The argument and output can be of different types.
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
Example:
Output:
expression.
The Predicate interface represents an operation that takes a single input and returns a boolean
value.
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
}
Example:
System.out.println(predicate.test(10));
Output:
true
Read more at Java 8 Predicate interface Example
@FunctionalInterface
public interface Consumer < T > {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
Example:
Output:
Ramesh
returns a result.
Example:
Output:
2020-04-30T11:32:51.628
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u); // Other default and static methods
// ...
}
Example:
BiFunction < Integer, Integer, Integer > substraction = (t, u) -> (t - u);
BiFunction < Integer, Integer, Integer > multiplication = (t, u) -> (t * u);
BiFunction < Integer, Integer, Integer > division = (t, u) -> (t / u);
System.out.println(biFunction.apply(10, 20));
System.out.println(substraction.apply(200, 100));
System.out.println(multiplication.apply(200, 100));
System.out.println(division.apply(200, 100));
Output:
30
900
20000
2