JavaAndSpringKnowledgeBoost May2026
JavaAndSpringKnowledgeBoost May2026
1
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Latest Update:
5th May 2026: You can find at the bottom of the page.
2
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Table of Contents
1 Why datatypes are important in Java? ..................................................................... 20
2 What is reference type in java? ................................................................................ 21
3 In how many ways we can create the object? .......................................................... 21
4 Explain about 4 pillars of Object-oriented programming (OOPS) (Frequent Question).
22
5 How is abstraction different from encapsulation? .................................................... 24
6 Questions on Encapsulation? ................................................................................... 25
7 Questions on Inheritance? ....................................................................................... 25
8 What is constructor in java? ..................................................................................... 26
9 Difference between == and .equals() in Java ............................................................ 28
10 Is Java Purely Object-Oriented? ............................................................................... 30
11 Difference between final, finally, and finalize()? ....................................................... 30
12 Is Java pass-by-value or pass-by-reference? ............................................................. 31
13 What is immutability, how to achieve it? ................................................................. 32
14 Why String is immutable in Java? ............................................................................. 33
15 What is Object class in java and tell its methods? .................................................... 34
16 Deep Copy vs Shallow Copy? ................................................................................... 35
17 Explain the difference between String, StringBuilder, and StringBuffer. .................... 36
18 What are Access Modifiers in Java? ......................................................................... 37
19 What are Wrapper Classes in Java and Why Do We Need Them? ............................. 38
20 What is Autoboxing and Unboxing in Java? .............................................................. 39
21 What is Type casting? .............................................................................................. 40
22 What is a static keyword in Java (Commonly asked Question)? ................................ 42
23 What are Nested Classes? ........................................................................................ 44
24 What is the difference between method overloading and method overriding?
(Commonly asked question) ................................................................................................ 46
25 What are the rules for overriding a method in Java? ................................................ 47
26 What is Shadowing in java and its types? ................................................................. 49
27 What are super and this in Java? How are they used? .............................................. 50
28 Explain about Abstract classes in Java ...................................................................... 52
4
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
5
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
6
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
7
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
122 Output-Based 16: Passing reference of the array’s copy. ........................................ 147
123 Output-Based 17: Final variable. ............................................................................ 148
124 Output-Based 18: Final array. ................................................................................. 148
125 Output-Based 19: Final Object. .............................................................................. 148
126 Output-Based 20: Multiple Exceptions. .................................................................. 149
127 Output-Based 21: Try with return and finally. ......................................................... 149
128 Output-Based 22: Try and Finally with returns. ...................................................... 149
129 Output-Based 23: Execution flow with static .......................................................... 150
130 Output-Based 24: Execution flow with instance. .................................................... 150
131 Output-Based 25: Overriding: Method overriding basics. ...................................... 151
132 Output-Based 26: Overriding: Variable hiding. ...................................................... 152
133 Output-Based 27: Overriding: Constructor Execution Order. ................................. 152
134 Output-Based 28: Overriding: Static method hiding. ............................................. 153
135 Output-Based 29: Overriding: Accessing Child-Specific Method. .......................... 153
136 Output-Based 30: String Concatenation. ............................................................... 154
137 Output-Based 31: Overriding: Type Casting 1. ....................................................... 154
138 Output-Based 32: Overriding: Type Casting 2. ....................................................... 155
139 Output-Based 33: Overriding: Field Access. .......................................................... 155
140 Output-Based 34: Overriding: Private Method in Parent. ...................................... 156
141 Output-Based 35: Overriding: Protected Method Access ...................................... 156
142 Output-Based 36: Overriding: Parent public, child private ..................................... 157
143 Output-Based 37: Overriding: Checked Exceptions ................................................ 158
144 Output-Based 38: Overriding: Un-Checked Exceptions .......................................... 158
145 Output-Based 40: Overriding: Method Call in Constructor .................................... 159
146 Output-Based 41: Overriding: Method Call in Constructor with static ................... 159
147 Output-Based 42: Interface Default Method vs Class Method ................................ 160
148 Output-Based 43: Overriding: Diamond Problem (Interface) ................................. 161
149 Output-Based 44: Abstract Class: Main Method ..................................................... 161
150 Output-Based 45: Abstract Class: Private Method .................................................. 162
151 Output-Based 46: Abstract Class: Multiple abstract classes in chain ....................... 162
152 Output-Based 47: Overloading: Type Promotion .................................................... 162
153 Output-Based 48: Overloading: With Varargs vs Exact Match ................................. 163
8
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
9
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
10
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
11
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
248 Streams 24: Most Repeated Number in a given list. .............................................. 212
249 Streams 25: Frequency of words or count of each word in a String ....................... 212
250 Streams 26-35: Scenario based questions on Student Data ................................... 213
251 Streams 36-45: Scenario based questions on Employee Data ................................ 213
252 Stream 46-50: Scenario based questions on City Data ........................................... 214
253 Spring 1: What is Spring boot? .............................................................................. 214
254 Spring 2: What are the advantages of Spring boot? ............................................... 215
255 Spring 3: What are embedded containers / servers in Spring and what is the default
one? how to add Jetty for example? .................................................................................. 215
256 Spring 4: Difference between Spring and Spring Boot?.......................................... 216
257 Spring 5: Explain Spring MVC architecture? ........................................................... 217
258 Spring 6: What is @SpringBootApplication? .......................................................... 218
259 Spring 7: What is Dependency Injection? .............................................................. 218
260 Spring 8: What is IOC Container? .......................................................................... 219
261 Spring 9: What is the difference between @Component, @Service, and
@Repository? ................................................................................................................... 221
262 Spring 10: What is [Link] file? ...................................................... 223
263 Spring 11: What are Spring boot starters? ............................................................. 224
264 Spring 12: How many ways dependency injection can be done or Types of
Dependency Injection? ...................................................................................................... 224
265 Spring 13: What do you mean by Annotation-based container configuration? ....... 226
266 Spring 14: Explain about @Autowired? .................................................................. 226
267 Spring 15: Explain about @Qualifier and @Primary? ............................................. 227
268 Spring 16: Difference between [Link] vs [Link]? ............. 228
269 Spring 17: What is the use of @Value / How to load config values dynamically? .... 229
270 Spring 18: What is the use of @ConfigurationProperties / How to load config values
dynamically? ..................................................................................................................... 230
271 Spring 19: How do profiles work in Spring boot, Explain about @Profile? .............. 230
272 Spring 20: How spring auto configuration works internally? ................................... 231
273 Spring 21: Difference between @Bean vs @Configuration ..................................... 233
274 Spring 22: Difference between @Bean vs @Component ........................................ 234
275 Spring 23: What is Spring Bean .............................................................................. 235
276 Spring 24: What are bean scopes? ......................................................................... 236
12
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
277 Spring 25: What is the bean life cycle? ................................................................... 238
278 Spring 26: Can we create beans conditionally, if yes how? ..................................... 240
279 Spring 27: How does @Conditional works internally? ............................................ 242
280 Spring 28: Difference between CommandLineRunner and ApplicationRunner? ..... 242
281 Spring 29: How to handle Circular dependencies? ................................................. 244
282 Spring 30: What is eager loading and lazy loading of beans?? ................................ 245
283 Spring 31: What is Dispatcher Servlet?................................................................... 246
284 Spring 32: How embedded server works in Spring boot? ....................................... 247
285 Spring 33: What is ORM? ....................................................................................... 248
286 Spring 34: What is Hibernate and how it works? .................................................... 249
287 Spring 35: What is JPA and how does it different from Hibernate? ........................ 249
288 Spring 36: JDBC vs Hibernate vs JPA?..................................................................... 252
289 Spring 37: How do you use @Entity, @Table, @Column in JPA? ............................ 253
290 Spring 38: What are best practices or rules while creating the Entity? .................. 254
291 Spring 39: What are the different types of relationships in JPA and explain
@OneToOne with example ................................................................................................ 255
292 Spring 40: Explain @OneToMany or @ManytoOne with example ......................... 257
293 Spring 41: Explain @ManytoMany with example .................................................. 258
294 Spring 42: What is cascading in JPA and when would you use it? .......................... 259
295 Spring 43: How does eager loading and lazy loading works in JPA? ....................... 260
296 Spring 44: Explain Repositories, like CrudRepository, JpaRepository, and
PagingAndSortingRepository? ........................................................................................... 262
297 Spring 45: What is JPQL and how does it different from HQL? ............................... 263
298 Spring 46: What is @Query (Custom Queries) and why should we use them?? ..... 264
299 Spring 47: What is @NamedQuery and @NamedNativeQuery? ............................ 265
300 Spring 48: What is the use of @Transactional?...................................................... 266
301 Spring 49: What is propagation in Transaction? ..................................................... 269
302 Spring 50: How transaction works under the hood? .............................................. 271
303 Spring 51: What is N+1 problem how do you fix it? ............................................... 273
304 Spring 52: Difference Between JOIN and JOIN FETCH? .......................................... 273
305 Spring 53: How does locking works in Spring JPA? ................................................. 274
306 Spring 54: Explain JPA Architecture? ..................................................................... 276
13
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
14
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
339 Spring 88: How to create Custom Endpoint in Actuator? ....................................... 311
340 Spring 89: How to secure Actuator endpoints and why to secure? ........................ 312
341 Spring 90: What is AOP? ....................................................................................... 313
342 Spring 91: What are the core components of AOP?............................................... 314
343 Spring 92: How proxy works in AOP?..................................................................... 316
344 Spring 93: Which classes or methods in Spring cannot be declared as final, and
why?? 317
345 Spring 94: What is Self-Invocation Problem? ......................................................... 318
346 Spring 95: How to do Scheduling in Spring boot? .................................................. 319
347 Spring 96: What is the difference between fixedDelay and fixedRate? .................. 320
348 Spring 97: How can you make tasks run in parallel? .............................................. 320
349 Spring 98: How can we handle scheduled task failures? ........................................ 321
350 Spring 99: How to run a task in the background in Spring boot? ........................... 322
351 Spring 100: How @Async works behind the scenes? ............................................. 323
352 Spring 101: Can you run Database transactional tasks in Async? ........................... 325
353 Spring 102: How cache works in spring boot? ....................................................... 325
354 Spring 103: How @cachable works? ..................................................................... 325
355 Spring 104: What is the importance of the key while caching? .............................. 326
356 Spring 105 Can you cache based on the condition? ............................................... 326
357 Spring 106: How to update the cache? .................................................................. 326
358 Spring 107: How to delete the cache? ................................................................... 327
359 Spring 108: How cache work behind the scenes? .................................................. 327
360 Spring 109: How CocurrentMapCacheManager works? ........................................ 327
361 Spring 110: What is proxy and how does it work Spring? ...................................... 327
362 Spring 111: How a CGLIB Proxy works with @Bean? ............................................. 329
363 Spring 112: What is filter in Spring boot and how it will used? .............................. 329
364 Spring 113: How do you create a custom filter? .................................................... 330
365 Spring 114: What is interceptor and its uses?........................................................ 331
366 Spring 115: How to create an Interceptor? ............................................................ 332
367 Spring 116: Difference between Filter and Interceptor? ........................................ 333
368 Spring 117: Have you written any custom Annotation, if yes how you have written it?
334
15
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
16
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
398 Rest 17: How do you validate the Request from client in Spring boot? .................. 370
399 Rest 18: How to create custom validators in spring? ............................................. 371
400 Rest 19: How do you implement caching in REST APIs? ......................................... 373
401 Rest 20: How can you handle rate limiting in REST API? ........................................ 374
402 Rest 21: Rate limiting vs API throttling? ................................................................. 374
403 Rest 22: What are different types of authentications used in REST APIs?............... 374
404 Rest 23: Difference between URI and URL? ........................................................... 374
405 Rest 24: How do you implement pagination in REST API? ...................................... 375
406 Rest 25: What is the difference between synchronous and asynchronous
communication in RESTful web services? .......................................................................... 375
407 Rest 26: What are the best practices while designing the REST API? ..................... 375
408 Rest 27: How do you document the APIs and their details?................................... 376
409 Rest 28: SOAP VS REST? ........................................................................................ 376
410 Rest 29: How do you invoke the other APIs or Inter-service communication in a
microservice in Spring? ..................................................................................................... 377
411 Rest 30: How do you implement search functionality? .......................................... 378
412 Spring Scenario 1: Get by User ID or Email. ........................................................... 378
413 Spring Scenario 2: Debug the slow API. ................................................................. 379
414 Spring Scenario 3: Performance optimization. ....................................................... 380
415 Spring Scenario 4: DB Migrations .......................................................................... 380
416 Spring Scenario 5: File upload and download ........................................................ 381
417 Spring Scenario 6: Asynchronous Processing ......................................................... 382
418 Spring Scenario 7: Handling Configuration ............................................................ 383
419 Spring Scenario 8: Apply configuration without reboot ......................................... 384
420 Spring Scenario 9: Large file handling. ................................................................... 386
421 Spring Scenario 10: Caching. ................................................................................. 387
422 Spring Scenario 11: Validations. ............................................................................ 388
423 Spring Scenario 12: Scheduling the task. ............................................................... 389
424 Spring Scenario 13: Dependency Injection. ........................................................... 390
425 Spring Scenario 14: Custom Bean. ......................................................................... 390
426 Spring Scenario 15: Inject bean on condition. ....................................................... 391
427 Spring Scenario 16: Inject bean on multiple conditions. ........................................ 392
17
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
428 Spring Scenario 17: Dynamic bean selection, based on parameter from client. ..... 393
429 Spring Scenario 18: Load initial cache data. ........................................................... 394
430 Spring Scenario 19: Logging in Spring boot............................................................ 395
431 Spring Scenario 20: Monitoring the Spring application .......................................... 396
432 Spring Scenario 21: Post idempotency .................................................................. 396
433 Spring Scenario 22: Custom Annotation + Interceptor ........................................... 397
434 Spring Scenario 23: Rate Limiting .......................................................................... 399
435 Spring Scenario 24: Custom Query method ........................................................... 400
436 Spring Scenario 25: Custom Query ........................................................................ 400
437 Spring Scenario 26: Lazy vs Eager / N+1 problem .................................................. 401
438 Spring Scenario 27: save() or saveAll() ................................................................... 402
439 Spring Scenario 28: Partial Update ........................................................................ 403
440 Spring Scenario 29: Soft Deletes............................................................................ 404
441 Spring Scenario 30: Auditing ................................................................................. 405
442 Spring Scenario 31: Handling null values ............................................................... 406
443 Spring Scenario 32: Transaction rollback failed ...................................................... 407
444 Spring Scenario 33: Read-only transaction ............................................................ 408
445 Spring Scenario 34: Event driven ........................................................................... 408
446 Spring Scenario 35: Improve initial loading time or Cold Start Optimization
Techniques ........................................................................................................................ 408
447 Spring Scenario 36: Public some APIs .................................................................... 409
448 Spring Scenario 37: Only ADMIN operation ........................................................... 410
449 Spring Scenario 38: Monitoring the Application .................................................... 411
450 Spring Scenario 39: Inter-service communication .................................................. 411
451 Spring Scenario 40: Searching Million Records ...................................................... 412
452 Spring Scenario 41: Process Million Records (NOTE: It is about processing not
searching) ......................................................................................................................... 413
453 Spring Scenario 42: OutOfMemory due to huge data. ........................................... 414
454 Spring Scenario 43: Writing to DB by two threads ................................................. 415
455 Spring Scenario 44: Parallel API call ....................................................................... 416
456 Spring Scenario 45: Secure the App....................................................................... 417
457 Spring Scenario 46: Prevent SQL Injection ............................................................. 418
18
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Java course reference link: (1) Java Tutorial For beginners - YouTube
Java 8 reference link (In depth):
Lambda Expressions in Java 8 | Java 8 Features | Crash Course ✅
Spring boot course reference link:
To learn Spring on a high level go through this playlist: Spring 6 and Spring Boot Tutorial for
Beginners - YouTube It contains, Spring boot, Web, JPA and security.
19
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
2. To catch errors
Java checks the code at compile time.
If we try to assign a number to a String, it throws an error before the program runs.
1. What would happen if you try to add a String and an int in Java? Why?
If we add a String and an int, Java converts the int to a String and adds.
"Age" + 25 gives "Age25".
2. Is it good use String isActive = "true"; instead of boolean isActive = true?
Using String isActive = "true" instead of a boolean is not ideal, it can lead to bugs since
any string can be assigned, not just true or false.
3. Is Java strongly typed language?
Yes, Java is a strongly typed language. Variables must be declared with a specific data
type. Before a variable can be used, its data type (e.g., int, String, double) must be explicitly
specified during declaration.
20
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
2. Using clone():
class Car implements Cloneable {
int speed = 100;
public Object clone() throws CloneNotSupportedException {
return [Link]();
}
}
Car car1 = new Car();
Car car2 = (Car) [Link](); // Constructor NOT called
Indirect Questions
21
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class InheritanceDemo {
public static void main(String[] args) {
Dog dog = new Dog();
[Link](); // inherited from Animal
[Link](); // defined in Dog
}
}
Interview Tip:
Always mention Java supports single inheritance with classes, but multiple inheritance via
interfaces.
2. Encapsulation
Encapsulation is about protecting data by wrapping variables (fields) and code (methods)
together in a class.
We restrict direct access to fields using access modifiers and expose behaviour through
methods.
class Student {
private int marks; // can't access directly from outside
22
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class EncapsulationDemo {
public static void main(String[] args) {
Student s = new Student();
[Link](85);
[Link]("Marks: " + [Link]());
}
}
Interview Tip:
Use private fields + public getters/setters to achieve Encapsulation.
3. Polymorphism
Polymorphism means "many forms" , the same object can behave differently based on context.
It is of two types: Compile-time (Method Overloading) and Runtime (Method Overriding).
class Shape {
void draw() {
[Link]("Drawing a shape");
}
}
class PolymorphismDemo {
public static void main(String[] args) {
Shape s1 = new Circle(); // Upcasting
[Link](); // Calls Circle’s overridden draw()
}
}
Interview Tip:
Always say: Overriding = Runtime Polymorphism, Overloading = Compile-time Polymorphism.
Runtime polymorphism (also called dynamic polymorphism) means the method that gets
executed is determined at runtime, not compile time.
4. Abstraction
Abstraction means hiding internal implementation and showing only essential details to the user.
It is implemented using abstract classes or interfaces.
abstract class Vehicle {
abstract void start();
23
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class AbstractionDemo {
public static void main(String[] args) {
Vehicle v = new Bike();
[Link]();
}
}
Interview Tip:
Always mention that interfaces provide 100% abstraction (prior to Java 8), and abstract classes
can have both abstract and concrete methods.
In code: Interfaces and abstract classes are common ways to apply abstraction.
Encapsulation focuses on hiding data and protecting it from direct access. It keeps the internal
state safe and only exposes what is necessary.
Example:
class BankAccount {
private double balance;
In code: We use private variables and public getters or setters to achieve encapsulation.
24
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
6 Questions on Encapsulation?
1. How to achieve encapsulation in Java?
Encapsulation is done by keeping class variables private and exposing public getter and setter
methods. This restricts direct access to fields from outside the class.
2. Why is encapsulation needed?
Encapsulation helps protect data from unwanted changes. It keeps data and the methods that
work on it in one place and controls who can access or change it. This makes the code safer and
easier to manage.
3. Why do we make global variables private?
We make them private to prevent direct access or modification from outside the class. If fields
are public, anyone can change them anytime, which can break the logic.
4. What is the role of setters and getters in encapsulation?
Setters and getters help us to control how someone uses the class's data.
A getter allows others to see the value, but not change it directly.
A setter allows to change it, but only the way we want.
5. If no encapsulation is implemented, what consequences may occur?
Without encapsulation, any part of the program can change the data. This can cause mistakes
that are hard to find. One small change can break other parts of the program
6. Can you provide an example that illustrates the concept of encapsulation?
Imagine a BankAccount class with a private balance. We use deposit() and withdraw() methods
to change it. Nobody can change the balance directly. they must go through these methods,
which can include checks to prevent negative balances. That is a clean example of encapsulation.
7. How does encapsulation contribute to code organization and maintenance?
Encapsulation helps to keep each part of the code separate. Every class handles its own data
and work. So, we can change one part without worrying about breaking others. It also makes it
easier for someone new to understand and work on just one part without looking at everything.
8. In what ways does encapsulation enhance code security?
Encapsulation hides important data so that other parts of the program can’t touch it directly.
Only safe actions are allowed. This protects the data from being changed in the wrong way,
either by mistake or on purpose. It is like putting a lock on something valuable so only the right
key can open it.
9. What are the potential drawbacks of overusing encapsulation in a program?
If we use encapsulation too much, the code can get bigger and more complicated. We might
add getters and setters even when they aren’t needed. It is better to use encapsulation only
when it really helps.
7 Questions on Inheritance?
1. Why do we need inheritance in programming?
25
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Inheritance helps reuse code and organize things better. Instead of writing the same features
again and again, we just inherit them from a base class.
9. Why does Java allow multiple interfaces but not multiple classes?
Java allows a class to use many interfaces, but not many classes. That is because interfaces
only have method names, not real code. So even if two interfaces have the same method, it is
not a problem, the class that implements these interfaces writes its own version.
But classes have real code. If two classes have the same method with different logic, Java
won’t know which one to use. This creates confusion. So, Java allow a class extend only one
class.
26
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Points to remember:
It has no return type (not even void).
Its name is exactly the same as the class.
We can have multiple constructors in the same class (this is called constructor
overloading).
class Car {
String model;
// Constructor
Car(String carModel) {
model = carModel;
}
}
When new Car("Maruthi") is called, Java automatically runs the constructor, sets model = "
Maruthi "
Indirect Questions:
1. What is difference of constructor and a method?
A constructor is used to initialize an object when it is created, while a method is used to
perform actions after the object exists. Constructors don't have a return type and their name
must match the class name. Methods can have return types and any name. Basically,
constructors set up the object; methods operate on it.
2. Can a class have multiple constructors?
Yes, Java allows constructor overloading, so a class can have multiple constructors with
different parameter lists. This helps in creating objects in different ways. For example, one
constructor might set default values, and another might accept values from the user. The
compiler figures out which one to call based on the arguments passed.
3. Explain the difference between a default constructor and a parameterized constructor
A default constructor has no parameters and sets fields to default values. It is either defined
by us or provided automatically if no other constructors are defined. A parameterized
constructor takes arguments and can initialize an object with specific vales.
3. Can a constructor have a return type?
No, constructors can’t have any return type, not even void. If you try to give it a return type,
Java treats it as a regular method, not a constructor. Constructor’s return type is class type.
27
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
28
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Interview Tip: Output based questions can be asked on this topic. Prepare for them. Will discuss
in output-based questions section.
Related Questions:
1. What are different ways to create a String in Java?
We can create strings using literals like
String s = "hello"; -> this goes into the string pool.
Using new keyword:
String s = new String("hello"); -> this creates a new object in heap.
We can also build strings dynamically using StringBuilder or StringBuffer.
String s3 = new StringBuilder().append("he").append("llo").toString();
From a character array using new String(char[]):
char[] arr = {'h','i'}; String s4 = new String(arr);
2. What is the String Constant Pool?
It is a special memory area in Java where string literals are stored.
When we write String a = "hello"; and then String b = "hello";, both point to the same object in
the pool so no duplicate objects created.
It is to optimize memory since strings are used a lot and are immutable, so reusing the string
is safe and efficient.
3. What does intern() do, and why is it useful?
The intern() method Puts the string in the pool if it is not already there, or gives the pooled
version. So even if we create a string using new, we can save the string in the pool.
Example:
String s1 = new String("hello");// Creates a new string object in the heap
String s2 = [Link](); // Adds "hello" to the pool and returns a reference
to it
String s3 = "hello"; // Directly references the "hello" in the string pool
29
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
finally is the block of code in a try-catch that always runs, no matter what, even if there
is an exception.
try {
int x = 10 / 0;
} catch (Exception e) {
[Link]("Error!");
} finally {
[Link]("Always runs");
}
finalize() is a method from the Object class that gets called just before the object is
garbage collected. But honestly, no one really uses it anymore, it is considered outdated
and unreliable.
protected void finalize() throws Throwable {
Indirect Questions:
1. Can we combine abstract and final keywords in a class declaration?
No, we can’t use abstract and final together in a class. abstract means the class should be
extended, while final means it can’t be extended.
2. Can we declare a variable as abstract?
30
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
For objects, Java still passes by value, but that value is the reference to the object.
So, the method gets a copy of the reference. We can use it to change the object's
internal state (like modifying a field).
For objects: We are sending a copy of the reference, so inside the method we can
change the object’s internals
class Dog {
String name;
}
void renameDog(Dog d) {
[Link] = "Bruno";
}
Dog myDog = new Dog();
[Link] = "Max";
renameDog(myDog);
[Link]([Link]); // Bruno
31
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference: Java: Pass By Value Or Pass By Reference | by Ananya Sen | Nov, 2020 | Medium |
Medium
32
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
33
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Thread safety
Since Strings cannot be changed, multiple threads can use the same String object
without any issue.
No need for extra synchronization. This makes programs safer and faster.
34
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Deep Copy:
A deep copy makes a new object and also makes new copies of everything inside it.
If it is a simple value (like an int), it copies the value itself.
If it is a complex object, it creates a new object in memory with the same data, so nothing is
shared between the original and the copy.
We can achieve deep copy using “cloneable” marker interface.
Code link: JavaSamples/[Link] at main · CodingLyf-
Fullstack/JavaSamples
Explanation: In the below code, we have a Person object that contains name as a String and
Address as another object.
35
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When we make a deep copy of the person object, both the name field and the Address object
are copied independently.
So, when we change the copied person’s name, it won’t affect the original person’s name, and
when we change the copied person’s address, it also won’t affect the original person’s address
// Print results
[Link]("Original Person: " + originalPerson);
[Link]("Deep Copy Person: " + deepCopyPerson);
}
}
36
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Thread-safe: All methods are synchronized, so it is safe when multiple threads are using
it.
Performance: Slower than StringBuilder. Because of thread-safety (synchronization), it is
a bit slower even if we are not using multiple threads.
Use when: We want to change strings in a multi-threaded program where thread safety
is important.
Additional Question:
1. Is it good to use StringBuffer in Single threaded application?
No, because it adds overhead of Synchronization which slows down the process.
Access modifiers are keywords in Java that control who can access a class, method, or
variable.
We can think of them like doors, they decide whether something is open to all, only to the
family, or just to yourself.
Java has four access modifiers:
1. public
Means "open to all"
Any class, anywhere in the project, can access it.
Use it, when we want to make the method or variable available everywhere.
2. private
Means "only for me"
The variable or method can only be accessed within the same class.
If we try to use age or displayAge() from another class, we will get a compile-time error.
Use it, when we want to hide data or logic from outside , for encapsulation.
3. protected
Means "family access"
Can be accessed:
o Within the same class
o In other classes in the same package
o In subclasses (child classes) even if they are in different packages
Use when: We want to share with related classes (like inheritance), but not with the
whole world.
37
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
18.1 What are Wrapper Classes in Java and Why Do We Ned Them?
In Java, primitive types like int, char, float are not objects. But Java is an object-oriented
language, and sometimes, especially while working with collections or frameworks, we need
everything to be an object.
That is where wrapper classes come in.
Wrapper classes are object representations of the primitive data types
Primitive Wrapper Class
int Integer
char Character
float Float
double Double
boolean Boolean
long Long
short Short
byte Byte
int a = 10; // primitive
[Link](10);
38
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
int x = [Link](s);
This method parseInt() is available only in the Integer class, not with primitive types.
Again, Java internally calls [Link](), but we don’t need to write that.
39
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
40
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class Animal {
void makeSound() {
[Link]("Animal sound");
}
}
[Link](); // Allowed
// [Link](); // Not allowed – Animal reference can't access Dog
methods
41
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Counter() {
count++;
[Link](count);
}
}
public class Main {
public static void main(String[] args) {
new Counter(); // prints 1
new Counter(); // prints 2
new Counter(); // prints 3
}
}
2. Static Methods
Static methods belong to the class rather than any particular instance. They can access static
variables directly but cannot access instance variables or methods.
In every Java program, we have declared the main method static. It is because to run the
program the JVM should be able to invoke the main method during the initial phase where no
objects exist in the memory.
When to Use:
When we want a method that can be called without creating an instance of the class.
For utility or helper methods that don't require any object state.
class MathUtils {
42
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Static Blocks
Static blocks are used for static initialization of a class. They run when the class is loaded.
When to Use:
To initialize static variables or perform operations that need to happen once when the
class is loaded
The static block is executed only once when the class is loaded in memory. The class is loaded if
either the object of the class is requested in code or the static members are requested in code.
A class can have multiple static blocks and each static block is executed in the same sequence in
which they have been written in a program.
class Test {
// static variable
static int age;
// static block
static {
age = 23;
}
}
Reference: Java Static Keyword (With Examples)
Indirect Questions:
43
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
44
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class Engine {
void start() {
[Link]("Starting engine of " + model); //
accessing private outer field
}
}
}
45
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class OverloadingDemo {
public static void main(String[] args) {
Calculator calc = new Calculator();
[Link]([Link](10, 20)); // calls int, int
[Link]([Link](5.5, 4.5)); // calls double, double
[Link]([Link](1, 2, 3)); // calls int, int, int
}
}
Key Point:
- All overloaded methods must differ in parameters.
- Return type alone is NOT enough to overload.
Output based questions can be asked on rules of Method overriding. Check the next question for
rules.
class Animal {
void speak() {
[Link]("Animal speaks");
}
}
46
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
class OverridingDemo {
public static void main(String[] args) {
Animal animal = new Cat(); // Upcasting
[Link](); // Calls Cat’s speak() method
}
}
Key Rules:
- Method name and parameters must match exactly. Return type must be the same or a subclass
type (Covariant type).
- Access modifier cannot be more restrictive. (Refer Next question for these rules).
- We can use @Override annotation to help the compiler.
Interview Tip:
Always mention overloading increases readability and flexibility.
Overriding enables dynamic behaviour and is key to runtime polymorphism.
Reference: Java Method Overloading and Overriding | Medium
Indirect Questions:
1. Can you overload a method by changing only the return type?
No, we cannot overload a method just by changing the return type in Java.
The compiler decides which method to call based on the method name and parameters (not
return type).
47
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
48
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
void printNames() {
[Link](name); // 10 (Child's name)
[Link]([Link]); // "Parent" (Parent's name)
}
}
49
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
26 What are super and this in Java? How are they used?
this keyword.
- Refers to the current object of the class.
- Used when we want to refer to the current instance variable or method.
- Also used to call another constructor in the same class.
Student(String name) {
[Link] = name; // distinguishes instance variable from
constructor parameter
}
void display() {
[Link]("Name: " + [Link]);
}
}
class ThisKeywordDemo {
public static void main(String[] args) {
Student s = new Student("CodingLyf");
[Link]();
}
}
super keyword
- Refers to the parent class.
- Used to call parent class’s constructor, method, or variable.
- Helps when subclass overrides methods or hides variables.
class Animal {
String type = "Animal";
void sound() {
[Link]("Some animal sound");
}
}
50
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
void printType() {
[Link]([Link]); // Dog
[Link]([Link]); // Animal
}
@Override
void sound() {
[Link](); // calls Animal's sound method
[Link]("Dog barks");
}
}
class SuperKeywordDemo {
public static void main(String[] args) {
Dog dog = new Dog();
[Link]();
[Link]();
}
}
Indirect Questions:
1. In what situations would you need to use this in a constructor?
When the constructor parameter names are the same as instance variable names, this helps
avoid confusion. For example: [Link] = name; tells Java we are assigning the value to the
object's field, not just the parameter.
2. Can this be used to call a method or access a variable?
Yes. We can use ‘this’ to access the instance variables or call other methods in the same class.
It is helpful when local variable names clash or when we want to make it clear that we are
working with the current object's fields or behavior.
3. Does this always refer to the current class instance?
Yes, it always refers to the current object of the class are are working with. It is how we point
to the actual instance the code is running on. It doesn’t refer to the class or other objects, only
the current one.
51
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
void move() {
[Link]("Moving the shape"); // concrete method
}
}
class AbstractClassDemo {
public static void main(String[] args) {
Shape s = new Circle(); // Allowed, reference is abstract, object is
concrete
[Link]();
[Link]();
}
}
52
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
- When some methods should have default implementation, but others should be
overridden
Interview Tip:
- Mention we use abstract class when we want to provide common behaviour with shared code.
- Prefer interface if we only need method declarations.
Indirect Questions:
53
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
void show();
void get();
}
abstract class Child implements Parent
{
public void show()
{
[Link]("Inside Child");
}
}
9. Is it possible to create reference variable to abstract class and assign the concrete class
object?
We can’t instantiate an abstract class, but we can create a reference variable of its type and
assign it to a concrete subclass object.
abstract class Animal {
abstract void sound();
}
Think of it as a rulebook, any class that 'signs' the interface must follow the rules (i.e., implement
the methods).
Interview Tip:
- Use interface when we only need to define the contract, not implementation
- We can combine multiple interfaces using `implements A, B, C` unlike classes
54
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
55
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
56
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Access
Can use any (private, protected, etc.) All members are public by default
Modifiers
Default Yes (can provide method Yes (via default methods since
Implementation implementations) Java 8)
Deserialization is the reverse , converting the byte stream back into a Java object.
In a microservices architecture, different services communicate with each other over the
network, often through REST APIs, gRPC, or message queues (like Kafka or RabbitMQ).
Serialization allows the data objects to be converted into a byte stream so that they can be
transmitted across network boundaries.
For example, when a service needs to send a complex object as part of a request or a
message, making the object Serializable ensures it can be converted into a format (e.g.,
JSON, XML) suitable for network transfer.
In a RESTful service, serialization is commonly used to convert objects to a JSON or XML
format for HTTP communication between a client and server. In Java, libraries like Jackson,
Gson, or JAXB handle serialization (converting objects to JSON or XML) and deserialization
(parsing JSON or XML back into objects)
Important Points:
- The class must implement Serializable interface to make it serializable
- transient keyword is used for fields which we don't want to save
- SerialVersionUID should be declared to maintain version compatibility
Indirect Questions:
[Link] do you make a class serializable in Java?
To make a class serializable in Java, it must implement the `Serializable` interface. This is a
marker interface with no methods.
2. What is serialVersionUID?
57
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
58
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Real-World Analogy:
Think of a movie ticket with 'VIP' stamped on it.
The stamp itself doesn’t do anything, but the staff sees it and allow into a special lounge.
Similarly, JVM checks if a class implements certain marker interfaces and behaves accordingly.
Indirect Questions:
1. Have you written any custom marker interface?
2. Can you implement a custom marker interface for example?
Auditable -> Marks entities whose changes should be logged (e.g., created/updated
timestamps).
//Marker interface with no methods
interface Auditable { }
@Override
public String toString() {
return "LibraryItem{" +
"title='" + title + '\'' +
", createdAt=" + createdAt +
", updatedAt=" + updatedAt +
'}';
}
}
Main class:
public class AuditDemo {
public static void main(String[] args) {
LibraryItem book = new LibraryItem("Clean Code");
[Link]("Clean Code - Updated");
logChange(book);
}
59
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Marker
public class MyClass {}
1. Association
This is the most basic connection between two classes.
Example: A Student attends a college. Student and College are related.
But both can exist without each other. One doesn't depend on the other.
class Student {
String name;
College college; // Association
}
class College {
String name;
}
2. Aggregation
A more specific type of association where one object "has-a" relationship with another
object.
It means one class contains another, but the child can still exist on its own.
Example: A Library has Books. Even if Library is deleted, Books can still exist elsewhere.
Example: A Team object and a Player object. The team contains multiple players but a
player can exist without a team.
class Library {
List<Book> books; // Aggregation
}
class Book {
String title;
60
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Composition
The strongest form of association, also a "has-a" relationship.
If the parent is deleted, child also goes.
Example: Consider the case of Human having a heart. Here Human object contains the
heart and heart cannot exist without Human.
class House {
Room room = new Room(); // Composition
}
class Room {
int size;
}
Indirect Questions:
1. Can you explain the difference between aggregation and composition?
Aggregation is a weak relationship, child can exist on its own.
In composition, child’s life depends on the parent.
2. How would you model a car and its engine in Java?
Car and Engine are tightly connected, so it is composition.
If the car’s gone, engine usually has no use also
3. What’s the best way to model a Book and Library in OOP?
Books can exist without a Library. they can belong to another.
So, it is aggregation.
Code: JavaSamples/[Link] at main · CodingLyf-Fullstack/JavaSamples
Inheritance means one class can use the code from another class by extending it. That might be
helpful, but it is not always a good idea.
Why? Because it creates a strong link between the two classes. If the parent class changes, it can
break the child class. Also, Interfaces has N number of methods, we need to inherit all of them
even though we don’t need.
Reference: Composition over Inheritance [Object Oriented Programming]
Favoring Composition Over Inheritance | by Sheldon Cohen | Medium (Code might be C# but
theory is good to understand)
61
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
36 What is multi-tasking?
Multitasking allows a system (or program) to run more than one task simultaneously. For
example, we might be listening to music while downloading a file and editing a document, all
happening at the same time.
In Java, multitasking is handled through multithreading or multiprocessing, depending on the
context.
Types of Multitasking in Java
There are two main types of multitasking:
1. Process-based Multitasking
2. Thread-based Multitasking
1. Process-Based Multitasking
Each task is a separate process, meaning a complete, independent program running in its own
memory space.
Example
Opening a browser, opening a code editor, and opening a video player at the same time.
Points to remember:
Each process runs independently.
It requires more memory since each process has its own memory and resources.
Switching between processes involves context switching, which is expensive.
In Java, this is done using the ProcessBuilder or [Link]().
2. Thread-Based Multitasking
Each task is a separate thread, but all threads run within a single process. They share the same
memory space.
Example:
A video player: one thread handles video decoding, another thread handles audio, another
thread handles sub titles.
Points to remember:
Lightweight compared to processes.
Threads share memory, which makes data sharing easy but also introduces the
need for synchronization.
Faster context switching between threads.
Most commonly used in Java via Thread class or implementing Runnable.
62
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Two processes cannot directly access each other’s memory. They need special
communication methods like sockets or inter-process communication (IPC).
Processes are handled by the OS, but threads are what Java developers often use to get
things done efficiently inside a single app.
Real-world example:
Opening two different apps on your computer, like a browser and a text editor, each runs as a
separate process. They don’t interfere with each other.
What is a Thread?
A thread is a smaller unit of execution within a process.
A Java process (i.e., your running app) can have multiple threads running inside it.
All threads in the same process share memory (especially the heap). This makes data
sharing fast and easy.
Each thread still has its own call stack (local variables), so they don’t clash at every level.
Threads are commonly used for multitasking, doing more than one thing at the same
time.
Real-world example:
In a video calling app (like Zoom), multiple threads may be running:
One thread handles audio
Another handles video
A third listens for chat messages
All of these threads live inside one single process: the Zoom app
Indirect Questions:
1. What is thread pool?
A thread pool is a collection of reusable threads managed by the JVM.
Instead of creating a new thread every time (which is costly), tasks are submitted to the
pool and executed by existing threads.
In Java, we typically use ExecutorService / [Link]().
2. Explain object-level thread locks.
When we mark a method or block as synchronized (non-static), the lock is taken on the
current object (this).
Only one thread can access the synchronized block/method of that object at a time.
But different instances of the class have different locks.
63
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Java Memory Model establishes rules and guarantees regarding the visibility, ordering, and
atomicity of operations on shared variables, ensuring consistent and predictable behaviour in
multithreaded environments.
Here are the key parts:
1. Heap Memory: Stores objects and shared data. All threads can access it.
2. Stack Memory: Each thread has its own stack, storing method calls and local variables.
3. Working Memory (per thread): A thread often keeps a copy of variables in its own
cache. This is faster, but can cause problems if other threads change the original variable
in the heap.
3 rules JVM follows in multi-threading
1. Visibility Rule
Without synchronization, Change made by one thread may stay in cache and not seen by
others.
Use volatile or synchronized so updates are visible across threads.
2. Ordering Rule
JVM and CPU may reorder instructions for speed.
It uses the happens-before rule: if action A happens before B, then B will always see A’s
changes.
3. Atomicity Rule
The JMM guarantees that certain operations appear as a single, indivisible unit
Reads/writes to int, boolean, etc. are atomic.
For long and double, use volatile or synchronized for atomicity.
Indirect Questions:
1. How JMM Affects Threads
When multiple threads run in Java, they don’t directly read/write main memory all the time.
Instead, each thread has its own working memory (CPU cache).
Thread-local caching: Each thread may keep variables locally to avoid constant memory access.
Main memory: Shared among all threads. Updates in one thread are not immediately visible to
others unless synchronized properly.
If Thread A updates a variable, Thread B may not see the update immediately.
Use volatile, synchronized blocks, or atomic variables.
64
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Think of it like giving each worker in a team their own notepad. Even if they’re all writing notes,
no one can see or mess with anyone else’s notes.
Use cases:
Database connections / transactions (per thread):
In frameworks, a thread might handle one request.
A ThreadLocal can store the current DB connection or transaction
User/session context:
In a web app, when a request comes in, we can store the current user or request ID in a
ThreadLocal.
Later, anywhere in the call chain, we can fetch it without explicitly passing it as a parameter.
Real-Life Example:
Imagine we running a restaurant alone. We take orders, cook, serve, one at a time. That is a
single-threaded program.
Now hire more staff, one handles orders, another cooks, another serves. Things move faster.
That is multi-threading.
Java lets us create such workers inside the program.
There are two ways to create a Thread
1. By extending the Thread class:
65
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
66
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Java provides built-in tools like Thread, Runnable, ExecutorService to manage threads.
Runnable:
Think of Runnable like sending your friend to buy something, but we don’t wait to hear
what happened.
We just say: “Go do this” and move on.
Runnable is used when we don’t need a result back. It is used to run some code.
Callable
Now think of Callable like sending a delivery guy and expecting him to come back with your
package. We will use it when we need result from the task.
class MyCallable implements Callable<String> {
public String call() throws Exception {
return "Task completed!";
}
}
[Link]();
}
}
67
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Interview Tip:
Runnable is useful when we just want to execute code. Callable is better when we need the
result or want to handle exceptions properly.
Callable is usually used with ExecutorService and Future to get results.
Indirect Questions:
1. Can threads return values in Java?
Yes, by using Callable with ExecutorService, threads can return values.
The result is accessed through a Future object.
2. Why does Runnable not support checked exceptions?
Because [Link]() doesn’t declare throws Exception, so checked exceptions aren’t
allowed.
We have to handle them manually inside the method.
3. How would you handle result + exception in a thread?
Use Callable and submit it to an ExecutorService.
Then call [Link]() , it gives the result or throws the exception.
4. How cancel the long running callable
We can wrap the Callable in a Future using an ExecutorService. Then call [Link](true)
to try interrupting the running task.
ExecutorService executor = [Link]();
[Link]("Cancelling task...");
[Link](true);
68
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When the thread scheduler selects the thread, it moves to the running state.
The run() method is executing.
4. Blocked/Waiting
Blocked: When a thread is temporarily inactive (e.g., waiting for I/O, waiting to acquire a
lock).
Waiting: When a thread waits indefinitely for another thread to perform an action
(using wait(), join(), etc.).
Timed Waiting: When a thread waits for a specified time
(using sleep(time), wait(timeout), etc.).
5. Terminated (Dead)
When the thread completes its run() method or is terminated abnormally.
The thread cannot be restarted (calling start() on a dead thread
throws IllegalThreadStateException).
Indirect Questions:
1. What happens if you call start() twice on the same thread?
It throws IllegalThreadStateException. A thread can be started only once.2.
2. Can a thread go from RUNNABLE to TERMINATED without entering BLOCKED or WAITING?
Yes, if it finishes execution without needing to wait or get blocked.
3. Can a thread be started twice? Why or why not?
No. Once it is dead, it is dead. We have to create a new thread object.
[Link] happens if you call start() after run() was already called directly?
It still works. but run() just ran like a normal method, not a thread. Now start() creates a
proper thread.
Technical Notes:
The ExecutorService interface is part of the [Link] package
It extends the Executor interface, which defines a single method execute(Runnable
command) for executing tasks.
Executors is a utility class in Java that provides factory methods for creating and
managing different types of ExecutorService instances.
Always remember to call shutdown() when we are done.
69
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
1. How do you manage multiple threads in a clean way?
Use ExecutorService to handle [Link] creates a thread pool, assigns work, and reuses threads.
No need to manually start or stop threads each time.
2. What’s the difference between execute() and submit()?
execute() runs a task but gives no result back.
submit() runs a task and returns a Future .so we can get the result or catch exceptions.
3. Can ExecutorService handle exceptions from tasks?
Yes , but only if we use submit() and check the result with [Link]().
If we use execute(), exceptions may be lost unless we log them manually inside the task.
4. What happens if you don’t shut down an executor?
The app will keep running because the executor’s threads stay alive.
Always call shutdown() to release resources and stop the thread pool cleanly.
5. How would you design thread pool based on system load?
By Using ThreadPoolExecutor, ThreadPoolExecutor is a Java class that manages a pool of
worker threads to execute tasks asynchronously.
It allows us to reuse threads, control the number of concurrent threads, queue tasks, and
define policies for handling extra tasks when the pool is full.
Reference: Understanding ThreadPoolExecutor in Java | by Pranav Tiwari | Medium
44 What is Synchronization?
In multithreaded applications, multiple threads can attempt to access and modify the
same shared resources (e.g., variables, objects, files) concurrently. Without synchronization, this
concurrent access can lead to unpredictable and incorrect results.
Synchronization in Java is a mechanism that controls access to shared resources by multiple
threads in a multithreaded environment. It ensures that only one thread can execute a critical
section of code
70
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Real-World Example (I did not get any best example than this 😊)
Imagine a public toilet with one door and a key.
If one person is inside and locks the door, no one else can enter.
Only after they unlock and exit can the next person go in.
This is how synchronized works in Java. It gives the first thread a key (a monitor/lock) and blocks
others until it is done.
Indirect Questions:
1. How do you avoid race conditions in multithreaded Java code?
Use synchronized, Locks, or thread-safe data structures to ensure only one thread accesses
critical code at a time.
This prevents threads from messing with shared data at the same time.
2. What happens if two threads access the same variable at the same time?
If that variable isn't protected (no lock), both threads might read or write at the same time,
causing unpredictable results.
This is how race conditions and weird bugs happen.
3. Can two threads call the same synchronized method at once?
No, if the method is synchronized on the same object, only one thread can enter it at a time.
The other thread waits until the first one releases the lock.
4. How would you ensure that a piece of code is executed by only one thread at a time?
Use synchronized block or method.
5. Is Synchronized thread safe?
Yes, synchronized is a keyword and a mechanism used to achieve thread safety in languages
like Java, ensuring that only one thread can access a shared resource or critical section of code at
a time, thus preventing data inconsistency
7. If static synchronized method and instance synchronized called simultaneously on same
object, will it conflict?
No, they won’t conflict.
A static synchronized method locks on the Class object ([Link]).
An instance synchronized method locks on the current instance (this).
But we don’t always want to lock everything. Locking too much can slow down the app.
So, we have two options: Lock entire method called synchronized methods or lock only that
particular section of the code calling synchronized blocks
71
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Synchronized Method:
Synchronized Block
synchronized (this) {
balance += 100; // Only this part is locked
}
}
Indirect Questions:
1. What’s the performance impact of using synchronized?
It can slow things down if too many threads keep waiting to enter locked code.
Use it only where needed, or the program will become slow.
2. How do you lock only part of a method?
Just wrap the critical code inside a synchronized block instead of the whole method.
That way, only that small section gets locked. it is faster, cleaner, and safer.
3. What happens if I synchronize too much?
Too much locking means threads keep waiting, and the app becomes slow or stuck.
It is like blocking the whole road for a bike to pass. It is not efficient at all.
4. If two threads try to access the same synchronized method, what happens to the second one?
It waits and gets into blocked state until the first one releases the lock.
72
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
That is where wait(), notify(), and notifyAll() come into play. These are methods defined in the
Object class , not in Thread class, because in Java, every object can act as a lock.
Real-World Example:
When the person inside comes out, they say “done” then only the next person can go.
That is wait() (someone waiting), and notify() (someone getting informed that they can go in).
wait(): Causes the current thread to pause its execution and release the lock it holds on the
object. Thread goes to waiting state.
notifyAll(): wakes up all waiting threads (only one can proceed at a time)
73
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
wait() is an instance method defined in the Object class, but it is typically called on an object
within a synchronized block.
It is used for thread synchronization and inter-thread communication.
When a thread calls wait(), it releases the lock on the object and is suspended until another
thread calls notify() or notifyAll() on the same object.
It is crucial for scenarios where one thread needs to wait for a specific condition to be met
by another thread.
join()
join() is a method of the Thread class.
It allows one thread to wait for the completion of another thread.
When thread A calls [Link](), thread A waits until threadB finishes
Atomic:
74
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Atomic classes are for atomicity and visibility. Atomic classes make sure that when one
thread changes a value, it does it completely and no one else can mess with it halfway. That is
called atomicity
At the same time, visibility means: once a thread updates the value, other threads can
immediately see the new value. There’s no delay.
75
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
No. volatile does not provide full thread safety. It only ensures visibility of changes across
threads, but doesn’t make compound actions (like incrementing a counter) atomic.
6. How visibility will be ensured in multithreaded programming.
Using volatile
Scenario B: You place the order through an app from home. While it is being prepared, you
watch Netflix, take a shower, and the app notifies us when it is done. That is CompletableFuture.
1: If two APIs return values and you want to process them together?
We can call both APIs using CompletableFuture. Use [Link]() to wait for
both to finish. Once they’re done, we can get both results and combine them however we want.
2: How do you run a task asynchronously in Java?
Just wrap the task using [Link]() or supplyAsync().
This tells Java to run it in the background thread, so the main thread doesn't get stuck
waiting.
try block: This block encloses the code segment that is susceptible to throwing an exception.
catch block: If an exception occurs within the try block, the corresponding catch block is
executed. A try block can have multiple catch blocks to handle different exception types.
finally block: This block is optional and contains code that is guaranteed to execute, regardless of
whether an exception occurred in the try block or was caught by a catch block. It is typically used
for cleanup operations like closing resources.
try {
BufferedReader reader = new BufferedReader(new FileReader("[Link]"));
76
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
At the top:
Throwable: The root of all errors and exceptions in Java.
Two main branches:
Error
o Serious problems that applications shouldn’t try to handle.
o Examples: OutOfMemoryError, StackOverflowError.
o Usually caused by the JVM or environment.
77
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Exception
o Problems an application can catch and handle.
Interview Tip:
List out all the exceptions you have faced in your project and explain how to handled and how
you fixed the errors.
Checked exceptions are checked by the compiler at compile time, and the programmer
must handle them (either by catching them or declaring them in the method signature) or they
will cause a compilation error
Unchecked exceptions: we can handle them, but the compiler won’t force us.
These are runtime bugs. Errors that happen because of mistakes inside the code.
NullPointerException – Accessing Null
ArrayIndexOutOfBoundsException – Accessing Invalid index from an Array
IllegalArgumentException
int divide(int a, int b) {
return a / b; // ArithmeticException if b is 0
}
Indirect questions:
1. Why does Java force you to catch IOException but not NullPointerException?
Because IOException comes from things outside the code , like reading a file, connecting
to a server. We can't always predict if the file will be there or the server will respond. Java says,
“This can fail in real life, so handle it properly.”
But NullPointerException? That is the code mistake. we tried to use something that was
null. Java cant predict it. So we need to handle explicitly
2. What happens if you don’t handle a checked exception?
Java just won’t compile the code.
78
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Real-World Example:
Imagine We are writing a banking app. If a user tries to withdraw more money than they have,
we throw an InsufficientFundsException.
public class BankAccount {
private double balance;
Throws:
throws is used in a method's signature to declare the types of checked exceptions that the
method might throw. This informs calling methods that they need to either handle these
exceptions (using try-catch) or declare them as well (propagating them further).
Real World Example: We are writing a file reader method. Since files can be missing or
corrupted, Java forces us to declare throws IOException to warn callers.
public class FileProcessor {
// Warns that this method might throw an IOException
public String readFirstLine(String filePath) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
return [Link]();
}
}
79
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
1. Can we use throw without throws?
We can use throw for unchecked exceptions (like NullPointerException) without throws.
But for checked exceptions (like IOException), if we throw them, we must declare throws or
handle them. Otherwise, Java will throw compile-time error.
2. What happens if I don’t declare a throws for a checked exception?
If we don’t catch it with try-catch or declare it with throws, our code just won’t compile.
3. Can we use throw with multiple exceptions?
No. throw is for throwing a single exception instance at a time.
4. Can you override a method and change the exceptions it throws?
Yes, but we can throw narrower checked exceptions.
We can’t add new broader checked exceptions in the child class
Examples:
extending Exception: OutOfStockException
public class OutOfStockException extends Exception {
public OutOfStockException(String message) {
super(message);
}
}
80
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
Reference: Custom Exceptions in Java. What is a Custom Exception? | by Priya Salvi | Medium
Interview Tip
- Use checked exceptions when the caller must handle the error (e.g., IOException).
- Use unchecked exceptions (RuntimeException) for programming errors that can’t be
reasonably recovered.
- Use try-catch-finally to handle exceptions and clean up resources.
- Prefer try-with-resources for automatic resource management (e.g., streams, DB connections).
- Create custom exceptions to provide meaningful, domain-specific error messages.
- Always log or rethrow exceptions; never leave catch blocks empty.
81
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Hash Based Collections uses hashCode() first to find the “bucket” and then equals() to check
if the object already exists.
If we override only equals() but not hashCode(), If two objects that are equal logically, but
Java can still place them in different buckets because their hash codes are different. Due to
this, collections like HashSet may store duplicate objects.
If we override only hashCode() but not equals(), two objects may go into the same bucket
because their hash codes are the same. But Java may still treat them as different objects
because equals() is not properly comparing their data.
class Person {
String name;
int age;
// @Override
// public boolean equals(Object o) {
// if (this == o) return true;
// if (!(o instanceof Person)) return false;
// Person p = (Person) o;
// return age == [Link] && [Link]([Link]);
// }
//
// @Override
// public int hashCode() {
// return [Link](name, age);
// }
}
[Link]([Link]());
}
}
Explanation: Here we have two person object that are logically same, same name and same age.
If we don’t override equals and hashCode(), Set will store them two times as their hashcodes are
different. (we will get [Link]() has 2)
If we override equals and hashCode(), Set size will be 1. Means it store the object only once by
checking equals and hashcode methods.
2. What if hash function returns same values how it saves values in HashMap?
82
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If two keys have the same hash code, the HashMap puts them in the same bucket (a linked
list or a balanced tree from Java 8).
Then it uses the key’s equals() method to differentiate them and store/retrieve the right value.
All these points were discussed for each collection in the upcoming questions.
Definition:
In Java, a collection is a framework that provides an architecture for storing and manipulating a
collection of objects. In JDK 1.2, a new framework called "Collection Framework" was created,
which contains all of the collection classes and interfaces.
Collection: This is the main interface of the framework. It defines fundamental operations that
can be performed on any collection of objects, including adding, removing, and checking for the
presence of elements.
In Java, there are two main building blocks for storing groups of objects:
1. Collection interface ([Link]). It is used for things like Lists, Sets, and Queues.
2. Map interface ([Link]). It is used for key-value pairs, like a dictionary.
Under the Collection interface, we have several types:
List, for an ordered list (e.g., ArrayList, LinkedList, Vector)
Set, to stores unique items (e.g., HashSet, LinkedHashSet, TreeSet)
Queue / Deque, for managing elements in a certain order (e.g., PriorityQueue, ArrayDeque)
Under the Map interface, we have:
HashMap, TreeMap, LinkedHashMap, etc., which store key-value pairs.
So, the Java Collection Framework is a group of interfaces and classes that helps to work with
different types of data structures easily.
83
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
84
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Interview Tip:
Always start by explaining the use-case: “ use a List when I need order and allow duplicates, a
Set when uniqueness is required, and a Map when I need key-value pairs.”
Mention common implementations and why: “For List, ArrayList for fast access, LinkedList for
frequent insert/remove. For Set, HashSet for speed, TreeSet for sorting. For Map, HashMap for
general use, TreeMap for sorted keys.”
Tell about performance: “ArrayList get/put is O(1) on average; LinkedList insert/remove is O(1) if
at node, but access is O(n). HashMap operations are O(1).”
Always mention real-world scenarios: “Pick LinkedHashMap if I need insertion order, or
ConcurrentHashMap for multi-threaded caching.”
Indirect Questions
1. Can a List contain null values?
Yes, a List can hold any number of null values.
2. What about Set and Map?
A Set allows only one null value, and a Map allows one null key and many null values.
3. Can a Map contain null keys?
Yes, a Map (like HashMap) can have one null key.
4. What happens when you add the same element twice in a Set?
The duplicate is ignored because Set keeps only one copy.
5. How would you ensure only unique usernames are allowed?
Store usernames in a Set or use them as keys in a Map.
6. What happens if you try to add a duplicate key in a HashMap?
The old value is overwritten with the new one.
7. Why does not collection interface extend the Map interface?
The Collection interface does not extend Map because they represent different concepts. A
Collection is a group of individual elements, while a Map is a group of key-value pairs.
57 ArrayList vs LinkedList?
Internal Structure:
85
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
ArrayList: An ArrayList is backed by a dynamic array. This means it can resize itself as
needed, but elements are stored contiguously in memory.
LinkedList: A LinkedList uses a doubly linked list. Each element (node) stores a reference
to the next and previous nodes.
Access:
ArrayList : Accessing an element by its index (e.g., get(index)) is very fast (O(1) time
complexity) because the array provides direct access to elements.
ArrayList: Inserting or deleting elements in the middle of an ArrayList can be slow (O(n)
time complexity) because it may require shifting elements to make space or close
gaps. Appending or removing from the end is faster.
LinkedList: Inserting or deleting elements anywhere in the list is fast (O(1) on average for
insertions/deletions at the beginning or end) because it only involves updating node references.
Memory Usage:
LinkedList: Consumes more memory than ArrayList due to the overhead of storing
references to the next and previous nodes.
Use Cases:
ArrayList: Best for scenarios where we need frequent random access to elements and
modifications (insertions/deletions) are not a primary concern.
LinkedList: Ideal for scenarios where we need frequent insertions or deletions, especially
at the beginning or end of the list, and random access is not a primary requirement.
Indirect Questions:
1. How does Java manage dynamic resizing in ArrayList?
When the internal array is full, ArrayList creates a new array with 50% more capacity.
It then copies all elements into the new array.
2. Why is LinkedList not preferred for random access?
LinkedList stores elements as nodes with references to next and previous.
Accessing an element at index i requires traversal from head or tail , O(n) time.
So it is slow compared to ArrayList’s O(1) where we can access via indexing.
3. If you are inserting an element in the middle of a LinkedList with 10 million items, how will it
perform compared to an ArrayList?
86
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
LinkedList: Inserting in the middle requires traversing to that position (O(n)) and then updating
pointers (O(1)). So overall O(n).
ArrayList: Inserting in the middle requires shifting all elements after that index (O(n)).
For 10 million items:
Both are O(n), but in practice, LinkedList can be slightly faster for insertion since no
shifting of elements is needed, only pointer updates.
Rule:
Use LinkedList if frequent insertions/deletions in the middle are needed.
Use ArrayList if random access and iteration speed matter more.
4. If you need to implement a queue that frequently adds and removes elements from both
ends, which list would be a better choice and why?
Pick LinkedList over ArrayList.
LinkedList implements Deque, so it is designed for efficient insertions and deletions at both ends
in O(1) time.
ArrayList is backed by an array, so adding/removing at the front or middle requires shifting
elements, which is O(n).
5. Defining the constructor capacity in ArrayList increases performance?
Yes, it can.
An ArrayList in Java grows dynamically. If we don’t set the capacity, it starts with a default size
(10) and when more elements are added, it creates a new bigger array (usually 1.5x of old size),
copies all elements into it, and then continues.
This resizing and copying cost time and memory.
So, if we know in advance that we will store, say, 10,000 items, defining the constructor like:
List<Integer> list = new ArrayList<>(10000); it saves multiple resizes and improves
performance, especially in large datasets.
58 ArrayList vs Vector?
Internal Structure
ArrayList and Vector both use a dynamic array internally.
The difference is,
ArrayList increases size by 50% when it is full.
Vector increases size by 100% (it doubles).
So, Vector tends to allocate more memory when resizing. That can lead to slightly fewer resizes
but more unused memory.
Access
Access speed is the same for both , O(1) for reading any element using .get(index)
because both are array-based. So if the main job is reading by index, both perform well.
Insertions/Deletions
If we insert/delete at the end, both are fast O(1).
87
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
1. If you want to maintain the insertion order of key-value pairs, which Map implementation
would you choose and why?
88
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Use LinkedHashMap. It maintains the order in which we added the keys, so when we
iterate, we get the elements in the same order.
2. How would you store user records where the keys must always stay sorted alphabetically?
Go for TreeMap. It automatically keeps keys sorted based on natural order (like
alphabetical for strings) or a custom comparator.
3. What would happen if you insert multiple elements with the same hashcode into a Map? How
is ordering handled in such a case?
In a HashMap, they go into the same bucket. Order is not guaranteed.
In a LinkedHashMap, they're linked in insertion order even in the same bucket.
In a TreeMap, hashcode doesn't matter, only key ordering does.
4. In what scenarios could maintaining a sorted order of keys lead to performance trade-offs?
When using a TreeMap, every put, get, or remove operation takes O(log n) time due to the
underlying Red-Black Tree. This is slower than a HashMap’s average O(1), but useful when sorted
order is required.
5. If you are building a cache that needs predictable iteration order and fast access, which Map
would you use and why?
LinkedHashMap is ideal. It offers fast access like a HashMap and maintains order, which is
great for things like LRU (Least Recently Used) caching.
6. How can we make HashMap Synchronized?
Map<Integer, String> map = new HashMap<>();
[Link](map);
7. What are the consequences of non-final fields in a class that is used as a key in a HashMap?
Using non-final fields in a class that is used as a key in a HashMap can cause serious issues
because HashMap depends on two things:
1. hashCode(): determines which bucket the key goes into.
2. equals(): determines whether two keys are the same inside that bucket.
Problem:
If the fields used in hashCode() or equals() are mutable (non-final), and if we change them after
inserting the object into the map, then:
The key’s hashCode() may change, so the object is now in the wrong bucket.
A lookup using the same key (but with changed values) will fail , we will get null even
though the entry exists.
class Person {
String name; // mutable, not final
Person(String name) {
[Link] = name;
}
@Override
public int hashCode() {
return [Link](name);
}
@Override
public boolean equals(Object o) {
89
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
// Lookup works
[Link]([Link](p1)); // Engineer
// Lookup fails
[Link]([Link](p1)); // null
}
}
When we put p1 in the map, its hash is based on "Raju".
After changing [Link] to "Raghu", its hash changes but the entry is still stored under
the old bucket.
So, lookup fails, the object exists in the map, but HashMap can’t find it anymore.
60 HashMap vs HashTable?
Synchronization:
HashMap: Doesn't provide thread safety.
HashTable: Provides thread safety by synchronizing all its methods, ensuring that only one
thread can access the table at a time.
Performance:
HashMap: Due to the lack of synchronization overhead, HashMap generally offers better
performance than HashTable
HashTable: The synchronization mechanism adds overhead, potentially impacting
performance.
Null keys and values:
HashMap: One null key and multiple null values are permitted.
HashTable: Does not allow, Attempting to insert null keys or values will result in a
NullPointerException.
Iterators:
HashMap is Fail-fast , if it is modified after an iterator is created a
ConcurrentModificationException is thrown
HashTable is fail-safe, meaning modifications to the table during iteration will not cause an
exception
90
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
1. Is HashMap thread-safe by default?
No, HashMap is not thread-safe. If multiple threads access it concurrently and at least one
modifies it, we can get unpredictable results.
2. Why does Hashtable not allow null keys or values?
To avoid ambiguity during lookups and to keep the behaviour consistent across threads,
Hashtable disallows null keys and values.
3. Which is faster: HashMap or Hashtable?
HashMap is faster because it is unsynchronized. Hashtable uses locks on every operation,
which slows things down in single-threaded scenarios.
4. What is the difference between Iterator and Enumerator?
Iterator is newer, supports remove(), and is fail-fast. Enumerator is older, does not support
removal, and is not fail-fast.
5. When should we use ConcurrentHashMap over Hashtable?
Use ConcurrentHashMap when we need high-performance thread-safe operations. It allows
concurrent reads and partial concurrent writes.
6. Why is Hashtable considered a legacy class?
Because it was part of early Java and later replaced by better alternatives like HashMap and
ConcurrentHashMap in the Collections Framework.
61 ConcurrentHashMap vs SynchronizedHashmap ?
1) Locking Mechanism:
SynchronizedHashMap maintain object level lock. i.e the whole map is locked..
But in ConcurrentHashMap, the whole map is not locked. The map is divided into number of
segments and each segment maintains its own lock.
2) Synchronized operations:
In synchronizedHashMap all operations are synchronized. That means, whatever the
operation we want to perform on the map, whether it is read or update, we have to acquire
object lock.
But in ConcurrentHashMap, only update operations are synchronized. Read operations are
not synchronized.
3) Number of threads
Only one thread can enter into a SynchronizedHashMap.
91
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
5) Nature Of Iterators
Iterators returned by SynchronizedHashMap are fail-fast in nature. i.e they throw
ConcurrentModificationException if the map is modified after the creation of iterator.
Iterators returned by ConcurrentHashMap are fail-safe in nature. i.e they DONT throw
ConcurrentModificationException if the map is modified after the creation of iterator.
92
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference: Why Nulls Are Banned: The Surprising Reason ConcurrentHashMap Doesn’t Allow
Null Keys or Values | by The Code Alchemist | Medium
Additional Question:
1. What is the work around to handle the nulls in ConcurrentHashMap?
Use a Placeholder Object: This is the most common and efficient approach. Create a special,
unique object that represents null.
public static final Object NULL_VALUE = new Object();
93
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
// To "put null"
[Link]("key", value == null ? NULL_VALUE : value);
2) Implementation:
HashSet uses a HashMap internally to store elements.
LinkedHashSet uses a LinkedHashMap internally, which maintains a doubly-linked list to track
insertion order.
TreeSet uses a TreeMap internally, which is a self-balancing binary search tree.
3) Performance:
Hashset: Generally offers the best performance for add, remove, and contains operations (O(1)
on average) due to the efficient hashing mechanism.
LinkedHashSet: Performance is slightly slower than HashSet because of the overhead of
maintaining the linked list, but still generally fast (O(1) on average for most operations).
Treeset: Performance is generally slower than both HashSet and LinkedHashSet (O(log n) for
add, remove, and contains operations) because of the sorting overhead.
94
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions
1. How would you maintain insertion order in a Set?
Use LinkedHashSet
Don’t say HashSet, it doesn’t maintain order
2. What if I need to always keep the elements sorted?
Use TreeSet. It uses Red-Black Tree internally for ordering
3. How would you implement a deduplicated list of elements while keeping insertion order?
LinkedHashSet, Because it is a Set (removes duplicates) + maintains order
4. Which Set would perform best for search operations?
In most cases, HashSet gives O(1) for contains()
TreeSet takes O(log n)
5. Can I store null in a Set?
HashSet and LinkedHashSet allow one null
TreeSet throws NullPointerException (if using natural ordering)
6. What happens if I insert elements in random order, then iterate the Set?
In HashSet: iteration order will be unpredictable
In LinkedHashSet: elements come out in the order they went in
In TreeSet: elements come out sorted
7. How does TreeSet know how to sort the elements?
It uses compareTo() (natural ordering) Or a custom Comparator if passed during construction
8. Why Treeset does not allow null?
A TreeSet compares each element either by comparable or comparator. If TreeSet allows null,
then it will throw NullPointerException.
9. What happens if you add elements to a HashSet with duplicate hashCode() values but
different equals() implementations?
If two objects have the same hashCode() but equals() returns false, the HashSet will store both
objects.
Here is why:
HashSet first checks the bucket using hashCode().
Within the bucket, it uses equals() to see if the object already exists.
Since equals() is false, HashSet treats them as different, even though they collide in the
hash bucket
95
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
removed. Queues are widely used in scenarios like task scheduling, buffering and producer
consumer problems.
Since the Queue is an interface, we cannot provide the direct implementation of it.
Queues in Java can be classified into bounded and unbounded implementations based on their
capacity.
1. Unbounded Queue: Can grow dynamically (no fixed size).
2. Bounded Queue: Has a fixed maximum capacity.
A bounded queue has a fixed size. Once it is full, we can’t just keep adding elements, either the
operation fails, or it waits until space is available.
ArrayBlockingQueue: It Uses an array with a fixed capacity. It also supports fair ordering if
we want threads to access in a strict first-come, first-served manner.
LinkedBlockingQueue: Works like a linked list and we can set the capacity. If we don’t, it
defaults to a very large size (Integer.MAX_VALUE).
PriorityBlockingQueue: Instead of strict FIFO, it orders elements based on priority (either
natural ordering or a custom comparator).
2. Unbounded Queues
Unbounded queues don’t force a hard capacity limit. They’ll grow as needed, limited only by the
available memory.
PriorityQueue: Keeps elements ordered by natural order or a comparator, but it is not
thread-safe.
ConcurrentLinkedQueue: A thread-safe option that works well in highly concurrent
scenarios.
LinkedList (as Queue): LinkedList also implement Deque. So, it can be also used as Queue.
LinkedBlockingQueue:
Useful when we want flexibility in size (bounded but large by default). For example, handling
requests in a web server where we may want to queue thousands of tasks.
96
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
// Add tasks
[Link](() -> [Link]("Task 1 executed"));
[Link](() -> [Link]("Task 2 executed"));
// Execute
Runnable task = [Link]();
if (task != null) [Link]();
PriorityBlockingQueue
When tasks have priorities, like a hospital system where emergency patients must be treated
before routine checkups(Refer Question No: ).
PriorityQueue: When we need ordered processing but don’t care about thread safety
ConcurrentLinkedQueue: When multiple threads are adding and removing without blocking.
LinkedList (as Queue): For simple, single-threaded use cases where we just need FIFO behavior.
1. Initial Capacity
When we create an ArrayList, it starts with a default capacity , which is usually 10, unless we give
a specific value: List<String> list = new ArrayList<>(); // default capacity = 10
Capacity here means: how many elements can be stored before the array has to grow.
2. Capacity vs Size
Capacity -> Total slots available in the internal array
Size -> How many elements we have added so far
Let’s say we created a list with default capacity 10, and added 3 elements then
Capacity = 10 and Size = 3
3. How it Grows
When we keep adding items and the array runs out of space, it automatically grows like this:
A new array is created with more space (typically 1.5x the old size)
All elements are copied from the old array to the new one
The old array is discarded
This resizing is done inside a method called grow().
Example:
Old capacity = 10 and new capacity = 15
This resizing takes time, so adding many items at once can temporarily slow things down.
4. Adding Elements
97
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference: How HashMap Internally Works in Java With Animation | Popular Java Interview QA
| Java Techie
HashMap works by using a hash function to map keys to indices in an internal array (buckets).
When a key-value pair is added, the hash code of the key is used to determine which bucket to
store it in. If multiple keys hash to the same index, a linked list (or a balanced tree in Java 8+ for
larger lists) is used to store these collisions.
1. Hashing:
When we insert a key-value pair (e.g., put(key, value)), the hashCode() method of the key object
is invoked. The result, along with the current size of the HashMap, is used to calculate an index
within the internal array.
2. Collision Handling:
If multiple keys generate the same hash code (a hash collision), they are stored in the same
bucket. In older versions of Java (before 8), this was handled using a linked list. In Java 8 and
later, if the number of elements in a bucket exceeds a threshold (usually 8), the linked list is
converted to a balanced tree (red-black tree) for better performance.
98
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Retrieval:
When we retrieve a value using get(key), the same hashing process is used to determine the
correct bucket. If the key is not directly found in the bucket, the linked list or tree (depending on
the implementation) is traversed to find the key-value pair.
4. Resizing:
If the HashMap becomes too full (exceeds a load factor threshold, typically 0.75), it will resize its
internal array to a larger size, typically doubling it. This process, called rehashing, involves
recalculating the hash codes and re-distributing the elements into the new array, which can be a
costly operation.
Key Concepts:
equals(): Used to compare keys for equality when collisions occur. If hashCode() returns the
same value for two keys but equals() returns false, it signifies a collision.
Load Factor: A threshold that determines when the HashMap should resize.
Indirect Questions:
99
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference: Core JAVA: How does HashSet work internally? Implementation | Why are its
elements unique?
HashSet uses a HashMap behind the scenes to store its elements. Here is how it actually works:
100
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When we don’t provide a Comparator, TreeMap uses the natural ordering of keys. That means
the key class must implement Comparable interface.
[10🖤]
/ \
[5🔴] [15🔴]
/ \
[12🖤] [20🖤]
Legend:
🔴 = Red node
🖤 = Black node
Each node = key-value pair
Always follows Red-Black tree rules (Below are the rules good to know)
Natural Ordering
If we just write:
101
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Custom Ordering
Operations:
[10🖤]
/ \
[5🖤] [15🖤]
/
[1🔴]
It stays balanced
Search: get(key)
To find a key, TreeMap walks down the tree:
To find 12 in this tree:
[10🖤]
\
[15🔴]
/
[12🖤]
12 > 10 , so go right
102
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
12 < 15 , so go left
Found it
Only takes a few steps thanks to the balanced structure.
Deletion: remove(key)
If we remove a node, like 10:
[10🖤]
/ \
[5🔴] [15🔴]
TreeMap finds the in-order successor (like 12 or 15), replaces 10 with it, then re-
balances the tree by rotating/recolouring.
Indirect Questions:
1. Will TreeMap allow key or value?
- TreeMap don’t allow null as key but allow null as value
2. Why TreeMap wont allow null key and what will happened if we add null as a key?
- TreeMap maintains its keys in sorted order, To maintain this sorted order, TreeMap needs to
compare keys with each other. A null value cannot be compared with a non-null value using
these comparison methods. Attempting to do so results in a NullPointerException
- Same with TreeSet as well
103
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
It is a special kind of Map in Java that allows multiple threads to read and write at the same time
without messing up the data.
Before Java 8: Segment-Based
The map was divided into smaller pieces called segments.
Each Segment can contain number of buckets.
Each segment had its own lock.
If two threads worked on different segments, they could proceed without waiting.
But still, locking was needed per segment, which made things a bit complex.
. From Java 8 Onwards: Bucket-Based Locking
Segments were removed.
Now the map is divided into buckets (like in HashMap).
Each bucket holds entries (either a linked list or tree).
Instead of locking the whole map, it only locks the specific bucket being updated.
This means more threads can work in parallel.
CAS (Compare-And-Swap)
For small updates like adding or changing a value, it may skip locking altogether.
It uses CAS, a technique to check and change a value in one atomic step.
This reduces thread fighting and improves speed.
Internal Operations
Adding or Updating an Entry
Calculate the hash of the key to find which bucket it belongs to.
If that bucket is empty, just insert the new entry , so no lock needed.
If the bucket is not empty:
o Lock only that bucket.
o Check if the key exists:
If yes, update the value.
If not, add the new entry.
o Then release the lock.
o In simple cases, CAS may be used instead of locking.
Reading an Entry
No locking is needed for reads.
Thanks to special memory rules (volatile), the reading thread will see the most up-to-date
value.
Removing an Entry
1. Find the right bucket using the key’s hash.
2. Lock that specific bucket.
3. Remove the entry.
4. Release the lock.
Indirect Question:
104
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Supported Collections:
Iterator can be used with any collection like List, Set, Queue, or Map.
ListIterator works only with List collections like ArrayList, LinkedList
Direction:
Real-World Example:
Imagine scrolling through a photo gallery.
With Iterator, we can only hit “Next”.
With ListIterator, we get both “Next” and “Previous”.
//Iterator example - one direction only
List<String> names = new ArrayList<>();
[Link]("Dhoni");[Link]("Virat");
Iterator<String> iterator = [Link]();
while([Link]()) {
[Link]([Link]());
}
while([Link]()) {
[Link]("Forward: " + [Link]());
}
while([Link]()) {
[Link]("Backward: " + [Link]());
}
Modification:
105
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Starting Point:
Features:
Iterator: Simpler, with basic methods like hasNext(), next(), and remove().
ListIterator: Provides extra methods like hasPrevious(), previous(), add(), and set().
When to Use:
Iterator: Use for simple traversal of any collection.
ListIterator: Use for advanced list traversal when we need both directions or to modify the list.
Indirect Questions:
1. What is the best way to traverse a Set, and why doesn't ListIterator work for it?
Use Iterator because Set doesn’t maintain index order, and ListIterator needs positional access
which only Lists provide.
5. What happens if you try to modify a collection during iteration without using the right tool?
We’ll get a ConcurrentModificationException because the collection detects structural changes
mid-iteration.
6. What collection types restrict you from using a ListIterator, and why?
Set, Queue, and Map don't support ListIterator because they don’t guarantee indexed order.
7. When should you use Iterator over ListIterator in real-world Java applications?
Use Iterator when working with Sets or non-indexed collections; it is simple and universal.
75 Fail-Fast vs Fail-Safe?
Definition:
Fail-Fast throws a ConcurrentModificationException if a collection is modified during
iteration (other than via the iterator).
Fail-Safe does not throw exceptions during iteration, as it works on a copy of the
collection or uses special mechanisms to handle changes.
Examples:
Fail-Fast: ArrayList, HashMap, HashSet, LinkedList (use their standard iterators).
Fail-Safe: CopyOnWriteArrayList, ConcurrentHashMap.
106
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Fail-fast iterators check if the collection has been modified while iterating. If it detects a change,
it immediately throws a ConcurrentModificationException.
How it works:
1. The collection keeps a modCount (modification count) that increases with every change
(add, remove, etc.).
2. When an iterator is created, it saves the current modCount as expectedModCount.
3. Before each operation , the iterator checks if modCount == expectedModCount.
4. If they don’t match, it means the collection was modified, and the iterator throws an
exception.
Example:
List<String> list = new ArrayList<>();
[Link]("A");
[Link]("B");
107
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Fail-safe iterators consume more memory. They work on a copy of the collection, so any
changes to the original don’t affect iteration. Fail-fast iterators, on the other hand, directly
iterate the collection and throw ConcurrentModificationException on modification, so they use
less memory.
77 How FAIL-SAFE iterator works? why it does NOT throw concurrent modification
exception?
Fail-safe iterators don’t throw ConcurrentModificationException because they don’t operate on
the actual collection. Instead, they work on a copy of the collection's data, taken at the moment
the iterator was created.
How it works:
Here, [Link]("C") modifies the original list, but the iterator only print "A" and "B", since it works
on copy.
108
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The Comparator interface is used to define multiple ways of sorting objects. It is found in the
[Link] package and has two primary methods: compare() and equals(), although equals() is
rarely overridden.
class NameComparator implements Comparator<Student> {
public int compare(Student a, Student b) {
return [Link]([Link]);
}
}
Interview Tip:
Use Comparable for default sorting. Use Comparator when we need custom sorting. Also
mention, Java uses them in sorting and ordering, like in [Link](), TreeMap, or TreeSet.
Without them, Java won’t know how to compare objects. TreeMap in Java relies on either
the Comparable interface or a Comparator
Indirect Question:
1. If a class defines its own natural ordering using Comparable, but I also provide a custom
Comparator while sorting, which ordering will be applied?
If a class implements Comparable, that defines its natural ordering (say by ID or name).
But if we pass a Comparator explicitly to a sort method ([Link](list, comparator) or
[Link](comparator)), the Comparator takes precedence.
So, natural ordering is used only when no Comparator is given.
79 [Link]() vs [Link]?
[Link]() (Java 9+)
Creates a truly immutable list (cannot be modified in any way).
If we try to modify it (add, remove, set), it throws an UnsupportedOperationException.
Nulls are not allowed (throws NullPointerException if we try to add null).
More memory-efficient (optimized for small lists).
List<String> immutableList = [Link]("A", "B", "C");
[Link]("D"); // Throws UnsupportedOperationException
109
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]()
Wraps an existing list and makes it unmodifiable (but the original list can still change).
If the original list changes, the unmodifiable view also reflects those changes.
Allows null (if the original list had null).
But when we tried to take things out and cast them to the right type, the program would crash
at runtime with a ClassCastException.
String name = (String) [Link](2);
// Runtime error: ClassCastException
Generics were introduced in Java 5 to solve this exact problem. Generics in Java provide a way to
write classes, interfaces, and methods that operate on objects of various types while
maintaining type safety.
How Generics Work
Type Parameters
Generics introduce placeholders for types, usually written as single capital letters like T
for Type, E for Element, K for Key, V for Value. These placeholders sit inside angle brackets (<>).
Generic Classes
We can define a class that works with any type. For example, a simple Box class:
class Box<T> {
private T value;
T get() {
110
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
return value;
}
}
Now, when we create a Box, we specify what type it holds:
Box<String> stringBox = new Box<>();
[Link]("Hello Generics");
[Link]([Link]()); // Hello Generics
Generic Methods
We can also make methods generic. The type parameter goes before the return type:
public <T> T printAndReturn(T data) {
[Link](data);
return data;
}
Now the method works with any type:
printAndReturn("Java"); // prints Java
printAndReturn(123); // prints 123
Wildcards
What if we don’t know the exact type but still want flexibility? That is where wildcards (?) come
in
List<? extends Number> numbers;
This means the list can hold Integer, Double, or any subclass of Number.
Important Thing to Know
Primitives don’t work: We can’t use int or char directly with generics. Instead, we use
wrapper classes like Integer and Character.
111
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
112
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Step by Step Process from Object creation to object deletion from memory
1. Heap: When we create an object in Java using new keyword, it goes to the heap. The heap
memory in the JVM is divided into generations.
2. Young Generation again divided into 3 section : Eden Space, FromSpace (S0) and ToSpace (S1)
Eden space - all new objects start here, and initial memory is allocated to them
Survivor spaces (FromSpace and ToSpace) - objects are moved here from Eden after surviving
one garbage collection cycle. When objects are garbage collected from the Young Generation, it
is a minor garbage collection(Minor GC) event.
3. Old Generation: Objects that are long-lived are eventually moved from the Young Generation
to the Old Generation. This is also known as Tenured Generation, and contains objects that have
remained in the survivor spaces for a long time. Here Major GC event occurs to clear the objects.
Major GC uses Marks and Sweep Algorithm.
Mark: The garbage collector "marks" all reachable objects, starting from root nodes.
Sweep: After marking, its "sweeps" through memory to delete objects that were not marked as
reachable, freeing up space.
Reference: Garbage Collection in Java – What is GC and How it Works in the JVM
[Link]
9. Java Memory Management and Garbage Collection in Depth (Video)
Indirect Questions:
113
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](); // Suggest GC
[Link]();
114
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Output:
Before GC: {[Link]@372f7a8d=Value for key1,
[Link]@2f92e0f4=Value for key2}
After GC: {[Link]@2f92e0f4=Value for key2}
Interview Tip: No need to mention all the features Start with 3–4 important ones, explain how
they help in real projects. The major ones are lambdas, streams, functional interfaces, and
default methods. We used lambdas and streams heavily when working on data transformations
and in business logics.
86 What are default methods and why are they are introduced?
A default method allows to add a new method to an interface without breaking the classes
that already implement it.
Before Java 8, interfaces can only have abstract methods. So, if we add a new method to an
interface, every class that implemented it has to override that method, or we will get a compile-
time error. That was a huge headache, especially for large codebases or libraries where
interfaces were implemented in hundreds of places.
To fix this, Java introduced default methods. Now, when we add a new method to an interface,
we can also provide a default implementation. In this way, existing classes won’t break, they can
either use the default or choose to override it.
115
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The stream() method was added as a default method in the [Link] interface in Java 8:
default Stream<E> stream() {
return [Link](spliterator(), false);
}
Now any class that implements Iterable, like List, Set, or Queue, automatically got the ability to
use streams:
List<String> names = [Link]("Coding", "Lyf");
[Link]()
.filter(name -> [Link]() > 4)
.forEach([Link]::println);
We don’t have to go back and modify ArrayList, LinkedList, or any collection class.
Indirect Questions:
1. Is it necessary to override default methods of interface in Java 8?
No, they contain built in implementation. We override only if we want custom behaviour.
2. Is the default keyword one of the access modifiers?
No, it is not. It is a special keyword for method implementation in interfaces, not for setting
access levels like public or private.
3. How to override default methods?
We can override like a like any normal method. override it in the class using @Override, and
provide own body.
4. If two interfaces have the same default method, and you implement both, what will happen?
If a class implements two interfaces that each have the same default method, a compilation
error will occur because the compiler cannot determine which default method to inherit.
To resolve this, the class must explicitly override the default method and provide its own
implementation, or explicitly call the desired interface's default method
using [Link]().
5. Can you call a default method from a class that implements Interface?
Yes, we can call a default method from a class that implements the interface, but only within
that class or its subclasses, and only using [Link]().
Interview Tip: Try to tell with real world example like, Default methods were introduced so
interfaces can be good choice without breaking existing implementations. For example, if an
interface is used in 100 places, adding a new method would normally break them. With default,
we can add it with a basic body and avoid rewriting everywhere.
116
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
So, in Java 8, They allowed interfaces to group their own utility methods?
That is how static methods in interfaces came to picture. They belong to the interface, not to
the implementing class. So, we can call them like [Link](), not through an
object.
JDK Example:
In Java 8, the Comparator interface added static methods like:
public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
return (a, b) -> [Link](b);
}
Optional is a container that may or may not hold a non-null value. It is used to clearly
show that a method might not return a result. Instead of returning null, the method returns an
Optional to help avoid NullPointerException and make the code safer and easier to understand.
Example: In the below example, if user is null, [Link]() will throw NullPointerException.
String getName(User user) {
return [Link]();
117
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Now from Java 8, instead of returning String we will return Optional<String> which tells that ,
this may contain null and should be handled.
Optional<String> getName(User user) {
return [Link]([Link]());
}
[Link]() vs [Link]():
[Link](value): Use it when the value might be null. If value is non-null, it returns
an Optional containing the value; if value is null, it returns an empty Optional ([Link]()).
[Link]() vs null:
118
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]([Link]());
}
This works, but it is a bit long and not the cleanest way to write code.
[Link]()
This is a shorter and cleaner way. If a value is present, it runs the code. No need to check
manually.
[Link](name -> [Link](name));
Let’s say we have a list of names and want only names that start with "S".
Before Java 8:
List<String> names = [Link]("Sam", "Ravi", "Sneha", "John");
List<String> result = new ArrayList<>();
119
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
if ([Link]("S")) {
[Link](name);
}
}
Here we wrote:
A loop
An if condition
Manually added items to a new list
From Java 8 (Functional Way):
List<String> names = [Link]("Sam", "Ravi", "Sneha", "John");
Functional interface: A functional interface is an interface that contains exactly one abstract
method, although it can also contain multiple default or static methods. The presence of a single
abstract method allows instances of functional interfaces to be created with lambda expressions.
@FunctionalInterface
public interface MyFunctionalInterface {
void execute();
}
This interface has only one abstract method, execute, making it a functional interface.
Functional interfaces are used extensively with lambda expressions. A lambda expression
provides a clear and concise way to implement the single abstract method of a functional
interface. Here is how we can implement the MyFunctionalInterface using a lambda expression
Tricky Questions:
[Link] we include default and static methods in functional Interface?
Yes, A functional interface can have exactly one abstract method and any number of default
and static methods.
120
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Consumer: This interface represents an operation that accepts a single input argument and
returns no result. It is used when an action needs to be performed on an object without
producing a return value. Example: forEach()
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Supplier: This interface represents a supplier of results. It takes no arguments and returns a
value of a specified type. It is used when a value needs to be generated or retrieved. Example:
[Link]
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Predicate: A Predicate is a functional interface that represents an operation that takes an input
of type `T` and returns a boolean result. Example: filter()
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
121
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Function: This interface represents a function that accepts one argument and produces a
result. It is used for transforming an input value into an output value of a potentially different
type. Example: map()
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
Indirect Questions:
2. What interface allows converting one data type into another in streams?
Function<T, R> : it maps one type to another, like converting String to Integer.
Function<String, Integer> toInteger = str -> [Link](str);
5. How do you lazily provide a default value in case of null using Optional?
Use [Link](Supplier). It’ll only call the Supplier if the value is missing.
Optional<String> name = [Link](null);
String result = [Link](() -> "Default Name");
6. How do you think the Supplier interface can be useful when writing lazy initialization code?
Supplier can delay object creation until it is actually needed, it is great for saving memory or
resources.
7. Which functional interfaces existed in Java before Java 8?
Runnable and Callable were considered functional interfaces before Java 8 as they had a single
abstract method.
122
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Java 8 changed this by introducing the idea that functions can be first-class citizens. That means
functions can be treated just like variables, we can pass them around, store them, and return
them from methods.
Before Java 8 (Anonymous Inner Class): if we want to create a thread that prints "Hello".
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
[Link]("Hello");
}
});
[Link]();
After Java 8 (Lambda Expression): Same behaviour, written in a much cleaner way:
Thread thread = new Thread(() -> [Link]("Hello"));
[Link]();
Now we are passing behaviour (a function) like data, that is what we mean by functions
becoming first-class citizens.
Before Java 8, if we wanted to create a new Runnable to run in a thread, we had to write it as an
anonymous class:
Runnable r = new Runnable() {
@Override
public void run() {
[Link]("Running a task!");
}
};
Lambda Expressions Introduced in Java 8, a lambda expression provides a much more concise
way to represent an implementation of an interface with a single abstract method (known as a
functional interface).
Using a lambda expression, the same Runnable task can be written in a single line:
Runnable r = () -> [Link]("Running a task!");
123
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
It can extend abstract and concrete class. It can't extend abstract and concrete class.
It can implement an interface that contains It can implement an interface which contains a
any number of abstract methods. single abstract method.
It is the best choice if we want to handle It is the best choice if we want to handle
multiple methods. interface.
It works fine. What we are doing is, taking “s” and passing it to [Link].
124
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Streams are introduced in Java 8. Streams make the code shorter, readable, and more
declarative; they provide a functional and efficient way to process collections by creating a
pipeline of operations. They enable declarative programming, lazy evaluation, and parallel
processing without modifying the original data source.
125
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Lazy Evaluation -> Water doesn’t flow until the tap is opened. Similarly, Stream operations don’t
execute until a terminal operation like collect or forEach is called.
Parallel Processing -> Just like multiple pipes can distribute water to different locations
simultaneously, parallel streams split data into chunks and process them across multiple threads
for better performance.
Immutable Flow -> Water in the pipeline doesn’t affect the water tank. Similarly, a Java Stream
doesn’t modify the original collection; instead, it produces a transformed result.
It provides various operators to process the data. They can be segregated like
Source Operators
This is where the stream starts. We can turn a list, array, or even lines from a file into a stream.
Example: [Link](1,2,3).stream() or [Link](path)
Intermediate Operators
These are the steps in the middle. They transform the stream but don’t run until a terminal
operation is called (this is called lazy evolution).
Example: .filter(n -> n % 2 == 0).map(n -> n * 2)
Short-Circuit Operators
These stop the stream early when a condition is met. Useful when we don’t need to process the
entire stream.
Example: .limit(5), .anyMatch(x -> x > 100)
Terminal Operators
These are the end of the stream. Once we call a terminal operation, everything runs and gives us
a result like a list, count, sum, etc.
Example: .collect(toList()), .count(), .forEach([Link]::println)
Indirect Questions:
1. What is lazy evaluation in streams?
Streams don’t do anything until a terminal operation is called. That means nothing runs
during filter() or map() until we finally say something like collect() or forEach().
126
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]()
.filter(x -> x % 2 == 0)
.map(x -> x * x)
.forEach([Link]::println);
This looks like multiple steps, but under the hood it is one loop.
How Fusion Happens
Each intermediate op (filter, map) doesn’t create a new list.
Instead, it wraps its logic into a chain of operations.
When the terminal op (forEach) pulls elements, the pipeline executes all stages in
sequence for each element.
So for element x = 4:
Check filter (4 % 2 == 0 > true)
Apply map (4 * 4 > 16)
Send to forEach (print 16)
Only then does it move to the next element.
This is why it is called loop fusion: multiple logical loops (filter > map > forEach) are fused into a
single physical loop.
Overhead: Streams introduce additional abstraction and object creation, which can
make them slower than plain for-loops, especially for small or simple tasks.
Performance: For basic iteration (e.g., summing an array), a classic loop is often faster
due to lower overhead.
Reference: Is Java Stream Really Faster Than For-Loop? 🚀 | Java Interview Question
95 Can you list of streams operators you have used or you know?
1. Source Operators: Create a stream from a collection, array, or I/O source.
127
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Terminal Operators: Trigger execution and produce a final result, consuming the stream.
4. Short-Circuiting Operators: Stop execution early when a condition is met for better
performance.
Many indirect or Scenario based questions can be asked on these operators. Example
128
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
In Java streams (or lambdas), we can access variables from outside the stream/lambda body
if they are effectively final. That means the variable isn’t reassigned after its initialization.
int factor = 2; // effectively final
List<Integer> numbers = [Link](1, 2, 3);
[Link]()
.map(n -> n * factor) // accessing outside variable
.forEach([Link]::println);
5. If you don’t use the terminal operation in Stream pipeline, will the intermediate operations be
executed, why or why not?
Streams in Java are lazy. Intermediate operations (map, filter, sorted, etc.) are only
recorded, not run immediately.
They get executed only when a terminal operation (forEach, collect, reduce, etc.) is called.
Without a terminal operation, the pipeline never triggers, so nothing runs.
Streams are different from collections. Streams don't store anything. They just describe how
data should be processed. We don’t add or remove things from a Stream. We just say, ‘take this
list, filter out the even numbers, map each number to its square, and collect the result.’
The important difference is, Streams are lazy. They don’t do anything until we tell them to finish,
we usually do with a terminal operation like .collect() or .forEach().
129
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Let’s say we have a list of 1000 numbers. With a Collection, we already have all those numbers in
memory. With a Stream, nothing really happens until we start processing them. The data flows
through like water in a pipe, step-by-step.
So, the core difference is, Collections are about storing data. Streams are about processing data.
Reference: Exploring the Differences: Java map vs. flatMap | by Reetesh Kumar |
Medium
Indirect Question:
[Link] of lists and need to be converted it into a single list of all elements, how you do it?
Use flatMap
[Link](sum); // Output: 30
99 forEach vs collect()?
collect()
It collects the processed stream into a data structure (like a List, Set, or Map)
It returns that data structure
We use it when we want to store or reuse the results
130
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
forEach()
It goes through each item and performs an action (like printing or logging)
It returns nothing (void)
We use it for side effects, not for building data
Indirect Question:
1. What happens if you call terminal operation without any intermediate operations?
It works. The stream directly applies the terminal operation over the source data.
For example: count()
List<String> list = [Link]("a", "b", "c");
100 How can you optimize a Stream pipeline for better performance?
Apply filtering and short-circuiting operations (like filter, limit, findFirst) early in the pipeline
to reduce the number of elements processed downstream.
Use primitive specialized streams (IntStream, LongStream, DoubleStream) to avoid
unnecessary boxing/unboxing.
Use parallel streams only when working with large datasets and the workload is CPU-bound.
[Link]()
.map(String::toUpperCase)
.forEach([Link]::println);
This will process "Rohit", then "Gill", then "Hardik", one after the other.
Parallel Streams
A parallel stream splits the data into chunks and processes them in parallel using multiple
threads behind the scenes (from the common fork-join pool). The goal is better performance,
especially with large datasets.
[Link] ()
.map(String::toUpperCase)
131
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
.forEach([Link]::println);
Now "Rohit", "Gill", and "Hardik" might be processed out of order and at the same time by
different threads.
When .parallel() is called, Spliterator splits the work into chunks that can be processed in
parallel by ForkJoinPool.
Indirect Questions:
4. What is a Spliterator?
Spliterator stands for Split + Iterator. It is a special iterator introduced in Java 8 that supports:
1. Sequential traversal (like Iterator).
2. Efficient splitting of data into chunks for parallel processing.
It is the backbone of how the Stream API works under the hood.
Unchecked Exceptions:
We can catch these unchecked exceptions while processing the data. We can handle unchecked
exceptions with two approaches
1. Handle It Inside
2. Filter Out the Bad Ones
Example: Suppose we have a list and we would like to convert strings to number. But it will
throw NumberFormatException because of “four”
List<String> numbersAsString = [Link]("1", "2", "3", "four", "5");
In “Handle it Inside” approach, we catch the error and return some fallback value. In the below
we have handled the exception and return -1 as a fallback value.
132
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]()
.map(s -> {
try {
return [Link](s); // throw NumberFormatException
} catch (NumberFormatException e) {
return -1; // fallback value
}
})
.forEach([Link]::println);
In “Filter out the bad ones” approach we will filter them using filter method. Here we are
returning null when exception occurs and filtered using Objects:nonNull.
[Link]()
.map(s -> {
try {
return [Link](s);
} catch (NumberFormatException e) {
// We caught the exception! Let's return a default value, like -1.
[Link]("Could not parse: " + s);
return null;
}
})
.filter(Objects::nonNull)
.forEach([Link]::println);
We can also use Wrapper to handle exceptions to write more cleaner code. We will see that in
next section.
Code Link: JavaSamples/[Link] at main · CodingLyf-
Fullstack/JavaSamples
Checked Exceptions:
Java streams don't work well with checked exceptions because the functional interfaces
used in stream operations (like Function, Predicate, etc.) don't declare any checked exceptions.
Let’s see three approaches
1. Wrap in RuntimeException
The simplest approach is to catch the checked exception and wrap it in a runtime exception. In
the below we are catching Checked Exception and throwing Runtime Exception.
[Link]()
.map(item -> {
try {
return someMethodThatThrowsCheckedException(item);
} catch (IOException e) {
throw new RuntimeException(e);
}
})
133
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
.forEach([Link]::println);
3. Propagate Exception
If we need to propagate the checked exception, we need to collect results and handle
exceptions after processing:
[Link](item -> {
try {
[Link](someMethodThatThrowsCheckedException(item));
} catch (CheckedException e) {
[Link](e);
}
});
if (![Link]()) {
// Handle exceptions
}
134
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
But when we write code inside lambdas or anonymous classes, this behaves differently
In a Lambda, this refers to the outer class , the class where the lambda is written.
Example:
public class MyClass {
private String name = "Coding Lyf";
135
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
Java 9:
Java 9 introduced convenience static factory methods on the List, Set, and Map interfaces to
easily create immutable collections. These methods provide a concise way to create collections
whose state cannot be changed after construction. Attempting to modify such collections will
result in an UnsupportedOperationException.
Java 10:
136
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Local variable reference : Local Variable Type Inference , allows to declare the local variables
without explicitly stating their type. Java looks at the value we assign and automatically guesses
the correct type for the variable. This feature utilizes the reserved type name var
[Link](message);
[Link](number);
[Link](list);
}
}
2. HTTP Client: Java 11 includes a new HTTP client API that provides a more modern and
efficient way to send HTTP requests and receive responses. The new HTTP client API supports
both HTTP/1.1 and HTTP/2 protocols and includes features like HTTP/2 push, server push, and
WebSocket. The new API is also asynchronous and non-blocking, making it more scalable and
performant than the previous HttpURLConnection API.
3. String methods: isBlank(), strip(), stripLeading(), stripTrailing(), lines(), repeat(int)
Java 12:
[Link]() Method: A new method mismatch(Path, Path) was added to the Files class,
allowing for easy comparison of two files and returning the index of the first differing byte or -1
if they are identical.
String API Enhancements: New methods like indent() and transform() were added to the String
class for easier string manipulation.
137
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](int n): To add or remove indentation (leading spaces) from each line of a multiline
string.
[Link](result);
Java 14:
Switch Expressions: In Java 14, switch expressions were finalized Standard feature. This
allowed switch to return values and eliminated the need for explicit break statements
int day = 2;
String dayName = switch (day) {
case 1, 7 -> "Weekend";
case 2, 3, 4, 5, 6 -> "Weekday";
default -> "Invalid day";
};
[Link](dayName);
The switch statement can now be used as an expression that returns a value.
Arrow (->) syntax introduced for cleaner case expressions.
The break statement is no longer needed in this context.
Yield: the yield keyword is used within switch expressions to return a value from a case block.
String dayOfWeek = "Monday";
String activity = switch (dayOfWeek) {
case "Monday" -> {
[Link]("Starting the week!");
yield "Go to work";
}
case "Saturday", "Sunday" -> "Relax";
default -> "Study";
};
[Link]("Today's activity: " + activity);
Java 15
Text Blocks: A Text Block is a multi-line string literal enclosed in triple double quotes ("""). It
simplifies the creation of strings that span multiple lines, such as HTML, JSON, SQL queries, or
other structured text.
String htmlContent = """
<html>
<body>
<h1>Welcome!</h1>
</body>
</html>
""";
138
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Java 16:
Record: In Java, a record is a special type of class declaration aimed at reducing the boilerplate
code. Java records were introduced with the intention to be used as a fast way to create data
carrier classes, i.e. the classes whose objective is to simply contain data and carry it between
modules, also known as POJOs (Plain Old Java Objects) and DTOs (Data Transfer Objects)
public record Person(String name, int age) {}
Pattern matching for instanceof in Java simplifies type checking and casting by combining them
into a single operation.
Before pattern matching, checking the type of an object and then casting it to access its specific
members required two separate steps:
Object obj = "Hello World";
if (obj instanceof String) {
String s = (String) obj; // Explicit cast
[Link]([Link]());
}
With pattern matching, as a standard feature in Java 16, the explicit casting is no longer needed
Object obj = "Hello World";
if (obj instanceof String s) { // 's' is the pattern variable
[Link]([Link]());
}
Java 17:
139
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The permits clause explicitly lists the classes or interfaces that are allowed to extend or
implement the sealed type.
When we use permits in a sealed class, the classes or interfaces we list must be marked with one
of these:
final: This means the class can’t be extended by any other class. It is the end of the chain.
sealed: This class is also sealed, so it controls who can extend it, just like the parent.
non-sealed: This class removes the restriction. Any class can extend it now, breaking the
sealed rule from this point on.
Java 21:
In older versions of Java, switch could only work with fixed values like numbers, strings,
or enums. But from Java 21, with pattern matching for switch, we can now use switch to check
both the type of an object and do something based on that type
This means we don’t need to write extra if or instanceof checks. Java handles that for you right
inside the switch.
static String handle(Object obj) {
return switch (obj) {
case String s -> "It is a string: " + s;
case Integer i -> "It is a number: " + i;
case null -> "It is null";
default -> "Something else";
};
}
So, if we pass a String, it will go into the String s case. If it is an Integer, it goes into the Integer i
case.
Record Patterns:
Records are a simple way to create classes that just hold data (introduced in Java 14, made
stable in Java 16).
Now, starting with Java 21, With Record Patterns we can easily extract the values from a record
using pattern matching, without manually calling getters.
Before record patterns, if we had a record “record Person(String name, int age) {}”, we read like
Person p = new Person("Macha", 25);
String name = [Link]();
int age = [Link]();
With record patterns, Java do this in a more readable way, especially inside if or switch:
if (p instanceof Person(String name, int age)) {
[Link]("Name: " + name + ", Age: " + age);
}
140
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Here, Java is checking if p is a Person, and at the same time, it pulls out name and age, no need
to call .name() or .age() manually.
Switch:
switch (p) {
case Person(String name, int age) ->
[Link](name + " is " + age + " years old");
}
Sequenced Interfaces:
SequencedCollections
SequencedMap
SequencedSet
SequencedCollection works with ArrayList and LinkedList, it gives new methods like
106 Output-Based 1: How many String objects will be created in memory from below code?
String s1 = new String("hello");
String s2 = "hello";
141
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
107 Output-Based 2: How many String objects will be created in memory from below code?
String s1 = new String("hello");
String s2 = "hello";
String s3 = [Link]();
We have added 3rd line [Link]();
intern(): When invoked on a String object, it checks if an identical string already exists in the
pool. If found, it returns a reference to the existing string. If not, it adds the string to the pool
and returns a reference to the newly added string.
Since “hello” is already existed in the string pool, It returns same object. So [Link]() wont
create new string object.
[Link](a == b);
[Link]([Link](b));
Explanation:
a == b is true
Both a and b are string literals with the same content.
Java stores string literals in the String pool, so both point to the same memory location.
Same reference -> == is true.
[Link](b) is true
.equals() checks if the contents are the same.
"CodingLyf" equals "CodingLyf" , so it returns true.
142
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](a == b);
[Link](a == c);
[Link]([Link](c));
Explanation:
a == b: true, because both refer to the same string literal in the String pool.
a == c: false, because new String() creates a new object in heap memory.
[Link](c): true, because equals() compares values, not references.
[Link](x == z);
[Link]([Link](z));
Explanation:
z = y + "lyf" is built at runtime using a variable, so it is a new object in memory.
Even though x and z look the same, they are not the same object, so == gives false.
.equals() checks the actual text inside both strings, which is the same, so it returns true.
Explanation:
a is "hello"
The method [Link](Object obj) does this internally: return (obj == null) ? "null" :
[Link]();
[Link]() for a String just returns itself (not a new object)..
So b ends up pointing to the same object as a. Output is true
143
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
"hello" is stored in the String Pool, “a” points to it.
[Link](0) returns the same object when the whole string is taken.
So a == b is true because both references point to the same string.
Explanation:
s1 is created using new, so it is a separate object in heap, and creates string literal “hello” in the
pool.
s2 points to the string pool version of "hello".
s3 = Since “hello” is already there in string pool, [Link]() won’t create new String, it just
returns the pool version of "hello", so s3 == s2 is true, but s1 == s3 is false
[Link](sb1 == sb2);
[Link]([Link](sb2));
144
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]("d");
[Link](sb1 == sb2);
[Link]([Link](sb2));
We are assigning sb2 = sb1, so both references point to the same object in memory.
So == returns true.
[Link]("d")
We have modified the content of the object both sb1 and sb2 point to.
Since S1 and S2 refer to the same object, the change is visible to both.
[Link](sb2)
Again, StringBuilder doesn’t override .equals(), so it uses Object equals, so it checks ==.
And since both refer to the same object, it returns true.
[Link](a == b);
[Link]([Link](a, b));
145
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
In Java, all arguments are passed by value, even primitives like int.
So, when change(a) is called, a copy of a's value (50) is passed to x.
Inside change() method, x = 100 modifies the copy, only local variable will be change, not
the original variable.
The original ‘a’ in main() remains unchanged, so the output is 50.
Explanation:
In Java, everything is passed by value, including object references.
sb in main() holds a reference to the StringBuilder object.
When passed to change(), a copy of that reference is passed, now both sb in main() and sb in
change() point to the same object in memory.
[Link](" Lyf") changes the actual object in memory, not the reference variable. so the
change is visible even after the method ends.
So, [Link](sb) prints Coding Lyf.
Point to remember:
146
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
In main(), sb points to a StringBuilder object with the content "Original".
When you call reassign(sb), a copy of the reference is passed into the method.
Inside reassign(), sb = new StringBuilder("New") just reassigns the local copy to a new object.
Now it is completely new object.
So, the original sb in main() still points to "Original", so output is “Original”.
Explanation:
In main(), nums is an array with values {1, 2, 3}.
When passed to modify(), a copy of the reference to the array is passed.
Java passes object references by value, so both arr and nums refer to the same array object.
arr[0] = 99 changes the content of the original array in memory, since both arr and nums
point to the same object.
So, when we print nums, the change is visible.
147
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
[Link](nums, [Link]) creates a new array object with the same contents as
nums. So changes made inside the method do not affect the original.
This new array is passed to modify(), where arr[0] = 99 modifies only the copy, not the
original.
Explanation:
final primitive = value can’t be changed.
Compilation error: cannot assign a value to final variable 'x',
148
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link] = "Sam";
[Link]([Link]);
}
}
Explanation:
final means, we can’t reassign the value to Person object ‘p’ but we can change the state.
final Person p = new Person();
p = new Person(); //It throws compilation error as we are reassigning
Explanation:
More specific exceptions must come before general exceptions.
It throws Compile Time Error
Explanation:
Even try return the value, finally still executes before method returns.
So, Output is “In finally”.
Explanation:
149
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
static {
[Link]("Static Block");
}
}
}
Explanation:
When the class is loaded (before main() runs), Java does these things in order for static:
All static variables are initialized first in the order they are defined.
Static blocks are executed in the order they appear in the code.
Here in this class static variable is defined at first so the output is
1. Static variable initialization
2. Static block
3. Main method (Does thing in above code)
Points to remember:
Static blocks & static variables run once when the class is loaded.
Instance variables and instance blocks run before the constructor for each new object.
int x = instanceInit();
{
[Link]("Instance Block");
}
Test() {
[Link]("Constructor");
}
150
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
When new Test() is called, object creation starts.
First, instance variable x is initialized, which calls instanceInit() and prints: Instance Variable
Initialization.
Then the instance block runs and prints: Instance Block.
After that, the constructor runs and prints: Constructor.
Concept: For every object, Java runs instance variable initializations (depends on order) >
instance blocks (depends on order) > constructor
Answer is:
Explanation:
A obj = new B(); creates a reference of type A but an object of type B , this is upcasting.
At runtime, method overriding comes into picture , we call it as dynamic method dispatch.
Since show() is overridden in class B, the method from B gets called, not A.
Output is B. It demonstrates the runtime polymorphism.
151
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
When new B() is called, B's constructor runs.
But since B extends A, A's constructor is called first which is implicit super() call.
152
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
show() is a static method, which means it is not overridden but it is hidden, a concept called
method hiding.
A obj = new B(); is upcasting, but with static methods, only the reference type matters, not
the object.
Since obj is of type A, [Link]() calls A's version, not B’s.
So the output is: A static.
Explanation:
153
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](s1); //S12
[Link](s2); //S3
[Link](s3); //3S
}
}
Explanation:
In s1 = "S" + 1 + 2, Java processes expressions left to right. Since "S" is a string, 1 is converted to
"1" and concatenated, resulting in "S1". Then "S1" concatenates with 2 (converted to "2"), so
"S12".
For s2 = "S" + (1 + 2), the parentheses force the addition 1 + 2 to happen first as integer
arithmetic, gives 3. Then "S" concatenates with "3" to form "S3".
In s3 = 1 + 2 + "S", the addition 1 + 2 happens first because both are integers, resulting in 3. Then
3 is concatenated with "S" to get "3S".
Explanation:
154
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
A a = new B(); we are storing a B object in a reference of type A. This is upcasting and
perfectly safe.
Then we write: C c = (C) a; this is downcasting. We are telling Java, “Treat this object as a C.”
But here is the problem: the actual object in memory is a B, not a C. So, the cast is logically
wrong, the compiler allows it because C is related to A.
At runtime, Java checks the object and throws: ClassCastException
Explanation:
Both class A and class B have a field named val. This is variable hiding, not overriding.
A obj = new B(); we are creating a B object but storing it in an A reference.
155
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When we access [Link], Java looks at the reference type, not the object type and since obj is
of type A, it fetches A's val.
So the output is 1.
Point to remember: fields are resolved at compile-time by reference type, but methods
resolve at run time which use runtime polymorphism.
Explanation:
In class A, show() is marked private, which means it is not inherited by class B.
In class B, we define a new public show() method, but it doesn’t override A's method.
A doesn’t have a visible show() method (it is private), so we can't call it through an A
reference..
So [Link](); causes a compile-time error
Point to remember: Private methods are not inherited, so no overriding happens.
New B().show() will work, it prints B. It treats show() as normal function
156
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Point to remember: In Java, when we override a method in a subclass, the overridden method
(the method in the subclass) must have the same or more accessible (less restrictive) access
modifier than the overriding method (the method in the parent class). Keep same visibility or
increase it, but never reduce it
Explanation:
A protected method can be accessed within the same package or by subclasses (even in
different packages).
A default (package-private) method is less accessible than protected because it is only
accessible within the same package.
test() in class A is protected, means visible to subclasses and classes in the same package.
So, we are reducing visibility, which is not allowed, even if the classes are in the same
package.
That is why the compiler throws error: Cannot reduce the visibility of the inherited method
from A
Point to remember: In Java, when we override a method in a subclass, the overridden method
(the method in the subclass) must have the same or more accessible (less restrictive) access
modifier than the method (the method in the parent class). Keep same visibility or increase it,
but never reduce it
157
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
Class A has a public method test() that prints "A test".
Class B extends A and attempts to override test() but declares it as private.
In Java, a subclass cannot reduce the visibility of an inherited method. This is a compilation
error because private is more restrictive than public
Solution: make the method public in class B:
Point to Remember: In method overriding, the child class cannot throw broader or new checked
exceptions than the parent method. It can throw the same or narrower checked exceptions.
Explanation:
[Link]() declares throws IOException, which is a checked exception.
In Child, the overridden method declares throws Exception, which is more general than
IOException.
In Java, an overridden method can only throw the same or narrower checked exceptions ,
not a broader one.
Since Exception is broader than IOException, the compiler throws an error
158
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Point to Remember: In Java, Child class methods can throw unchecked exceptions freely,
regardless of what the Parent declares
Explanation:
new B(); starts object creation, which first calls A's constructor (because B extends A).
Inside A() constructor, it calls show().
Since show() is overridden in B, Java calls B’s version , this is runtime polymorphism.
But here is the catch: when A() is running, the B part of the object isn’t fully initialized yet.
So even though control goes to [Link](), the field ‘x’ in B hasn’t been assigned 10 yet, ‘x’
holds the default value 0.
That is why the output is: B show: 0.
159
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
public class Test {
public static void main(String[] args) {
new B().show();
}
}
Explanation:
new B() triggers object creation, which first calls the constructor of A, since B extends A.
Inside A() constructor, it calls the static method show().
Static methods are not overridden, they are hidden, so the version that gets called is based
on the reference type at compile-time, not runtime.
In this case, since show() is called from A's constructor, the method [Link]() gets executed,
not [Link]().
So, the line [Link]("A show"); runs.
After the object is fully created, new B().show() is executed in main(). Now the reference is of
type B, so [Link]() runs, and by this point, static variable x = 10 is initialized.
Output is A show and B show: 10
Explanation:
Class A has a regular instance method msg().
Interface B has a default method msg().
Class Test extends A and implements B.
Point to remember: When msg() is called, Java gives priority to the class method over the
default method from the interface.
So, the output is: Class.
160
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
Both Interfaces A and B have a default method with same signature: void show().
When class C implements both A and B, and both interfaces have a default method with the
same name, Java doesn't know which one to inherit, this is called Diamond problem.
Class C implements both A and B, so Java forces it to override show() to resolve the conflict.
Inside C's show() method, [Link]() calls A's version and [Link]() calls B's
version
The class can still access specific interface methods using
[Link]()
After calling both interface methods, [Link]("C") prints "C".
Final output is: A, B, C
161
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
Class A defines an abstract method run(), and class B extends it without implementing run()
so B is still abstract.
Class C extends B and provides the actual implementation of run().
In main(), A obj = new C(); it is a valid upcasting, and [Link]() calls C's version due to
runtime polymorphism.
Output is: Running from C.
162
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
There are two overloaded methods: show(int, long) and show(long, int).
We call [Link](10, 20), where both 10 and 20 are int.
Java doesn’t know which method to use, should it convert the first int to long or long to int?
This casues compile time error.
void show(String... s) {
[Link]("Varargs");
}
void show(long l) {
[Link]("long");
}
Explanation:
163
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Two overloaded show() methods: one takes Integer, the other takes long.
The call [Link](10) passes an int.
Point to Remember: Java prefers widening over boxing during overload resolution.
int to long is widening and int to Integer is boxing.
So, java choose, long.
void show(Object o) {
[Link]("Object");
}
Explanation:
Two overloaded show() methods: one takes String, the other takes Object.
Point to remember: Overloading prefers more specific types when multiple matches are
possible.
[Link](null) passes null, which matches both, but String is more specific than Object
"CodingLyf" is a String, so again show(String) is called.
Output: String, String
class Test {
void show(A a) {
[Link]("A");
}
void show(B b) {
[Link]("B");
}
164
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](obj);
}
}
Explanation:
‘obj’ is declared as type A but instantiated with new B().
Point to Remember: Method overloading is resolved at compile-time based on reference
type, not object type. Overloading depends on reference type, not runtime object type.
Since obj is of type A, show(A a) is selected.
Output: A.
void show(String s) {
[Link]("String");
}
Explanation:
Two overloaded show() methods: one takes Object, one takes String.
‘obj’ is declared as Object but holds a String value.
Point to remember: Overloading is based on reference type, not runtime value type.
So, show(Object o) is chosen at compile-time.
Output: Object
165
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
Class A has only a parameterized constructor A(String s) , it has no default constructor.
Class B extends A and its constructor must call super(...) explicitly if no default constructor
exists in A.
Point to remember: If the superclass does not contain a no-arg constructor, the subclass
must explicitly call one of its available constructors.
B() doesn’t call super(...), so the compiler tries to insert super() but no-arg constructor
doesn’t exist in A.
Result: Compile-time error (Implicit super constructor A() is undefined. Must explicitly
invoke another constructor)
Point to remember: When creating a subclass object, the superclass constructor runs first.
In this example, Since A has no-arg constructor, when we call new B(), it first implicitly invoke the
A’s constructor.
Output: A, B
166
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class B extends A {
B() {
this(10);
[Link]("B Default");
}
B(int b) {
super(b);
[Link]("B int");
}
}
public class Test {
public static void main(String[] args) {
new B();
}
}
Explanation:
Class A only has a parameterized constructor A(int) that prints "A <value>".
In B’s constructor B(), the first statement is this(10), so it jumps to B(int) before executing "B
Default".
Point to remember: this() is used for constructor chaining within the same class, and it must
be the first statement.
Inside B(int), super(b) calls A’s constructor A(int), which runs first because superclass
constructors always execute before subclass constructors.
Execution flow: A(int) -> print "A 10", back to B(int) -> print "B int", back to B() -> print "B
Default".
Output: A 10, B int, B Default.
Explanation:
new B().display();
Inside display()
167
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
161 Output-Based 57: Functional Interface: Can a functional interface have default methods?
@FunctionalInterface
interface MyFunc {
void test();
default void show() {
[Link]("Default");
}
}
Answer: Yes, a functional interface can have any number of default or static methods but it must
have exactly one abstract method.
Explanation:
1. @FunctionalInterface ensures the interface has only one abstract method.
2. MyFunc has one abstract method test() and one default method show().
3. Pointer to remember: Default methods don’t break the functional interface rule because
they have a body. Same rule applies even to static methods
4. A lambda expression is used to implement the single abstract method test().
5. Output: Lambda, Default
168
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
163 Output-Based 59: Functional Interface: Will the code below compile?
@FunctionalInterface
interface MyFunc {
void test();
}
169
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class Demo {
public static void main(String[] args) {
MyInterface m = (a) -> a * a;
[Link]([Link](5));
}
}
Explanation:
A Thread object can be started only once , once it is started, it moves from NEW to other
states.
[Link]() the first time works fine and runs run().
The second [Link]() call throws IllegalThreadStateException because the thread is no
longer in NEW state.
Point to remember: Once a thread has been started, it cannot be restarted; we must create a
new Thread object.
Output: First "CodingLyf" may print, then a runtime exception is thrown before printing
170
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
Test extends Thread and implements Runnable, but Thread already implements Runnable,
so the implements Runnable here is redundant.
Calling [Link]() directly just executes it like a normal method in the main thread (no new
thread is created).
Calling [Link]() creates a new thread, which then calls run().
Point to remember: run() is just a method; start() is what actually starts a new thread and
then calls run() internally.
Output: CodingLyf CodingLyf
[Link]();
[Link]();
[Link]();
[Link]("Three");
}
}
Explanation:
Creating t1: A Thread is created with a lambda that simply prints "One". At this stage, the thread
is in the NEW state and hasn’t started yet.
171
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Creating t2: Another Thread is created whose job is to first call [Link]() (meaning it will wait
until t1 finishes) and then print "Two". It is also in the NEW state.
Starting t2 first: The main thread calls [Link](). This moves t2 to the RUNNABLE state, and
eventually the JVM schedules it. Inside t2’s code, it reaches [Link](). Since t1 hasn’t started yet,
t2 just waits for t1 to terminate in the future.
Starting t1: The main thread then calls [Link](). Now t1 moves to RUNNABLE, the JVM picks it
up, and it executes [Link]("One"). Once it finishes, t1 moves to the TERMINATED
state.
Main thread waiting for t2: The main thread calls [Link](). If t2 hasn’t finished yet, the main
thread will block until it does. In this case, it waits just until "Two" is printed.
Printing "Three": Once t2 has terminated, the main thread continues and prints "Three".
[Link]();
[Link]();
[Link]("C");
}
}
Explanation:
A new thread “t” is created with a task that prints "A", then tries [Link]() (waiting for
the main thread to finish), and finally would print "B".
The main thread calls [Link](). This moves t to the RUNNABLE state, and the JVM schedules it.
As soon as t runs, it prints "A", then calls [Link](). Now “t” is blocked, waiting for the
main thread to finish execution.
172
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Right after starting t, the main thread calls [Link](), which means the main thread is now blocked
waiting for “t” to finish.
Deadlock: The main thread is waiting for t to finish, but “t” is waiting for the main thread to
finish , neither can proceed. This is a classic deadlock.
Result: The only output is "A", after which the program hangs forever. "B" and "C" never print.
Instance variable a belongs to each object separately, so changing t1.a to 100 doesn't affect
t2.a so it stays 10.
Static variable b is shared by the class itself, not individual objects, so updating t1.b to 200
changes b for all instances.
So, both t1.b and t2.b reflect the updated value 200.
}
}
Answer: Compile-time Error
Explanation:
We cannot declare a local variable “I” as static inside a method; static is only allowed for class-
level members.
173
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class Test {
public static void main(String[] args) {
CodingLyf t = new CodingLyf();
[Link]();
[Link]("Main");
}
}
Answer: Compile-time Error
Explanation:
CodingLyf implements Runnable, which means it only has the run() method.
Runnable does not have a start() method.
The start() method belongs to the Thread class.
Fix: Wrap the Runnable instance inside a Thread and call start() on that Thread:
CodingLyf t = new CodingLyf();
Thread thread = new Thread(t);
[Link]();
[Link]("Main");
174
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
We can do with using if-else or switch. Above code is using switch expression from Java 17+.
The switch directly evaluates membershipType.
For "Premium", it checks if itemsPurchased > 5, else 0.
For anything else (non-premium), it checks itemsPurchased > 10.
Hint: Use a switch for operation type and if-else for balance validations.
Code link: JavaSamples/Scenario2_ATMOperations.java at main · CodingLyf-
Fullstack/JavaSamples
175
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
177 Java Scenario 6: Printing Even and Odd Numbers with Two Threads
Two threads should print numbers from 1 to 20. One prints even numbers, the other
prints odd numbers.
Hint:
Use synchronization to ensure correct order
Code link: JavaSamples/Scenario6_OddEvenPrinter.java at main · CodingLyf-
Fullstack/JavaSamples
Explanation:
1. Two threads start with different responsibilities
Odd thread calls printOdd(1, 3, 5...)
Even thread calls printEven(2, 4, 6...)
Both share the same Printer object, so synchronization works on its monitor.
176
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
178 Java Scenario 7: Sequential Execution of Two Threads Printing Numbers (1,2,3…) and
Letters(A,B,C,..) in Java. So that it prints (A,1B,2…)
Hint:
Use synchronization to ensure correct order
Code link: JavaSamples/Scenario7_AplhaNumericSequence.java at main · CodingLyf-
Fullstack/JavaSamples
Explanation:
Check the code, it contains all necessary explanation in the comments.
We create two threads; one for letters, one for numbers.
we create a shared lock “monitor” .
We also keep a flag called isLetter. If it is false, it is the letter thread’s turn. If it is true, it
is the number thread’s turn.
Each thread checks this flag in a while loop. If it is not their turn, they go to sleep using
[Link]() until the other thread wakes them up.
When a thread does print its value, it flips the flag to give the turn to the other thread,
then calls [Link]() to wake them up.
We start with isLetter = false, so the letter thread goes first, prints “A”, and hands the
turn to the number thread.
This back-and-forth continues until we’ve gone through all 26 letters and numbers in
sequence.
177
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
b. Using BlockingQueue
A BlockingQueue is just a queue with built-in thread safety and blocking behavior.
It is in [Link] and is mostly used when we have producer-consumer kind of
situations.
How it works?
When we try to put something in and the queue is full -> the thread will wait until space is
available.
When we try to take something out and the queue is empty -> the thread will wait until there’s
something to take.
This removes the headache of manually handling wait() and notify(); the queue does it for us.
Blocking Operations:
put(E e): Inserts the specified element into this queue, waiting if necessary for space to
become available.
take(): Retrieves and removes the head of this queue, waiting if necessary until an element
becomes available.
Implementations:
178
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Code links:
Deadlock Example: JavaSamples/Scenario9_Deadlock.java at main · CodingLyf-
Fullstack/JavaSamples
Explanation: In this example, thread1 acquires resource1 and then tries to
acquire resource2.
Simultaneously, thread2 acquires resource2 and then tries to acquire resource1.
This creates a circular dependency where thread1 holds resource1 and waits
for resource2 (held by thread2), and thread2 holds resource2 and waits for resource1 (held
by thread1), leading to a deadlock
This consistent ordering prevents the circular wait condition, thereby avoiding deadlock.
181 Java Scenario 10: Increment the shared counter with threads
Create 10 threads, each updating a shared counter. The goal is for the final count to be
10,000.
179
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Code links:
With Integer: JavaSamples/Scenario10_SharedCounter_Int.java at main · CodingLyf-
Fullstack/JavaSamples
AtomicInteger: JavaSamples/Scenario10_SharedCounter_Atomic.java at main · CodingLyf-
Fullstack/JavaSamples
// Async task 1
CompletableFuture<String> userFuture = [Link](() ->
{
simulateDelay(1000);
return "User: CodingLyf";
});
// Async task 2
180
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
//Existing implementations
class UpiPayment implements PaymentMethod {
//Implement the methods
}
181
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
182
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
All employees have common fields (name, salary) ; abstract classes can store these,
interfaces can’t.
We can keep shared code in one place and only make subclasses implement the different
part (calculateBonus()).
calculateBonus() can be an abstract method so each type of employee defines its own
formula.
In short: use an abstract class when all types share fields and some common methods, but each
has its own version of part of the logic.
183
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Hint:
Create an abstract class BankAccount with deposit() and abstract calculateInterest() method.
Implement for SavingsAccount and CurrentAccount.
Explanation:
If the exception represents a condition that a client (calling code) can be handle, we should
create a checked exception.
Example 1: InsufficientBalanceException
Imagine a bank withdrawal method. If someone tries to take ot more than they have, we throw
this exception. The ATM or mobile app can catch it and display, “Not enough funds.” The
program continues running happily.
Example 2: FileFormatException
The program only accepts .csv files for importing data. If someone uploads a .pdf, we throw this.
The caller can say, “Wrong file format. Please upload a CSV.”
Example 3: OrderNotFoundException
In an e-commerce site, a customer checks the status of an order ID that doesn’t exist. We throw
this so the UI can show “Order not found” instead of a system crash.
If the exception represents a programming error, a fundamental flaw in the application logic, or a
condition that cannot be recovered by the client, we should create an unchecked exception.
Example 1: PaymentProcessingFailedException
The payment service has a serious error , maybe wrong credentials or the provider is down. The
app can’t fix this during runtime.
Example 2: DatabaseConnectionFailedException
The app can’t connect to the database at all. Without that, nothing works, so it should fail
immediately.
184
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
In Java, We need to use try-with-resources to close the resources like InputStream, Reader, or
File handles.
import [Link].*;
Any class that implements AutoCloseable (like InputStream, OutputStream, Reader, Writer)
will be closed automatically when the try block ends , even if an exception happens.
This removes the need for a finally block.
Reference: Java’s AutoCloseable Interface Explained | Medium
Explanation:
185
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
We should create them as static methods as they won’t depend on any object state.
public final class MathUtils {
Hint:
Use Static.
186
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
We should create them as static methods as they won’t depend on any object state.
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
[Link]([Link](5, 3)); // 8
[Link]([Link](5, 3)); // 15
}
}
Solution: Use a TreeMap<String, Integer> ; it keeps keys sorted in natural or custom order while
allowing O(log n) operations for insert, lookup, and remove.
187
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Solution: We can achieve this by [Link] and also we can use Streams.
public class Test {
public static void main(String[] args) {
Map<String, Integer> scores = new HashMap<>();
[Link]("Mahesh", 85);
[Link]("NTR", 95);
[Link]("Charan", 92);
[Link]("Prabhas", 88);
Solution: Use a LinkedHashSet, it removes duplicates while keeping the insertion order.
Add all emails from the first list, then from the second list.
188
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
// Count occurrences
for (char c : [Link]()) {
[Link](c, [Link](c, 0) + 1);
}
Solution: Use an ArrayDeque (or LinkedList) and enforce the size manually.
On each insert, if size exceeds 100, remove from the head (poll()), then add the new log to the
tail (offer()).
public class Test {
private static final int MAX_SIZE = 5;
private Queue<String> logs = new ArrayDeque<>();
189
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Note: In the sample, we have taken Max Size as 5, when we try to insert 10 items, first 5 will be
deleted.
Solution: Use a HashMap<Integer, Integer> to store each product ID and its sale count.
Iterate through the list, update counts with getOrDefault(), then scan the map to find the entry
with the highest value.
public class Main {
public static void main(String[] args) {
List<Integer> sales = [Link](101, 102, 101, 103, 101, 102,
103, 103, 103);
// Count occurrences
for (int id : sales) {
[Link](id, [Link](id, 0) + 1);
}
Solution: Use a LinkedHashMap with accessOrder = true, it maintains entries in the order they
were last accessed.
Override removeEldestEntry() to automatically evict the least recently used when capacity is
exceeded.
190
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
while (![Link]()) {
Job job = [Link]();
[Link]("Executing: " + job);
}
Solution:
191
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Solution:
We can use a TreeSet<String> since it stores elements in sorted order and supports range
queries using subSet().
public class Test {
public static void main(String[] args) {
TreeSet<String> products = new TreeSet<>();
[Link]("apple");
[Link]("apricot");
[Link]("banana");
[Link]("blueberry");
[Link]("blackberry");
[Link]("cherry");
How it works:
subSet(prefix, true, end, true) efficiently fetches only items starting with that prefix , no full
scan needed.
Solution:
We can use a Stack<Character>:
Push opening brackets ((, {, [) onto the stack using push().
Pop when we encounter a closing bracket and check if it matches the top.
public class Main {
public static void main(String[] args) {
[Link](isBalanced("{[()]}"));
[Link](isBalanced("{[(])}"));
}
192
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
return [Link]();
}
}
Solution:
Use CopyOnWriteArrayList.
it allows concurrent reads without locking because it works on a snapshot of the array.
Writes (add, remove) create a new copy of the array, so reads never block.
Solution:
Use ConcurrentHashMap<String, AtomicInteger> so increments are thread-safe without explicit
locking.
193
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
LinkedList: better for frequent middle insertions/deletions since no shifting of elements, just
pointer updates.
ArrayList: better for fast random access and adding at end because it uses an array under the
hood
Solution:
When dealing with large files, the key is to read the file in chunks rather than loading the entire
file into memory. This can be done efficiently using BufferedReader or FileInputStream in Java.
By processing the file line-by-line or in smaller byte chunks.
194
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
}
To reduce the impact of garbage collection (GC) in an application, follow these steps:
1. Reduce Object Creation: Avoid creating unnecessary objects. Reuse objects when possible
instead of creating new ones.
2. Use Primitive Types: Prefer int, double, etc., over their object versions (Integer, Double) to
avoid extra memory usage.
195
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Limit Large Collections: Clear or reuse large lists, maps, or arrays instead of letting them
grow endlessly.
4. Avoid Memory Leaks: Remove references to objects (like event listeners or caches) when
they’re no longer needed.
5. Tune GC Settings: Adjust JVM flags (like -Xmx, -Xms) to optimize heap size and GC behavior
based on the app’s needs.
6. Use Object Pools: For frequently created/destroyed objects (like database connections), use
pooling (e.g., ArrayList pooling).
7. Profile & Monitor: Use tools (like VisualVM ) to find memory hotspots and optimize them.
196
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
7. Avoid Hardcoding
Move constants to config files or environment variables.
Use .properties or .yaml for application settings.
8. Write Unit & Integration Tests
Test edge cases, not just happy paths.9+
Use frameworks like JUnit, Mockito.
9. Memory Usage
Avoid creating unnecessary objects in loops.
Reuse immutable objects like String carefully.
Watch out for memory leaks from static references or listeners.
10. Follow Java Language Features Wisely
Prefer StringBuilder for concatenation in loops.
Use Optional to avoid null checks when it makes sense.
Use record for DTOs (Java 16+).
11. Use Logging Properly
Prefer a logging framework (SLF4J, Logback) over [Link].
Log only meaningful info.
Keep sensitive data out of logs.
12. Keep Build & Dependencies Clean
Avoid unused dependencies.
Keep dependencies up to date.
Use dependency management tools like Maven or Gradle consistently.
1. Profiling and Monitoring: We can use profiling tools like JProfiler to identify performance
bottleneck and to monitor the CPU usage, memory consumption, and response times.
2. Database Optimization: Data is very important part of every application, so we need to
optimize the SQL queries. Optimize queries by adding appropriate indexes, rewriting
complex joins, and reducing the number of queries by implementing batch processing.
3. Code Refactoring: Optimized loops and algorithms to reduce time complexity. I also removed
unnecessary synchronization to improve thread performance (Check above question for
coding practices).
4. Caching: Implemented caching strategies using tools like Ehcache to reduce the load on the
database and improve response times for frequently accessed data.
5. Garbage Collection Tuning: Adjusted JVM garbage collection settings to reduce pause times
and improve memory management.
197
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
We can implement retry using
1. Thread – A simple retry
2. Callable
3. Custom Interface
1. Thread – A simple retry
This code tries to run performOperation() up to 3 times, waiting 1 second between each retry if
it fails.
It simulates random failure with a 70% chance, and stops early if the operation succeeds.
If all retries fail, it prints "Retries exhausted".
Code Link: JavaSamples/Scenario46_SimpleRetry.java at main · CodingLyf-Fullstack/JavaSamples
2. Callable
This code defines a generic executeWithRetry method that runs a Callable and retries it up to a
given number of times with a delay between attempts.
It stops and returns immediately if the operation succeeds, otherwise it keeps retrying until the
max retries are reached.
If all attempts fail, it throws the last caught exception to the caller.
Code Link: JavaSamples/Scenario46_Retry_Callable.java at main · CodingLyf-
Fullstack/JavaSamples
3. Custom Interface
Java — Retry Pattern. Ah, the joys of development! Dealing… | by Lucas Amado | Medium
Explanation:
A stack is a fundamental data structure in computer science that follows the last-in, first-
out (LIFO) principle. Imagine a stack of plates: the last plate we add is the first one we can
remove. In programming, stacks are used to manage function calls, track undo/redo actions, and
more.
Key Concepts:
LIFO (Last-In, First-Out): The last element added to the stack is the first one to be removed.
Push: Adds an element to the top of the stack.
Pop: Removes and returns the top element from the stack.
Peek: Returns the top element without removing it.
isEmpty: Checks if the stack is empty.
Size: Returns the number of elements in the stack.
198
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
In Java, a Queue is an interface within the Java Collections Framework that represents a
collection designed for holding elements prior to processing, typically in a First-In, First-Out
(FIFO) manner. This means the element added first to the queue is the first one to be removed.
Key Characteristics:
FIFO Ordering: Elements are processed in the order they were inserted.
Code Explanation:
q1 (Main Queue): This queue always stores the elements in the order required for stack
operations (LIFO). The front of q1 will always contain the element that should be popped next.
q2 (Helper Queue): This queue is used temporarily during the push operation to maintain the
correct order in q1.
push(int x):
All elements from q1 are then moved to q2. This ensures that the new element x is now at
the front of q2, followed by all previous elements in their original order.
Finally, the references of q1 and q2 are swapped. This effectively makes q2 (which now holds
the correctly ordered elements) the new q1, and the old q1 becomes the new q2 (which is
now empty).
pop(): Since q1 always has the most recently added element at its front, a simple poll() operation
on q1 removes and returns the top element.
peek(): Similarly, peek() on q1 returns the top element without removing it.
isEmpty() and size(): These operations directly leverage the corresponding methods of q1.
Code Steps:
199
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Step 1: push(A):
Step 2: push(B):
In a circular array queue, the idea is that the array behaves like a circle rather than a straight
line. When we reach the end of the array, we wrap around to the beginning instead of stopping.
This allows us to reuse empty spaces at the front of the array once elements are dequeued.
Explanation there itself in the code: Check the logs to understand it better
}
}
Explanation:
1. filter(seen::add) means: for every number, try adding it into the HashSet seen.
2. [Link](x) returns true the first time a number is inserted, and false if that number was
already in the set.
3. Because filter keeps only the elements where the condition is true, the stream passes the
first time each number appears and drops later duplicates.
}
}
Explanation:
filter(i -> ) means: for every number, try adding it into the HashSet seen.
[Link](x) returns true the first time a number is inserted, and false if that number was
already in the set.
Because we use , the filter keeps only the elements where add() returned false.
That means only duplicates pass through the streams, and first occurrences are dropped.
201
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
distinct() removes duplicates, leaving only unique numbers.
sorted([Link]()) then sorts those unique numbers in descending order
(largest -> smallest).
By default, sorted() uses natural order (ascending). When we pass
[Link](), it flips that natural order.
Behind the scenes, the stream collects elements, then applies the comparator to arrange
them before building the final list.
For the input [11, 11, 1, 3, 5, 6, 5]:
After distinct() -> [11, 1, 3, 5, 6]
After sorted(reverseOrder()) -> [11, 6, 5, 3, 1]
Explanation:
1. [Link]() : creates a stream from the list [1, 2, 4, 41, 4].
202
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
1. allMatch(i -> i % 2 == 0) -> checks if every element in the stream satisfies the condition (even
in this case).
2. Since all numbers are even, it returns true.
Other flavours
1. anyMatch
Returns true if at least one element satisfies the condition.
boolean hasEven = [Link]().anyMatch(i -> i % 2 == 0);
// true, because even numbers exist
2. noneMatch
Returns true if no elements satisfy the condition.
boolean noOdd = [Link]().noneMatch(i -> i % 2 != 0);
// true, because there are no odd numbers
Similar Question:
1. Check if Any String Starts with 'A'
List<String> nameList = [Link]("Banana", "Apple", "Cat", "Andrew");
Use - anyMatch
203
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
.stream()
.filter(i -> [Link](i).startsWith("1"))
.toList();
[Link](startWith1);
}
}
Explanation:
1. [Link]() -> creates a stream of [10, 12, 20, null, 19, 30].
Caution: when i is null, [Link](null) returns the literal string "null", so it won’t
throw an exception (but it also won’t match).
Explanation:
[Link](...) Creates a list: ["Telugu", "Tamil", "Malayalam"]
[Link]() Turns that list into a stream , basically, a way to process each word one by one
3..filter(...): Keeps only the words that satisfy a condition , in this case, words that read the same
backward and forward (palindromes).
Inside the filter:
[Link]() makes the word lowercase (to ignore case).
new StringBuilder([Link]()).reverse() reverses the word
contentEquals(...) checks if the original word equals its reverse.
.toList() Collects the remaining (filtered) words into a new list.
204
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](findPalindromeStrings)
sPrints the final list of palindrome words.
1. Find out all the even numbers that exist in the list using Stream functions
Hint: Use .filter
2. Find out the FIRST even numbers that exist in the list using Stream functions
Hint: Use .filter and .findFirst
3. Java 8 program to perform cube on list elements and filter numbers greater than 50.
Hint: Use .map and .filter
232 Streams 11: Merge two unsorted arrays into single sorted array
public class SteamsSample {
public static void main(String[] args) {
int[] a = new int[] { 4, 2, 7, 1 };
int[] b = new int[] { 8, 3, 9, 5 };
int[] c = [Link](
[Link](a).boxed(), [Link](b).boxed())
.sorted()
.mapToInt(i -> i)
.toArray();
[Link]([Link](c));
}
}
Explanation:
205
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
234 Streams 12: Get 3rd highest element from the list
public class SteamsSample {
public static void main(String[] args) {
List<Integer> listOfIntegers = [Link](71, 18, 42, 21, 67, 32,
95, 14, 56, 87);
s1 = [Link]([Link](""))
206
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
.map(String::toUpperCase)
.sorted()
.collect([Link]());
s2 = [Link]([Link](""))
.map(String::toUpperCase)
.sorted()
.collect([Link]());
if ([Link](s2)) {
[Link]("Two strings are anagrams");
} else {
[Link]("Two strings are not anagrams");
}
}
}
An anagram is when two words or phrases use the same letters with the same frequency, just in
a different order.
Example: "listen" and "silent" are anagrams.
Explanation:
[Link]("") -> map(String::toUpperCase) -> sorted() breaks the string into characters, makes
them uppercase, and sorts them alphabetically.
.collect([Link]()) puts the sorted characters back into a single string.
If both sorted strings are equal, then they’re anagrams (same letters, same count, just
rearranged).
[Link](sumOfDigits);
}
}
[Link]().filter(list2::contains).forEach([Link]::println);
207
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
[Link](reversed);
}
}
Explanation:
.map(s -> new StringBuilder(s).reverse()): reverses each word
.collect([Link](" ")): joins them back with spaces.
Explanation:
flatMap(s -> [Link]([Link](" ")))
Each element in strings is a sentence like "java scala ruby".
[Link](" ") breaks it into words : ["java", "scala", "ruby"].
[Link](...) turns that array into a stream of words.
flatMap flattens all those small word-streams into one continuous stream of words across all
sentences.
o So instead of [["java","scala","ruby"], ["java","react","spring","java"]]
o We get a single stream: ["java","scala","ruby","java","react","spring","java"].
208
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
240 Streams 18: Convert the list of sentences into unique words.
public class SteamsSample {
public static void main(String[] args) {
List<String> sentences = [Link]("java is cool", "cool code in
java");
Set<String> words = [Link]()
.flatMap(s -> [Link]([Link](" ")))
.collect([Link]());
[Link](words);
}
}
}
}
Output:
Longest Strings [pineapple, blueberry]
209
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
244 Streams 22: Find the longest common prefix using Java streams:
public class SteamsSample {
public static void main(String[] args) {
}
}
reduce takes two elements at a time (s1 and s2), applies a function, and returns a result.
That result will then be compared with the next element in the stream.
First compares "flower" and "flow" : gives "flow".
Then compares "flow" and "flight" : gives "fl".
Inside the lambda:
int[] array = { 1, 4, 9, 6, 2, 7, 8 };
Integer maxProduct = [Link](0, [Link])
.map(i -> [Link](i + 1, [Link])
.map(j -> array[i] * array[j])
.max()
.orElse(0))
.max()
.orElse(0);
[Link](maxProduct);
}
}
210
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The problem is about finding the maximum product that can be formed by multiplying any two
different numbers in the array.
Think of it like trying every pair, calculating their product, and then just picking the largest
one.
For example, in {1, 4, 9, 6, 2, 7, 8}, the biggest product is from 9 × 8 = 72.
Step by step
1. [Link](0, [Link])
o This creates a stream of all indices from 0 to [Link] - 1.
o Each index i represents the first number in a pair.
2. [Link](i + 1, [Link])
o For each i, this creates another stream of indices starting from i+1 to the end.
o Why i+1? To avoid repeating pairs and avoid multiplying a number with itself.
o So if i = 2 (say number 9), it pairs 9 with every number after it.
3. .map(j -> array[i] * array[j])
o For each valid pair (i, j), it multiplies the two numbers.
o Example: if i=2 (9) and j=6 (8), result is 72.
4. Inner .max().orElse(0)
o Among all products generated for a fixed i, this picks the largest one.
o Example: if i=2 (9), the products are 9×6=54, 9×2=18, 9×7=63, 9×8=72. The max here
is 72.
5. Outer .max().orElse(0)
o Now it compares the “best product” for each i and keeps the overall maximum.
o That gives us the largest product across the entire array.
211
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
[Link]() : converts everything to lowercase so "Java" and "java" are treated
the same.
Result: "java is fun and java is powerful"
.split("\\s") : splits the string by whitespace into words.
Result: ["java", "is", "fun", "and", "java", "is", "powerful"]
[Link](...) -> turns that array into a stream.
.collect([Link]([Link](), [Link]()))
groupingBy([Link]()) : groups by the word itself.
[Link]() : counts how many times each word appears.
212
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Questions:
1. Find students from Hyderabad with a grade greater than 8.0
2. Find the student with the highest grade
3. Count the number of students in each department
4. Find the average grade per department
5. List students sorted by age and then by grade
6. Create a comma-separated list of student names
7. Check if all students are above 18
8. Find the department with the most students
9. Divide students into those who have grades above 8.0 and below
10. Find the student with the longest full name
Code link: StreamsScenarios/[Link] at main · CodingLyf-
Fullstack/StreamsScenarios
Questions:
[Link] the names of all Employees in the CS department, sorted by age in descending order
2. Group Employees by department and count how many Employees are in each department
[Link] the youngest female Employee.
4. Create a map of department -> list of Employee names.
5. Find the average age of Employees in each department.
6. Get a list of unique departments Employees belong to
213
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
7. Partition Employees into male and female groups, then list their names.
8. Group employees by department, then within each department find the oldest employee
9. Build a map of gender with average age of employees sorted by average age descending
10. For each department, find the youngest employee, but instead of returning the employee
object, return only their name in uppercase.
11. Return a map where keys will be first letter of the name and value will the set of names
starting with that letter, no solution provided, try on your own.
Code link: StreamsScenarios/[Link] at main · CodingLyf-
Fullstack/StreamsScenarios
Questions:
1. City with the second highest population
2. Group by first character of name, then max population in each group
3. Average population of top 3 most populated cities.
4. Map of population range -> city names.
5. Using reduce: String of cities ordered by population.
Expected output: Hyderabad(1200000) > Mumbai(800000) > Bangalore(450000) >
Chennai(60000) > Delhi(12000)
Code link: StreamsScenarios/[Link] at main · CodingLyf-
Fullstack/StreamsScenarios
Spring
252 Spring 1: What is Spring boot?
Spring Boot is a framework built on top of Spring that makes it faster and easier to
develop Java applications. Normally with Spring, we have to do a lot of manual setup,
configuration, and XML files. Spring Boot removes that pain by giving auto-configuration,
214
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
embedded servers, and prebuilt dependencies. So, we can just focus on writing business logic
instead of wiring everything.
Indirect Question:
Spring Boot 3.x makes some big changes. First, it switches from the old javax.* packages
to the new jakarta.* ones because it now uses Jakarta EE 10. It also requires Java 17 or higher, so
we get access to modern Java features. Another big addition is support for GraalVM native
images, which lets us build apps that start super-fast and use less memory , perfect for cloud and
container environments.
Yes, Spring Boot can be used to build non-web applications. We can exclude the web-starter
dependency and use CommandLineRunner or ApplicationRunner to run code at startup. It is
often used for batch jobs, schedulers, or standalone services.
Easy to use: The majority of the boilerplate code required to create a Spring application is
reduced by Spring Boot.
Scalable: Spring Boot apps are intended to be scalable. This implies they may be simply
scaled up or down to match the application’s needs.
Production-ready: Metrics, health checks, and externalized configuration are just a few of
the features that Spring Boot includes and are designed for use in production environments.
Hot reloading allows developers to make changes to their code, resources, or configuration
files while an application is running, and see those changes immediately reflected without
needing to restart the application.
254 Spring 3: What are embedded containers / servers in Spring and what is the default one?
how to add Jetty for example?
In normal Java web apps, we used to deploy the WAR file into an external server like Tomcat or
Jetty. That meant installing and managing the server separately.
Spring Boot ships with an embedded server inside the application.
The app is packaged as a JAR (not WAR).
215
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When we run it, the server starts along with the code.
We don’t need to deploy to any external container.
What’s the default server?
By default, Spring Boot uses Apache Tomcat as the embedded server.
So, if we don’t configure anything, we are already running on Tomcat without even
realizing it.
Suppose we prefer Jetty instead of Tomcat. Here is what we do in Maven:
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Spring Boot: It is built on top of Spring and provides auto-configuration, embedded servers,
and starter dependencies. It cuts down setup time and allows us to build production-ready
apps with less effort.
In short: Spring is the foundation; Spring Boot is the fast and modern way to use Spring.
216
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The Spring MVC architecture is a Model-View-Controller (MVC) framework used for building
web applications in Java. It promotes a clear separation of concerns, making applications
more modular, maintainable, and easier to develop.
217
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Responsible for generating the final output (e.g., HTML, JSON, XML) to be sent
back to the client.
@Configuration: This annotation configures the beans and packages in the class path.
So, using @SpringBootApplication at the main class makes the application ready with all these
features at once.
For example, if a Car class needs an Engine, instead of writing new Engine(),Spring inject the
engine for us. This reduces coupling, makes testing easier (we can inject mock objects), and
improves maintainability.
@Component
class Engine {}
@Component
class Car {
@Autowired
218
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Interview Tip:
Dependency Injection is about providing an object with its dependencies from the
outside rather than creating them internally. This makes the code loosely coupled, easier
to maintain, and easier to unit test.
In Spring, we can do this using constructor injection, setter injection, or field injection
with annotations like @Autowired and @Qualifier.
Mention about how you implemented a repository and service layers in your project.
Example: In a service class which needs repository, we inject the repository instead of
creating it, which makes testing and maintenance straightforward.
Indirect Questions:
IoC is achieved in Spring through Dependency Injection (DI), where the Spring container
manages the lifecycle and dependencies of the objects, freeing the developer from manually
instantiating dependencies.
2. How does Spring boot makes Dependency injection easier compared to traditional Spring
MVC?
Spring boot makes dependency injection easier compared to traditional Spring by auto-
configuring the beans and reducing the need for explicit configuration. In traditional Spring, we
had to define beans and their dependencies in XML files or with annotations, which can be
complex for large applications.
219
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context =
[Link]([Link], args);
Bean Lazy (beans created Eager by default (all singleton beans created at
Initialization only when requested) startup)
220
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
XmlBeanFactory ClassPathXmlApplicationContext,
Configuration (deprecated after AnnotationConfigApplicationContext,
Spring 3.x) WebApplicationContext
Rarely used today, Default choice for modern Spring & Spring Boot
Use Case
legacy/simple apps apps
260 Spring 9: What is the difference between @Component, @Service, and @Repository?
@Component: The most generic annotation. It marks a class as a Spring bean.
@Service: A specialization of @Component, used for classes that hold business logic. This
makes code easier to understand since we know it belongs to the service layer.
So basically, they all register beans with the container, but @Service and @Repository give extra
meaning and behaviour for their specific layers.
221
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
Think of it like building a house: We wouldn’t ask an electrician to lay the foundation, and we
wouldn’t ask a plumber to build the roof. Each expert should focus on their own work. In the
same, In Spring, each layer has its job, and separating them keeps things clear, safe, and easier
to maintain.
Controller layer: Handles HTTP requests and responses. It is the entry point where the
outside world talks to our app.
DAO (Data Access Object) layer: Talks to the database. It only cares about saving,
reading, updating, and deleting data.
Why separate?
2. Easier to change: We can swap a database or change business rules without touching
controllers.
@Repository annotation is not strictly required when we use Spring Data JPA.
}
So, what is the point of @Repository then?
It is mainly about exception translation. If something goes wrong in the database (like a
SQLException), @Repository tells Spring to wrap it into a generic DataAccessException. This way,
the error handling stays consistent
222
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
This makes the application flexible and easier to configure across different environments (dev,
test, prod).
Additional Question:
1. How will you configure different Databases in your App for different environments?
We can do using [Link] and Profile. Spring gives us profiles like dev, test,
and prod. Each profile can have its own configuration. When the app runs, we simply tell Spring
which profile to use, and it picks the right settings.
The most common way is to create different property files for each environment like
[Link], [Link]. When we switch the profile, Spring
automatically loads the right file.
Sometimes it is not just the properties that change, the beans themselves need to be
different.
In that case, we can use @Profile.
@Configuration
public class DataSourceConfig {
@Bean
@Profile("dev")
public DataSource devDataSource() {
@Bean
@Profile("prod")
public DataSource prodDataSource() {
}
}
223
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
myapp.server_url=[Link]
MYAPP_SERVER_URL=[Link] # from environment variable
All of these map correctly to serverUrl in MyAppProperties.
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
private String serverUrl;
// getter & setter
}
263 Spring 12: How many ways dependency injection can be done or Types of Dependency
Injection?
Spring supports three main ways:
Constructor Injection
Setter Injection
Field Injection
Constructor Injection: Here, we pass dependencies using the class constructor.
@Component
class Car {
private final Engine engine;
@Autowired
public Car(Engine engine) {
[Link] = engine;
}
}
Setter Injection: We provide Dependencies are passed through setter methods. It is good when
dependencies are optional
@Component
class Car {
224
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Autowired
public void setEngine(Engine engine) {
[Link] = engine;
}
}
Field Injection: Dependency is directly injected into the field using @Autowired. It is very easy
but not recommended for large projects since it makes testing and refactoring harder.
@Component
class Car {
@Autowired
private Engine engine;
}
Interview tip: Always say constructor injection is best practice because it makes the class
immutable and easier to test.
Indirect Questions:
225
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Now Instead of XML files, we can configure Spring beans using annotations. This is called
annotation-based configuration.
// Constructor injection
@Autowired // Optional since Spring 4.3 if there's only one constructor
public MyApp(GreetingService greetingService) {
[Link] = greetingService;
}
226
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Point to remember: If there are multiple beans of the same type, Spring throws an error unless
we use @Qualifier or @Primary.
Indirect Question:
1. How would you achieve the same thing that the auto-wired annotation does without using
the annotation?
Instead of @Autowired, we declare beans in a @Configuration class:
@Configuration
class AppConfig {
@Bean
public Service service() {
return new ServiceImpl();
}
@Bean
public Client client() {
return new Client(service()); // manual injection
}
}
Here, Client gets Service injected, same as @Autowired.
@Autowired is just a shortcut for dependency injection. Without it, we do the wiring explicitly in
XML or @Bean methods.
2. Is Autowired is mandatory when there is only one constructor?
Autowired is Optional since Spring 4.3 if there's only one constructor
Why we need it: When there are multiple beans of the same type, Spring gets confused.
@Qualifier tells Spring to pick the exact one using the name.
How it works: We need to give the bean a name and then point to it when injecting.
@Component("creditCard")
class CreditCardPayment implements Payment {}
@Component("debitCard")
class DebitCardPayment implements Payment {}
@Component
class PaymentService {
@Autowired
@Qualifier("creditCard") // pick credit card specifically
private Payment payment;
}
@Primary
227
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Why we need it: If multiple beans exist but one is used most often, then we can mark it as
Primary.
How it works: Mark one bean as @Primary, and Spring will pick it by default when we use
@Autowired without qualifiers.
@Component
@Primary
class CreditCardPayment implements Payment {} // default
@Component
class DebitCardPayment implements Payment {}
@Component
class PaymentService {
@Autowired
private Payment payment; // gets CreditCardPayment by default
}
Indirect Questions:
1. How do you handle multiple beans of the same type in Spring??
Use @Qualifier with @Autowired to specify which bean to inject. This ensures the
correct bean is selected when duplicates exist.
2. When you use both @Primary and @Qualifier, which one will take precedence?
When both @Qualifier and @Primary are used in, @Qualifier takes
precedence. @Primary indicates a default bean to use when multiple beans exist,
while @Qualifier allows for very specific bean selection. When both are present, Spring
prioritizes the bean identified by @Qualifier
3. Two beans of same type are found and Spring throw NoUniqueBeanDefinitionException. How
would you resolve it?
Use @Qualifier with @Autowired to specify which bean to inject. This ensures the
correct bean is selected when duplicates exist.
4. There is only one bean but you annotated with @Qualifier and @Primary, how does it affect?
If there is only one bean of that type:
@Primary has no effect, because there is nothing to choose between.
@Qualifier also doesn’t matter, the single bean will be injected regardless.
They only come into play when multiple beans of the same type exist.
228
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]=jdbc:mysql://localhost:3306/test
[Link]=root
Indirect Question:
1. When do you prefer .properties and .yml file?
For simplicity and small projects: [Link] might be preferred due to its
directness.
For complex, hierarchical configurations and improved readability: [Link] is generally
considered superior due to its structured nature and support for various data types.
Interview Tip: These file helps us to keep configs outside the code, so we can change them per
environment without touching Java classes.
268 Spring 17: What is the use of @Value / How to load config values dynamically?
@Value is used to inject values from [Link] or [Link] into our
code.
[Link]=MySpringApp
@Component
class Config {
@Value("${[Link]}")
private String appName;
Indirect Question:
1. How will you read values mentioned in properties file? Using @value
2. If you want to inject dynamic port from a different config file, how will you use value?
@Value("${[Link]}")
private int port;
229
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
269 Spring 18: What is the use of @ConfigurationProperties / How to load config values
dynamically?
@ConfigurationProperties is a Spring annotation used to bind external configuration (like
[Link] or [Link]) to a Java class. Instead of reading each property with
@Value, we can map a whole group of related properties into a strongly-typed class.
app:
email:
host: [Link]
port: 587
username: user@[Link]
@Component
@ConfigurationProperties(prefix = "[Link]")
public class EmailProperties {
private String host;
private int port;
private String username;
270 Spring 19: How do profiles work in Spring boot, Explain about @Profile?
In the real time projects, we might need different configurations for different
environments like Prod, QA and Dev.
This is where profiles come into picture. Spring boot allows us to manage application
configurations and components based on the environment in which the application is running.
This can be done through various methods:
application-{profile}.properties or application-{profile}.yml: Separate configuration files are
created for each profile (e.g., [Link], [Link]).
@Profile annotation: This annotation is used on classes
(e.g., @Configuration, @Component, @Service, @Repository) or methods to indicate that
they should only be loaded or activated when a specific profile is active
Key points:
Profiles are activated at run time using JVM system properties: -[Link]=prod.
Or Using [Link] property, Set in [Link], [Link]
@Profile
The @Profile annotation used to conditionally register beans or load configuration based on the
active profiles.
230
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
It is applied to:
@Configuration classes: To load specific configuration classes only when a particular profile is
active.
@Configuration
@Profile("production")
public class ProductionConfiguration {
// ... Beans specific to production environment
}
@Service
@Profile("!dev") // Active when 'dev' profile is NOT active
public class ProdUserServiceImpl implements UserService {
// ... Production-specific user service implementation
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
// ... Production data source
}
}
231
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
1. How Spring Boot knows what to configure?
Spring Uses conditional annotations like:
232
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
7. How to tell auto-configuration not to create bean when already bean exists?
Use @ConditionalOnMissingBean
@Bean
public Service service() {
return new Service(repository());
}
@Bean
public Repository repository() {
return new Repository();
}
}
Here, service() depends on repository(). Even though we call repository() directly, Spring ensures
the same singleton Repository is used.
@Bean:
@Bean is a method-level annotation. It tells Spring: “The object returned by this method
should be registered as a bean in the Spring context.”
We can declare @Bean methods in both @Configuration and @Component classes, but
there's an important difference, if one @Bean method calls another in a @Component class, we
might accidentally create multiple instances instead of getting the singleton behaviour.
233
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Component
public class AppConfig {
@Bean
public Service service() {
return new Service(repository());
}
@Bean
public Repository repository() {
return new Repository();
}
}
When we call repository() directly, Spring may create multiple beans.
Indirect Question:
1. Why do you sometimes get multiple instances of a bean if you don’t use @Configuration but
just @Bean in a class?
Without @Configuration, Spring doesn’t proxy the class, so calling one @Bean method from
another creates a new instance instead of reusing the singleton.
2. What happens if a @Bean method calls another @Bean method inside the same class?
In a non-@Configuration class, calling a @Bean method directly bypasses Spring, so it creates
a fresh object instead of using the Spring-managed bean.
3. Can you use @Bean without @Configuration? What are the implications?
Yes, it works, but we lose singleton guarantees between methods, and Spring simply registers
whatever object the method returns.
234
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
For Example, If we use a class from an outside library because we can't add @Component to it
as we don't have control to its code. Instead, we use @Bean in our own configuration class. We
write a method that creates the object for that library class and returns it.
@Bean
public DataSource dataSource(Environment env) {
return [Link]()
.url([Link]("[Link]"))
.username([Link]("[Link]"))
.build();
}
For Example. DataSource is a class from a third-party JDBC library, not our own code, so we can’t
mark it with @Component. Instead, we create it as a Spring bean by writing a @Bean method
that returns a DataSource object with the right configuration.
Additional questions:
235
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
236
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When to use: For application-wide shared resources, like configuration objects, caches,
or global services.
Indirect Questions:
1. If multiple components autowire the same service, do they share the same object?
Yes, with singleton scope, they all share the same instance
2. If I autowire a prototype bean in a singleton bean, will it be a new object every time?
No, the singleton will get one instance at initialization unless we use @Lookup or
ObjectFactory.
3. With @Scope("request"), Will two HTTP requests get the same bean instance?
No, each request gets a new instance.
4. If you autowire Prototype bean in singleton bean how many instances of prototype bean
would be created?
If we autowire a prototype bean into a singleton bean, only one instance of the
prototype bean gets created at the time of injection.
That same instance will be reused by the singleton throughout its lifetime.
Spring doesn’t create a new prototype object every time we call it from the singleton.
To get a fresh prototype on each use, we need ObjectFactory or Provider.
@Component
@Scope("prototype")
class PrototypeBean {
public PrototypeBean() {
[Link]("New PrototypeBean created");
}
}
@Component
class SingletonBean {
@Autowired
private ObjectFactory<PrototypeBean> objectFactory;
@Autowired
private Provider<PrototypeBean> provider;
237
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The singleton bean is created once at application startup. At that time, there is no active
HTTP request, so the request-scoped bean does not exist yet. If Spring tried to inject the request-
scoped bean directly into the singleton during construction, it would fail because the context for
the required scope (HTTP request) isn't active.
The Solution: Scoped Proxy
Spring's solution is to not inject the actual request-scoped bean. Instead, it injects a proxy object
that implements the same interface (or extends the class) as the request-scoped bean.
o This proxy is created at startup and injected into the singleton.
o Whenever a method is called on this proxy during an HTTP request, the proxy
delegates the call to the real request-scoped bean instance that was created for
that specific request.
How to do it: We must specify proxyMode = ScopedProxyMode.TARGET_CLASS (for class-based
proxies) or [Link] (for interface-based proxies) in
the @Scope annotation of the request-scoped bean.
Refer below question to understand it more.
How proxyMode works in Spring and how does it help? (Refer Question No. 379, Spring 128)
7. How does scope behave in multithread rest controller?
Singleton (default): Only one instance exists for the entire application. Multiple threads (HTTP
requests) share the same instance, so instance variables are shared across threads. we must
avoid mutable state unless properly synchronized.
Prototype: A new instance is created each time it is requested from the Spring context. In a REST
controller, if we inject a prototype bean, Spring resolves it once at startup for the singleton
controller. To get a fresh prototype per request, we need a proxy (@Scope("prototype",
proxyMode = ScopedProxyMode.TARGET_CLASS)).
Request / Session / Web Scopes: These scopes create a new bean per HTTP request or session,
so each thread (request) gets its own instance. Using proxies ensures the singleton controller can
safely access these shorter-lived beans.
Reference: The Scope of Beans in Spring Boot: A Comprehensive Guide | by Dev Cookies |
Medium
Note: There are many life cycle methods but here I am mentioning only the important. We can
read from the link below and check all the methods in the image
238
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Initialization (@PostConstruct)
After dependencies are injected, Spring calls methods marked with @PostConstruct.
This is where we put setup logic (like opening a DB connection, loading configs).
It is the safest place to initialize things because all dependencies are already injected.
@Component
public class DatabaseInitializer {
@PostConstruct
public void init() {
[Link]("DB connection established!");
// Load initial data, cache, etc.
}
}
4. Destruction (@PreDestroy)
When the Spring container shuts down, methods marked with @PreDestroy run.
Used for cleanup (closing DB connections, releasing resources).
Prevents memory leaks by properly releasing resources.
@Component
public class CacheManager {
@PreDestroy
public void cleanup() {
[Link]("Clearing cache before shutdown!");
// Close cache, release memory
}
}
239
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The @ConditionalOnProperty annotation creates the bean only if the specified property is
present in the environment and optionally has a specific value. It is commonly used to enable or
disable beans based on application configuration properties
@Bean
@ConditionalOnProperty(name = "[Link]", havingValue = "true")
public EmailService emailService() {
return new EmailService();
}
240
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The @ConditionalOnClass annotation creates the bean only if the specified class is present on
the classpath. It is useful for creating beans that depend on the presence of a particular library
or class.
@Bean
@ConditionalOnClass(name = "[Link]")
public MongoTemplate mongoTemplate() {
return new MongoTemplate();
}
The @ConditionalOnMissingBean annotation creates the bean only if the specified bean type or
name is not already defined in the application context.
@Bean
@ConditionalOnMissingBean
public MyBean defaultBean() {
return new MyBean();
}
The @ConditionalOnBean annotation creates the bean only if the specified bean type or name
is already defined in the application context. This annotation is useful for defining beans that
depend on the presence of other beans.
@Bean
@ConditionalOnBean([Link])
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
Real Time Example: Say we want our Spring Boot app to work with Firestore in dev and
MongoDB in prod.
[Link]: [Link]=firestore # or mongo
@Configuration
public class DatabaseConfig {
@Bean
@ConditionalOnProperty(name = "[Link]", havingValue = "firestore")
public FirestoreService firestoreService() {
return new FirestoreService();
}
@Bean
@ConditionalOnProperty(name = "[Link]", havingValue = "mongo")
public MongoService mongoService() {
return new MongoService();
}
}
241
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
This way, we don’t have to change the code when moving environments, just changing the
property will work.
Indirect Questions:
[Link] would you enable or disable a bean without touching the code, just by configuration?
Use @ConditionalOnProperty.
2. If I want to create a bean only if MongoDB driver is on the classpath, how do I handle it?
Use @ConditionalOnClass.
3. Suppose you already have a custom bean defined. How do you stop Spring Boot from creating
its default one?
Use @ConditionalOnMissingBean.
@Configuration
@Conditional([Link])
public class ProdConfig {
@Bean
public DataSource prodDataSource() {
return new HikariDataSource();
}
}
Here, the bean will only load if [Link]=prod.
242
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
CommandLineRunner
It is an interface in Spring Boot.
If the class implements it, the run(String... args) method will execute right after the Spring
ApplicationContext is loaded and before the application fully starts serving requests.
The method gives the access to the raw command-line arguments as a String[].
@Component
public class MyStartupRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
[Link]("App started with args: " + [Link](args));
ApplicationRunner
ApplicationRunner is another interface in Spring Boot that serves a similar purpose
to CommandLineRunner, but it provides a more structured way to access and parse command-
line arguments. The main difference is: instead of giving a raw String[], it provides an
ApplicationArguments object.
Indirect Questions:
1. How do you run some logic right after Spring Boot starts?
Using CommandLineRunner or ApplicationRunner.
2. If you just need to check if a simple flag like --enable-feature was passed, which runner would you
use?
CommandLineRunner is enough since we are just checking raw args.
3. If your Spring Boot app needs to read --db-url=localhost:3306 from command line, which runner is
better?
ApplicationRunner because it easily handles --key=value arguments.
4. If you had both CommandLineRunner and ApplicationRunner in your project, which one runs
first?
Both run, order depends on @Order annotation or Ordered interface.
@Component
@Order(1) // Runs first
public class FirstRunner implements CommandLineRunner { ... }
@Component
243
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Component
class B {
private final A a;
public B(A a) { this.a = a; }
}
Here, A needs B and B needs A.
When Spring tries to create them, it gets stuck in a loop and fails with a
BeanCurrentlyInCreationException.
Lazy tells Spring: “don’t create this bean immediately, create it only when needed.”
This breaks the cycle because Spring can first create one bean and keep a proxy for the other.
@Component
class A {
private final B b;
public A(@Lazy B b) { this.b = b; }
}
Now Spring can create A first, and only when we call [Link](), it will initialize B.
Constructor injection creates problems in circular dependency because both beans are required
immediately.
But if we use a setter, Spring can first create the object and later “inject” the dependency.
@Component
class A {
private B b;
@Autowired
public void setB(B b) {
this.b = b;
}
}
This way, Spring can create A without needing B instantly.
244
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Sometimes, circular dependency is a code smell. It means the classes are too tightly coupled.
Example: Instead of having A depend on B and B depend on A, write a third-class ‘C’ and move
shared logic , and both A & B classes depend on C.
@Component
class C {
// shared logic
}
@Component
class A {
private final C c;
public A(C c) { this.c = c; }
}
@Component
class B {
private final C c;
public B(C c) { this.c = c; }
}
281 Spring 30: What is eager loading and lazy loading of beans??
By default, Spring creates all singleton beans eagerly at the time the ApplicationContext starts.
@Component
class EagerBean {
public EagerBean() {
[Link]("Eager bean created!");
}
}
When we run the app, we will see "Eager bean created!" printed immediately, even if we never
used it.
Lazy loading means: Create the bean only when it is first requested (injected or accessed).
245
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
246
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
ViewResolver: If the controller returns a view name (like "home"), ViewResolver decides which
actual page (like [Link] or [Link]) should be shown.
View: Finally, the view (JSP, Thymeleaf, etc.) is rendered with the model data, and the response
goes back to the client.
Full Lifecycle in One Line:
Request > DispatcherServlet > HandlerMapping > HandlerAdapter > Controller > ViewResolver >
View > Response
Reference: The DispatcherServlet: The Engine of Request Handling in Spring Boot | by Lakshya
Agarwal | Medium
Indirect Question: What happens internally when you hit a REST API in Spring Boot?
247
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
We can just do
User u = new User(1, "CodingLyf");
[Link](u);
The ORM framework will convert that into SQL internally and talk to the database.
Hibernate is the popular ORM Framework.
248
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
// getters, setters
}
Here we just call save(). Hibernate internally does: INSERT INTO users (id, name) VALUES (1,
‘CodingLyf’);
286 Spring 35: What is JPA and how does it different from Hibernate?
Originally, Java developers used JDBC to talk to databases. But JDBC code was repetitive and
messy:
Connection con = [Link](...);
PreparedStatement ps = [Link]("INSERT INTO user VALUES (?, ?)");
[Link](1, 1);
249
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](2, "CodingLyf");
[Link]();
We had to write SQL everywhere, handle connections, manage transactions. Too much
boilerplate.
To fix this, Hibernate came along. Hibernate is an ORM (Object Relational Mapping) framework
that maps Java classes to DB tables. So instead of SQL, we work with objects:
@Autowired
UserRepository repo;
250
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](1); // SELECT
[Link]("CodingLyf"); // Custom query by name
In Short:
JPA (Java Persistence API) is a specification (or interface) for ORM (Object-Relational Mapping) in
Java.
Hibernate is a concrete implementation of JPA.
Indirect Questions?
1. What will happen under the hood when you run [Link]()? (Refer Question No. 307 Spring
55 )
Using the @Configuration class: This is a more advanced way to configure a database
connection. We can create a @Configuration class and specify the connection properties in the
class. Spring Boot will then use the @Configuration class to configure the database connection.
# Database URL
[Link]=jdbc:mysql://localhost:3306/mydatabase
# Database credentials
[Link]=myuser
[Link]=mypassword
# Formats the SQL queries printed in logs, so they look more readable (with line
breaks/indentation).
[Link].format_sql=true
3. How do you make sure existing database schema matches the entity mappings.
We need to set [Link]-auto=validate, which makes Hibernate check if
the entities match the database schema at startup.
Better to use a migration tool like Flyway or Liquibase to version and align schema
changes with entity updates.
251
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Hibernate
Hibernate is an ORM (Object Relational Mapping) framework built on top of JDBC.
252
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Instead of writing SQL manually, we work with objects, and Hibernate translates them
into SQL behind the scenes.
It handles connection management, caching, lazy loading, and relationships
(@OneToMany, @ManyToOne).
Provides HQL (Hibernate Query Language) and Criteria API for queries.
Hibernate vs JDBC
Hibernate converts Checked Exceptions to Runtime exceptions, In JDBC we need to handle
SQLException
Hibernate supports caching, where JDBC doesn’t.
Hibernate has inbuilt transaction support, where In JBDC we have manage explicitly
288 Spring 37: How do you use @Entity, @Table, @Column in JPA?
@Entity
Marks a Java class as a JPA entity (i.e., a table in the database).
Without @Entity, JPA won’t know that this class should be mapped to a database table.
import [Link].*;
253
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If we want to customize column name, length, nullability, uniqueness, etc., use @Column.
@Entity
@Table(name = "users")
public class User {
@Id
@Column(name = "user_id") // custom column name
private int id;
Indirect Questions:
[Link] do you mark a column as not nullable or unique?
To make sure JPA saves only unique values, we define a unique constraint on the entity field.
This can be done with @Column(unique = true).
Use @Column(nullable = false, unique = true)
2. How does JPA decide table/column names if you don’t give any?
JPA uses the class name as table name and field names as column names.
3. What happens if you don’t give @entity to class?
If we don’t give @Entity on a class, JPA will not treat it as a database entity, it will just behave
like a normal Java class means no table will be created.
4. Can we make @Entity as final class?
No, we should not make an @Entity class final
JPA providers (like Hibernate) often use proxy classes at runtime to enable features like lazy
loading.
To create these proxies, they extend the entity class.
If the entity is final, it cannot be subclassed, so Hibernate can’t create the proxy which
breaks lazy loading and other internal mechanisms.
5. Can we make @Entity as Abstract class?
Yes, it can be abstract, and other entities can extend it
289 Spring 38: What are best practices or rules while creating the Entity?
Use a Primary Key (@Id)
Every entity must have an identifier. Always define a primary key with @Id.
Avoid Final Classes
Entities should not be final because JPA providers like Hibernate use proxies (subclassing) for
lazy loading.
254
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
290 Spring 39: What are the different types of relationships in JPA and explain @OneToOne
with example
Database relationships are fundamental concepts in relational database design, allowing
data to be stored efficiently and retrieved accurately.
Different types are: OneToOne, OnetoMany, ManytoOne, and ManytoMany.
Reference: Types of Relationship in DBMS: Explained with Examples
@OneToOne Relationship
This is when one entity is directly related to exactly one other entity. Like a Person and their
Passport means each person has one passport, and each passport belongs to one person.
@Entity
public class Person {
@Id
private Long id;
@OneToOne
@JoinColumn(name = "passport_id")
private Passport passport;
// ... other fields
}
@Entity
public class Passport {
@Id
private Long id;
@OneToOne(mappedBy = "passport")
private Person person;
// ... other fields
}
255
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The @JoinColumn annotation is placed on the owning side of the relationship. It explicitly
defines the foreign key column in the database table that links to the primary key of the
associated entity.
mappedBy declares that the current entity is not responsible for managing the foreign key and
that another entity (the one specified in mappedBy) handles the relationship's persistence.
From the Example:
@OneToOne
@JoinColumn(name = "passport_id")
private Passport passport;
This means:
In the person table, there will be a column passport_id.
That column acts as a foreign key pointing to the passport table’s id.
So, the relationship is stored in the person table.
In Passsport class we wrote
@OneToOne(mappedBy = "passport")
private Person person;
mappedBy = "passport" tells Hibernate: "Don’t create a new join column here. Just look at the
field passport in the Person entity, because that is where the relationship is actually managed."
So passport table does not get an extra column like person_id.
This is how table looks like.
Here:
passport_id in Person points to id in Passport.
Only Person has the foreign key column, because it is the owning side.
Jave code:
Passport passport = new Passport();
[Link](101L);
[Link]("A12345");
256
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](1L);
[Link]("John");
[Link](passport);
Interview Tip: Always explain these relations with examples and dummy tables. So that it will be
easy for the explanation.
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
// ... other fields
}
@Entity
public class Department {
@Id
private Long id;
@OneToMany(mappedBy = "department")
private List<Employee> employees = new ArrayList<>();
// ... other fields
}
257
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Here:
Employees Alice and Bob belong to Department HR (id=10).
Employee Charlie belongs to Department IT (id=20).
The link is stored in employee.department_id.
Reference: ONE TO MANY mapping in Spring JPA | by Mohammed Youssef | Medium
@ManyToOne Relationship
This is the inverse of OneToMany. In the example above, the Employee side uses
@ManyToOne because many employees can belong to one department.
Reference: Many To One mapping in Spring Boot JPA (unidirectional) | by Vinotech | Medium
258
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference:
Theory: Spring Boot Many To Many Relationship | by HK | Medium
Example: Java Spring Boot — Many to Many Relationship | by Zübeyr Bahadır Damar | Medium
Scenario Question:
1. Supposed One employee has multiple managers, and one manager can have multiple
employees. How many tables do you use to save data?
We need 3 tables:
1. Employees: stores employee details (employee_id, name, etc.)
2. Managers: stores manager details (manager_id, name, etc.)
3. Employee_Manager: a junction (bridge) table that connects employees and managers.
o It has at least two columns: employee_id and manager_id, both as foreign keys.
293 Spring 42: What is cascading in JPA and when would you use it?
In JPA, cascading means that an operation done on a parent entity automatically flows
(or "cascades") to its child entities.
Think of it like this: if we delete a department, and we want all Employees under that
Department to also get deleted automatically, we set cascade rules. Without it, we need to
delete each Employee manually.
259
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
It saves us from writing extra code and keeps parent-child relationships consistent.
Different types of cascade types: ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH
Explanation with Relationships:
[Link]:
Use Case: When a new parent entity is persisted, its newly created child entities should also be
persisted.
Relationship Example (One-to-Many): A Customer entity has a list of Order entities. When a
new Customer is saved, all new Order entities associated with that customer should also be
saved.
PERSIST: Save parent also saves child.
REMOVE: Deleting parent deletes child.
MERGE: Updating parent updates child.
REFRESH: Refresh parent refreshes child.
ALL: Applies all above.
Reference: JPA/Hibernate Cascade Types. Cascading relationships are designed to… | by Himani
Prasad | Medium
Indirect Questions:
1. If I delete a department, will all its Employees also get deleted automatically?
By default, deleting a parent does not delete children.
If we want that, we need to explicitly add cascade = [Link] or
[Link] on the relationship.
2. Why does saving a parent entity not automatically save the child entities?
If cascade is missing, we must save the children separately.
With cascading, saving the parent pushes the persist operation down to its children.
3. Can you give me an example where you should NOT use [Link]?
For example, deleting a customer should not delete all their Orders, since Orders might
be needed for reporting or audit.
So, we will avoid [Link] in that relationship.
4. What happens if you delete parent entity when cascading type is all?
Child entities will also be deleted.
294 Spring 43: How does eager loading and lazy loading works in JPA?
Whenever we fetch an entity from the database, it may have relationships (like
Department has Employees).
The question is: Should JPA fetch everything immediately (Eager) or Will it fetch only when we
actually need it (Lazy)?
Eager Loading: Related entities are loaded immediately along with the parent, even if we don’t
use them.
260
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Entity
public class Department {
@Id
@GeneratedValue
private Long id;
Indirect questions
1. Why am I getting LazyInitializationException when accessing a collection after transaction is
closed?
Because it was marked LAZY, and the data wasn’t loaded before the session closed.
2. Which is the default fetch type for @OneToMany and @ManyToOne?
@OneToMany : LAZY (default)
@ManyToOne : EAGER (default)
3. How would you optimize performance if you always need parent + child data together?
Use fetch = [Link] or better use JPQL JOIN FETCH to control it at query level.
Interview Tip: We often prefer Lazy and control loading explicitly with JOIN FETCH in queries.
4. How does lazy loading breaks in rest Api, how do you solve it properly?
261
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
In JPA/Hibernate, associations are often marked as LAZY to avoid unnecessary data fetching. For
example:
@Entity
class User {
@OneToMany(mappedBy = "user", fetch = [Link])
private List<Order> orders;
}
How it breaks:
In a Spring REST controller, we often return entities directly as JSON.
When Jackson tries to serialize User, it accesses orders.
If the Hibernate session is already closed (because the transaction ended after service
layer), we get: [Link]
Fix:
Use DTOs to Map the correct data before returning.
Use join fetch
262
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Support for custom queries: Facilitates the definition of custom queries using
annotations or method names.
Repository hierarchy:
Indirect Questions:
1. If you only need simple save and find operations, which repository will you choose?
Use CrudRepository.
2. How would you fetch 20 students at a time from the database?
Use PagingAndSortingRepository with PageRequest.
3. Which repository allows batch deletion or flushing?
Use JpaRepository.
4. If you extend JpaRepository, do you still get CrudRepository methods?
Yes, because it is a hierarchy.
296 Spring 45: What is JPQL and how does it different from HQL?
JPQL(Java Persistence Query Language) queries are written using the entity classes and
their attributes instead of raw SQL queries.
//Entity: Employee (mapped to employees table)
String jpql = "SELECT e FROM Employee e WHERE [Link] = :deptName";
List<Employee> employees = [Link](jpql, [Link])
.setParameter("deptName", "IT")
263
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
.getResultList();
Here Employee is the entity class, and [Link] is a field in the object, not the DB
column.
HQL (Hibernate Query Language) is a powerful object-oriented query language used in
Hibernate ORM. HQL is a superset of the JPQL. A JPQL query is a valid HQL query, but not all HQL
queries are valid JPQL queries.
[Link] I switch from Hibernate to EclipseLink, will my queries still work?
Only JPQL queries are guaranteed to work. HQL has Hibernate-specific stuff.
[Link]’s the difference between using [Link]() and [Link]()?
The first is JPQL (JPA standard), the second is HQL (Hibernate-specific).
3. Can JPQL query database tables directly?
No, it queries entities and their mappings, not raw tables. For raw SQL, we will use
@NamedNativeQuery or createNativeQuery().
297 Spring 46: What is @Query (Custom Queries) and why should we use them??
By default, Spring Data JPA creates queries automatically just by looking at the method
names.
Example: List<Employee> findBySalaryGreaterThan(double salary);
Spring generates the query behind the scenes.
But sometimes we need more control, maybe a complex join, or a query that can’t be expressed
with method naming. That is when we use @Query.
@Query allow us write the own queries directly inside the repository method.
Two ways to use it
1. JPQL with @Query (works on entities and fields)
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
@Query("SELECT e FROM Employee e WHERE [Link] > :salary")
List<Employee> findEmployeesWithHighSalary(@Param("salary") double salary);
}
Here, notice we wrote the query using entity class (Employee) and its field (salary), not
database table/column.
2. Native SQL with @Query
Native queries are queries written in plain SQL
Why should we use them?
Complex queries
Sometimes JPQL can’t express what we want, like database-specific functions, window
functions, or advanced joins.
Example:
SELECT e.*, ROW_NUMBER() OVER (ORDER BY [Link] DESC) as rank
FROM employees e
This is not possible with JPQL, but we can do it with a native query.
264
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Performance tuning
Native queries useful when we need to write highly optimized SQL, sometimes better than
what JPA would generate for us.
Limitations of native queries:
Native queries are tied to the database (Oracle, MySQL, PostgreSQL, etc.). But JPQL is
database-independent.
SQL is harder to maintain if the DB schema changes.
Indirect Questions:
1. How Native queries create problems in Spring?
Native queries are specific to a database; switching DBs may break the query.
Changes in table structure require updating raw SQL manually
@NamedQuery is an annotation in JPA (Java Persistence API) that allows to define a reusable
query. This query is named (we give it a name) and defined once in the entity class. Later, we
can reuse that query by referencing the name in the code.
Named Queries are static, meaning once they are defined, they cannot be modified at
runtime.
The @NamedQuery annotation is placed at the top of the relevant Entity Class and
consists of two parameters:
name: A unique identifier used to reference the query.
query: The JPQL statement (JPQL query) that will be executed at runtime.
Example:
@Entity
@NamedQuery(
name = "[Link]", // Name of the query
query = "SELECT u FROM User u WHERE [Link] = :role" // The actual JPQL query
)
public class User {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
private String name;
private String role;
name = "[Link]" is the name of the query. We will reference this name later to
execute the query.
265
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
query = "SELECT u FROM User u WHERE [Link] = :role" is the actual query. It is written in
JPQL (Java Persistence Query Language), which is similar to SQL
Reference: Spring Data JPA @NamedQuery and @NamedQueries Example
We can also use @NamedNativeQueries Read here : Spring Data JPA @NamedNativeQuery and
@NamedNativeQueries Example
@Autowired
private AccountRepository accountRepo;
@Transactional
public void transferMoney(Long fromId, Long toId, double amount) {
Account from = [Link](fromId).get();
Account to = [Link](toId).get();
[Link]([Link]() - amount);
[Link]([Link]() + amount);
[Link](from);
[Link](to);
266
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Points to remember:
1. Use @Transactional on service layer methods, where business logic happens (not
usually on repository methods).
2. In Spring, transactions only work when a method is called from outside the class itself,
because Spring uses proxies to manage transactions.
3. By default, rollback only happens for runtime exceptions. If we want rollback for
checked exceptions too, we must configure it:
@Transactional(rollbackFor = [Link])
Interview Tip:
- Mention real world scenario while explaining about the transitional.
- Use @Transactional to ensure a group of DB operations succeed or fail together, maintaining
consistency.
- Mention Spring automatically handles commit and rollback, so you don’t manage transactions
manually.
- It Can be applied at method or class level depending on the scope of the transaction.
- Real-world example: In an e-commerce service, deducting stock and creating an order are in
the same transactional method; if order creation fails, stock deduction is rolled back
automatically.
Indirect Question:
1. What happens if a Spring bean is @Transactional, but the method is called from inside the
same class?
Answer: Self-invocation bypasses the proxy, so the transaction is ignored
Reference: Discover how to use the @Transactional annotation in Spring Boot | by Tharindu
Dulshan | Medium
2. What is the best place to keep @Transactional Annotation and why?
In a Spring application, @Transactional is used to make sure that a group of database operations
happen as one complete unit of work. If something goes wrong, all the changes are rolled back,
so the data stays consistent.
Now the question is: where should you place it?
Controller layer
Controllers should only handle requests and responses. They aren’t supposed to know
how transactions work, so putting @Transactional here mixes responsibilities.
Repository (DAO) layer
Repositories are focused on single database operations like saving, finding, or deleting
one entity. If we mark them transactional, we only control one small piece of the puzzle,
but not the bigger business process.
Service layer (Best place)
Services contain the actual business logic. They often call multiple repositories, maybe
even across different entities. By putting @Transactional at the service method level, we
ensure that all those operations run inside a single transaction. If anything fails, the
whole set of operations rolls back.
267
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Example
Imagine an e-commerce app:
1. When a customer places an order, the system saves the order details.
2. Then it deducts money from the customer’s balance.
3. Finally, it updates the product stock.
All three must succeed together. If the payment fails but the stock is already reduced, you end
up with inconsistent data.
That is why the service method should be transactional:
@Service
public class OrderService {
@Transactional
public void placeOrder(Order order) {
[Link](order);
[Link]([Link]());
[Link]([Link]());
}
}
Here, if payment fails, the saved order and stock update are rolled back automatically.
3. What type of proxy @Transactional creates?
When we put @Transactional on a method or class, Spring needs a way to wrap that
code so it can start, commit, or roll back a transaction. It does this with proxies. Now, which
proxy type gets used depends on the class.
1. JDK Dynamic Proxy
If the class implements an interface, Spring will by default create a JDK dynamic proxy.
This proxy implements the same interface and intercepts calls to add transactional behavior.
Here, UserServiceImpl implements UserService. Spring creates a JDK proxy that also implements
UserService. All calls go through that proxy.
public interface UserService {
void saveUser(User user);
}
@Service
@Transactional
public class UserServiceImpl implements UserService {
public void saveUser(User user) { ... }
}
2. CGLIB Proxy
If the class does not implement any interface, Spring falls back to CGLIB, which creates a
subclass at runtime. That subclass overrides the methods to add transaction logic.
@Service
@Transactional
public class OrderService {
public void placeOrder(Order order) { ... }
}
268
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Since OrderService has no interface, Spring uses CGLIB to generate something like
OrderService$$EnhancerBySpringCGLIB, which wraps the real logic.
@Transactional
public void placeOrder() {
// some DB operations for order
[Link]();
}
}
@Service
public class PaymentService {
@Transactional
public void processPayment() {
// DB operations for payment
}
}
Propagation Types:
REQUIRED (default)
If there’s already a transaction, join it.
If not, create a new one.
Example: Both order and payment will run in one transaction. If payment fails, the whole
order fails.
@Transactional(propagation = [Link])
269
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
REQUIRES_NEW
Always start a new transaction, even if one already exists.
Example: Payment starts in a new transaction. So even if order fails later, payment can
still be committed.
@Transactional(propagation = Propagation.REQUIRES_NEW)
NESTED
Runs inside the parent transaction but can roll back independently.
Example: Payment failure will roll back payment only, but not necessarily the whole
order.
@Transactional(propagation = [Link])
SUPPORTS
If a transaction exists, join it. If not, just run without a transaction.
NOT_SUPPORTED
Runs the method non-transactionally and suspends any existing transaction.
MANDATORY
Must run inside an existing transaction. If none exists throw exception.
NEVER
Must run without a transaction. If one exists throw exception.
Let’s take one simple example and apply all the 4 cases.
Imagine a BankService class with two methods: transferMoney() and sendEmailNotification().
@Service
public class BankService {
@Transactional
public void transferMoney(Long fromAccount, Long toAccount, double amount) {
}
}
@Service
public class EmailService {
270
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void sendEmailNotification(Long from, Long to, double amount) {
}
}
271
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
272
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference: Spring Transaction Internals — What Really Happens Under the Hood | by Arvind
Kumar | Medium
302 Spring 51: What is N+1 problem how do you fix it?
Imagine we want to fetch all students and their courses from the database.
First, we run 1 query to get all students.
Then, for each student (say there are N students), we run 1 query per student to fetch
their courses.
That means: 1 (main query) + N (extra queries) = N+1 queries.
So instead of just 2 queries (students + their courses), we end up making dozens or hundreds of
queries, which slows everything down badly.
List<Student> students = entityManager
.createQuery("SELECT s FROM Student s", [Link])
.getResultList();
273
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
objects in the code are loaded right away. If they are set to load lazily, they will only load when
we actually use them, which can cause extra queries (the N+1 problem) if we access them many
times.
JOIN FETCH:
JOIN FETCH in JPA/Hibernate is like a normal join, but it also forces Hibernate to load the
related entities immediately in the same query, avoiding lazy loading and the N+1 problem.
Use JOIN when we only need the association for filtering, but don’t actually need the associated
entities in memory. Example: get students who have at least one course.
Use JOIN FETCH when we know we will access the associated entities and want to avoid the N+1
problem by loading everything in one query. Example: get students and load their courses right
away.
Reference: Spring JPA: when to use “Join Fetch” | by Dev INTJ Code | Javarevisited | Medium
@Version
private int version; // JPA uses this to detect conflicts
}
How it works:
1. Transaction A reads a row (version = 1).
2. Transaction B updates the same row then version becomes 2.
3. Transaction A tries to update with version = 1 so Hibernate detects mismatch and throws
OptimisticLockException.
Best when conflicts are rare because it avoids unnecessary database locks and scales well.
Pessimistic Locking assumes that conflicts will occur and locks the data to prevent the other
transactions from accessing it concurrently.
How it works?
274
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
1. Acquire Lock:
When the transaction reads a record with the pessimistic lock, the database acquires the
lock on that record.
The lock can be of the different types, such as PESSIMISTIC_READ (prevents other
transactions from writing) or PESSIMISTIC_WRITE (prevents other transactions from
reading or writing).
2. Block Other Transactions
Other transactions trying to access the same record will be blocked until the lock can be
released. This prevents data inconsistency caused by the concurrent modifications.
3. Release Lock
The lock is held for the duration of the transaction and it can be automatically released
when the transaction commits or rolls back.
public interface ProductRepository extends JpaRepository<Product, Long> {
@Lock([Link])
Optional<Product> findById(Long id);
@Lock(LockModeType.PESSIMISTIC_WRITE)
Optional<Product> findByName(String name);
}
Examples:
Optimistic Locking: Imagine an online shopping website. Thousands of people are viewing
products, but only a few actually place orders at the same time. If two users try to buy the last
piece of a product, both can proceed without blocking each other. But at the moment of update,
Hibernate checks a @Version column. If the version in the database has changed, it throws an
OptimisticLockException.
Pessimistic locking: Think about a bank account. Two people try to withdraw money from the
same account at the same time. If both see ₹1000 and withdraw ₹800 each, the account would
go negative. That is dangerous.
With pessimistic locking, the first transaction locks that row in the database. The second
transaction has to wait until the first one commits or rolls back. That way, we never get
inconsistent balances.
Reference: Pessimistic and Optimistic Locking in JPA, Spring Boot | by Berat Yesbek | Medium
275
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
1. Database
This is the actual relational database (like MySQL, PostgreSQL, Oracle) where the tables and data
live.
JPA’s job is to talk to this database but using object, so we don’t directly write a lot of SQL.
2. Entity
An Entity is just a normal Java class mapped to a table in the database using @Entity.
Each object of that class represents a row in the table.
@Entity
public class Student {
@Id
private Long id;
private String name;
private String email;
}
4. EntityManagerFactory
It is heavyweight object created only once for the whole application.
It is Responsible for creating multiple EntityManagers.
Think of it like a "factory" that handles database managers.
276
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
5. EntityManager
This is the core interface we use in JPA.
Manages all the entity operations like insert, update, delete, query)
It interacts with the Persistence Context and Entity Transactions.
EntityManager em = [Link]();
[Link]().begin();
6. Persistence Context
A cache (in-memory storage) where EntityManager keeps track of all entities.
If we fetch an entity, it is stored here.
It is like a temporary storage area between the application and the database.
Whenever we make changes to an entity during a transaction, the persistence context
keeps track of those changes. Once the transaction is done, it saves these changes to the
database.
Here, no second DB query is executed for s2 because JPA fetches it from the persistence context.
7. EntityTransaction
Every operation in JPA happens inside a transaction.
begin() starts it, commit() saves changes, rollback() undoes them.
EntityTransaction tx = [Link]();
[Link]();
8. Query
We use JPQL (Java Persistence Query Language) or native SQL through EntityManager to
fetch data.
List<Student> students = em
.createQuery("SELECT s FROM Student s", [Link])
.getResultList();
277
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
278
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
4. JDBC Driver
- Vendor library like mysql-connector-java or postgresql.
- Converts JDBC calls into the database-specific protocol.
5. Database
- Stores your actual data (tables, rows, indexes).
- Executes SQL and returns results back up the stack.
Spring 55: What will happen under the hood when you call .save method of Repository?
The following is code is for save. UserService is calling save() of userRepository.
public interface UserRepository extends CrudRepository<User, Integer> {
// no need to write save(), findById(), etc.
// CrudRepository already provides them
}
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
So, when we call save(), we are not calling the actual code, we are calling a generated proxy that
knows how to talk to JPA’s EntityManager.
279
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Inside SimpleJpaRepository, the save() method checks whether the entity is new or already
exists.
Step 4 - Check Entity State (Transient, Managed, Detached, Removed)
At this moment, new User(1, "CodingLyf") is in the Transient state.
That means it exists in memory but is not yet known to the persistence context.
save() will call [Link]() if it is new, or merge() if it thinks it already exists.
Step 5 - Persistence Context (a.k.a First-Level Cache)
EntityManager maintains something called a persistence context. Think of it as a cache
in memory that holds all entities being tracked in the current transaction.
When we save the User:
It first gets added to the persistence context.
Now JPA starts tracking it. If we change the object later, JPA knows what changed.
Step 6 - SQL Generation
The actual INSERT or UPDATE statement is executed only when:
The transaction commits, or
[Link]() is called.
At that moment, Hibernate translates the entity into SQL. For example:
For a new user > JPA generates an INSERT INTO user ... query.
For an existing user > JPA generates an UPDATE user ... query.
Step 7 – Transaction Commit
Spring Data JPA usually runs the save() inside a transaction.
When the transaction commits:
JPA flushes all pending changes from persistence context to the database.
The SQL is executed.
The record is physically written in the DB table.
Step 8 – Return Value
280
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
1. Difference between save() and saveAndFlush()
When we call save(), Spring Data JPA doesn’t immediately fire the SQL query. Instead it
makes entry in the persistent context. It saves in DB only when the transaction is committed or a
flush operation occurs
saveAndFlush () performs the same operation as save() but immediately flushes the
changes to the database. This ensures that the entity's state is synchronized with the database
right away
2. Difference between persist() and merge()
persist() is used to take a brand-new object (in the transient state) and make it managed
state, scheduling it for insertion into the database.
merge() is used to take an existing object that is not managed (in the detached state) and
bring it back into the managed state, scheduling it for update in the database.
[Link]().begin();
Reference: Hibernate Persistence Context. In this article, we’ll talk about… | by Emre DALCI |
emlakjet | Medium
[Spring Boot] Persistence Context | by Hwangon Jang | Medium
Additional Question:
281
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If I have a student object managed by JPA and I change the student's name multiple times (say
100 times) before committing, will all 100 changes be saved to the database, or only the final
change? How does the persistence context determine what to update.
@Entity
public class Student {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
// Constructors
public Student() {}
In JPA/Hibernate, the persistence context acts like a cache for entity objects. When we
fetch or create an entity and it is managed by the persistence context
Changes are not immediately written to the database. They are flushed either when we
explicitly call [Link]() or at the end of a transaction.
Persistence context compares the current in-memory state of the entity with the
snapshot taken when the entity was first loaded to decide what to update. This is called
dirty checking.
Even if we change the student's name 100 times within the same transaction, only the
last change will be saved. The intermediate changes are not individually saved because
the persistence context only cares about the difference between the original and the
final state at the time of flush/commit.
282
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]().commit();
[Link]();
Here, the second time we ask for the student, JPA doesn’t bother going to the database. It
already knows the entity is inside the persistence context, so it just returns the cached object.
Key Point: we cannot turn off the first-level cache. It is always there.
2. Second-Level Cache (Shared Cache)
Now imagine your app has multiple sessions and same entity is needed by multiple sessions?
Without a shared cache, each session would query the database again.
That is where the second-level cache comes in.
It sits at the EntityManagerFactory level.
It can be shared across multiple sessions.
It is not enabled by default; we have to configure it.
Common providers are EhCache, Infinispan, Hazelcast.
@Entity
@Cacheable
283
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@[Link](
usage = CacheConcurrencyStrategy.READ_WRITE
)
public class Student {
@Id
private Long id;
private String name;
}
When this is enabled, if one session loads a Student from DB, the next session can pick it up
directly from the cache instead of querying the database again. This is where the real
performance boost happens in large applications.
Real time Example:
Without Second-Level Cache
User A logs in > System opens a session
They view Product with ID=101 > DB is hit, product details are fetched.
Later, User B logs in > New session (
They also view Product with ID=101 > Again DB is hit because each session has its own
first-level cache only.
So, the same product info is fetched twice from DB, even though nothing changed.
With Second-Level Cache
User A logs in > System fetches Product 101 from DB and puts it into second-level cache.
User B logs in > When they view Product 101, Hibernate/JPA picks it from the cache
instead of hitting DB again.
That is why in real-world apps with many users requesting the same data (products, courses,
profiles), second-level cache saves number of DB hits.
Point to remember: First level cache is session-scoped, whereas second level cache is application
scope
Indirect Questions:
1. When will cache be updated?
The second-level cache is updated automatically whenever Hibernate changes the entity
(insert, update, delete). If changes happen outside Hibernate means if we update the DB
directly, we need refresh or eviction to sync it.
2. Can caching cause stale data issues?
Yes. If another transaction updates the database, the cache might still hold the old value. To
avoid this, second-level caches use cache invalidation or concurrency strategies like READ_ONLY,
NONSTRICT_READ_WRITE, etc.
READ_ONLY > cache never updated (safe for reference data like countries, constants).
READ_WRITE > updates both DB and cache when entity changes.
NONSTRICT_READ_WRITE > DB updated immediately, cache updated lazily (may serve
slightly stale data).
284
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference video: Spring Boot : How to connect with multiple databases using Spring Data JPA
When we work with multiple databases, we need three main things for each database:
1. DataSource: the connection details (URL, username, password). We need do define
multipe datasoures
2. EntityManagerFactory: responsible for creating and managing JPA’s entity managers
(basically the bridge between the entities and the DB).
3. TransactionManager: tells Spring how to handle transactions (commit/rollback).
And finally, we map specific entities and repositories to the right database.
Let’s say we have two databases:
Primary DB: users (userdb)
Secondary DB: orders (orderdb)
Step 1: First, we need to configure the data sources in properties file.
# Primary DB (users)
[Link]=jdbc:mysql://localhost:3306/usersdb
[Link]=root
[Link]=secret
[Link]-class-name=[Link]
# Secondary DB (orders)
[Link]=jdbc:mysql://localhost:3306/ordersdb
[Link]=root
[Link]=secret
[Link]-class-name=[Link]
285
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
2. basePackages = "[Link]"
This is the folder (package) where our repository interfaces exists (Check above package info).
Example: inside [Link], we have UserRepository,
UserProfileRepository.
Spring will scan this package, find those interfaces, and auto-generate classes for them.
Without this, Spring won’t know where the repositories are hiding.
3. entityManagerFactoryRef = "userEntityManagerFactory"
286
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Now, repositories need to know which database connection + mapping rules they belong to.
That is handled by the EntityManagerFactory.
“Repositories in [Link] should use the userEntityManagerFactory.”
Why is this important?
In single-DB apps, there’s only one entity manager, so we don’t need this.
In multi-DB apps, each DB has its own entity manager, so we must explicit set it.
4. transactionManagerRef = "userTransactionManager"
Databases don’t just read and write; they also commit or roll back transactions.
It says “When these repositories do database work, handle their transactions using
userTransactionManager.”
So:
If something fails in a UserRepository call, this manager decides whether to rollback or
commit.
Again, in multi-DB setups, each DB has its own transaction manager.
Code link: ashokitschool/springboot_multi_db_config: springboot_multi_db_config
Indirect Questions:
1. What happens if you don’t specify basePackages in @EnableJpaRepositories?
By default, it scans the same package where our configuration class is placed (and sub-
packages).
If our repos are elsewhere, they won’t be found and we willl get No qualifying bean
errors.
2. Why do we need entityManagerFactoryRef in a multi-database setup?
Because each DB has its own entity manager.
Without this reference, Spring wouldn’t know which database connection to use for
those repositories.
It is used to mixing up entities of DB1 with DB2.
3. Can we skip transactionManagerRef? What happens?
If we have only one database, Spring will auto-wire the default transaction manager.
In multi-DB apps, we must specify it, otherwise the wrong transaction manager might
get applied, leading to runtime errors or commits going to the wrong DB.
4. If I put all my repositories (User and Order) in the same package, will @EnableJpaRepositories
still work?
Yes, @EnableJpaRepositories will still work even if we put all the repositories (User,
Order, etc.) in the same package.
But it is good to put repositories according to the DB for better maintainability:
5. What’s the difference between @EnableJpaRepositories and @Repository on an interface?
287
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
310 Spring 60: How do you create Custom repository in Spring JPA?
Spring Data JPA gives us a lot out of the box with JpaRepository, like findAll(), save(),
delete(), etc.
But sometimes, we need custom queries or complex logic when we can’t achieve with derived
query methods. That is where a custom repository comes in.
Reference: Spring data JPA custom repository. Watch this video before reading the theory.
Steps to create a custom repository
1. Create a custom interface, this is where we declare methods that aren’t in JpaRepository.
public interface EmployeeRepositoryCustom {
List<Employee> findEmployeesWithHighSalary(double minSalary);
}
@PersistenceContext
private EntityManager entityManager;
@Override
public List<Employee> findEmployeesWithHighSalary(double minSalary) {
return [Link](
"SELECT e FROM Employee e WHERE [Link] > :salary", [Link])
.setParameter("salary", minSalary)
.getResultList();
}
288
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Extend the main repository with the custom one. Now EmployeeRepository has both the
standard JPA methods and the custom one.
import [Link];
Code: shameed1910/spring-jpa-custom-repo
Reference: How to Use Connection Pooling for Faster Database Access in Spring Boot | by
Alexander Obregon | Medium
Spring Data JPA is a powerful tool for simplifying database access in Spring Boot
applications, providing repository interfaces that reduce the boilerplate code for CRUD
operations.
Sometimes we want to define a base repository with shared methods for multiple
repositories, but we don’t want Spring to create a bean for that base interface itself. That is
where @NoRepositoryBean comes in.
289
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The primary function of @NoRepositoryBean is to prevent Spring Data JPA from creating a
repository proxy for the annotated interface or class. It is typically used on base repository
interfaces or classes that define common methods for a set of repositories.
Example: Library System
Let’s say we are building a library system. We want a base repository with common
methods for all items in the library (books, magazines, etc.).
Entities:
@Entity
public class Book {
@Id
private Long id;
private String title;
private String author;
// getters/setters
}
@Entity
public class Magazine {
@Id
private Long id;
private String title;
private int issueNumber;
// getters/setters
}
LibraryItemRepository is marked with @NoRepositoryBean, so Spring does not create a bean for
it.
But Spring will create beans for BookRepository and MagazineRepository, and they both inherit
the shared findByTitleContaining() method.
It is useful to avoid duplicate code in multiple repositories.
290
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Spring Security is a framework that helps us to protect the Java applications. Think of
Spring Security as a bodyguard for the application. Whenever a request comes into the system, it
doesn’t let anyone walk in freely.
It first checks who the user is (authentication) and then decides what the user is allowed
to do (authorization).
So, in short:
Authentication: Verifying identity (like logging in with username/password).
Authorization: Checking permissions (like only admins can delete users).
Without Spring Security, we would have to write a lot of this logic by hand; validating users,
handling login failures. Spring Security handles all of this in a structured way.
Imagine we are building an online banking app. we don’t want just anyone to:
Log in with any random credentials
View someone else’s account details
Make unauthorized transactions
Spring Security makes sure that doesn’t happen. It places a security filter chain in front of
the application and intercepts requests before they reach the business logic.
Here is the most basic Spring Security setup in Spring Boot (using the new way with
SecurityFilterChain). We will see every option in the upcoming questions.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasRole("USER")
.anyRequest().authenticated()
)
.formLogin([Link]()); // enables default login form
return [Link]();
}
}
291
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
292
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
316 Spring 66: What are the key features of Spring Security?
1. Authentication: Authentication is the process of validating the identity of a user who is
attempting to access the application. Spring Security provides multiple authentication
methodologies (Username/Password Authentication, JWT, OAUTH2, SSO).
2. Authorization (Access Control): Authorization is the process of granting permissions or rights
to authenticated users. Once a user is successfully authenticated, authorization determines what
actions or resources they are allowed to access within an application.
Example: Only admins can delete users.
3. Protection against Common Attacks
Spring Security automatically protects against many common vulnerabilities:
CSRF (Cross-Site Request Forgery) > prevents fake form submissions.
XSS (Cross-Site Scripting) > Escapes dangerous inputs.
4. Password Security
Passwords are never stored in plain text. Spring Security provides hashing algorithms like BCrypt,
so even if the database is stolen, raw passwords aren’t exposed.
Indirect Questions:
1. Difference between Authentication and Authorization
Authentication is checking who the user is. Example: logging in with the email and password.
Authorization is checking what the users are allowed to do. Example: an admin can delete users,
but a normal user cannot.
Types of Authentications:
293
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
1. Username and Password Authentication: User provides a username and password and
system verifies against the DB.
2. Token-Based Authentication (JWT): User logs in once and receives a token (like JWT). Every
subsequent request includes the token (usually in Authorization header).
3. HTTP Basic Authentication: Credentials are sent in base64-encoded format in the request
header. Simple, but not recommended for production unless combined with HTTPS.
4. OAuth2 / OpenID Connect: Delegated authentication via third-party providers like Google,
Facebook, or Okta. The system relies on the external provider to authenticate the user and
provide an access token. Useful for SSO (Single Sign-On).
294
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
295
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
SecurityContextHolder
Now, how do we access the SecurityContext? That is the job of the SecurityContextHolder.
It is like the “manager” that gives the current SecurityContext for the running thread.
Authentication auth = SecurityContextHolder
.getContext()
.getAuthentication();
319 Spring 69: What is JWT and how does it differ from Basic auth?
Both JWT (JSON Web Token) and Basic Authentication are ways to check a user’s identity.
Basic Authentication
With Basic Auth, the client (like a browser or mobile app) sends the username and password
with every request. These credentials are usually sent in the HTTP header, encoded in Base64
(which is not encryption, just a form of encoding).
Pros: Simple to implement, no extra setup needed.
Cons: Insecure if not used over HTTPS (credentials can be stolen), and credentials are
repeatedly exposed on every request.
JWT takes a different approach. Instead of sending the username and password every time, the
server gives the client a token after a successful login. This token is a signed string containing
encoded information about the user (like their username and roles).
From that point on, the client only needs to send the token with each request, no passwords
involved. The server checks if the token is valid and not expired, then processes the request.
Good to know
Before JWTs became popular, web apps commonly used session IDs. Here is how that worked:
1. When user logs in, server creates a session and stores user info on the server.
2. Server gives the client a session ID, usually stored in a cookie.
3. For each request, the client sends the session ID, and the server looks up the session
data.
This works fine for small apps, but it doesn’t scale well:
The server must keep session data in memory or a database. More users mean server
requires more memory.
In a load-balanced system with multiple servers, we need session to store in shared
cache (Redis, Memcached). That adds complexity.
296
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
REST APIs are supposed to be stateless, but sessions make the server stateful.
JWT solves these problems by keeping all the necessary user information inside the token itself,
so the server doesn’t need to store anything about the user between requests.
Reference: What is JWT? JSON Web Tokens Explained (Java Brains)
Additional Question:
1. Should you use JWT or Session-based authentication in the microservices environment?
In a microservices environment, JSON Web Tokens (JWTs) are generally preferred over
session-based authentication.
In session-based authentication, the server has to store session data. Works fine for small
apps, but in microservices it is hard because every service would need to share session data.
With JWT after login, we get a token. we send that token every time. Each service can check
it without talking to others. Much easier for microservices.
2. How does Basic Authentication work in Rest API?
Basic Authentication in REST API works like this:
1. When a client (say, a browser or Postman) makes a request, it attaches an HTTP header:
Authorization: Basic <Base64 encoded username:password>
2. The server receives it, decodes the Base64 string back to username:password, and
checks against its user store (like DB or in-memory).
3. If it matches, the request is allowed. If not, it is rejected with 401 Unauthorized.
Problem: credentials are sent on every request, so it must be used over HTTPS to avoid the
exposure of passwords
3. In Spring boot, how is session managed?
When a user logs in, the server needs to remember the user between requests. HTTP
itself is stateless, meaning it forgets the user every time. To fix that, Spring Boot uses session
management.
1. Session Creation
After a successful login (say with form login or basic authentication), the server creates a
session object (HttpSession).
This session is just a unique ID (called JSESSIONID) stored on the server.
2. Session ID Sharing
The server sends this ID back to the browser as a cookie.
On every new request, the browser automatically sends this cookie back.
Spring uses it to look up the stored session and retrieve the user’s authentication details.
3. Where the Session Data Lives
By default, Spring Boot keeps session data in memory (in the server’s JVM).
But we can change this to:
Database
Redis (common for microservices and scaling)
297
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Custom storage
2. Payload
This is the main content of the token.
It holds the information about the user and some metadata.
Claims are key-value pairs, for example:
sub: Subject (the user ID)
name: Username
roles: User’s roles or authorities
exp: Expiration time of the token
{
"sub": "12345",
"name": "CodingLyf",
"roles": ["ADMIN", "USER"],
"exp": 1699999999
}
3. Signature
This is the security part of the token
It is created by Base64UrlEncode(header) + "." + Base64UrlEncode(payload) and then
signing it with a secret key or private key using the algorithm from the header.
Reference: What is the structure of a JWT - Java Brains
298
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
storage or cookies) and attach it to every request it makes. This way, the server can check if the
request comes from an authenticated user.
But here is the real question is, how does the server know the JWT is valid?
1. Browsers send Token in Authorization header. Authorization: Bearer <jwt_token>
2. Server will read this header and extracts the token.
3. From Token, we need to extract the username and now verify this username with
the usernames stored in DB. If it matches token is valid , if it is invalid token and
returns 401 error.
Point to remember: All these steps will be done in OncePerRequestFilter.
OncePerRequestFilter ensures the JWT validation logic runs exactly once for each request,
extracts the username from the token, validates it, and sets authentication in the security
context.
299
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
JWT (JSON Web Token) authentication in Spring Boot is basically about replacing the default
session-based authentication with stateless token-based authentication.
1. User Login Request
The client (browser or mobile app) sends a login request with username and password.
This hits the AuthenticationController.
2. Authentication Manager + UserDetailsService
Spring Security passes the credentials to the AuthenticationManager.
That, in turn, uses the custom UserDetailsService to fetch the user and check the
password with a PasswordEncoder.
If it is valid > user is authenticated.
If not > reject immediately.
3. JWT Token Creation
Instead of creating a session, we now generate a JWT.
JWT contains claims like: username, roles, issued time, expiration.
It is signed with the secret key (so no one can tamper with it).
It spring we use JWT Library (commonly used is jjwt)
This token is then sent back to the client in the response.
4. Client Stores the JWT
The client usually stores this JWT in localStorage or sessionStorage or cookies (in
browsers), or secure storage (in mobile apps).
From now on, every request from client : server includes this token in the Authorization
header:
Authorization: Bearer <jwt_token>
5. JWT Authentication Filter
We add a custom filter by extending OncePerRequestFilter in the Spring Security filter
chain (before UsernamePasswordAuthenticationFilter).
This filter:
1. Reads the Authorization header.
2. Extracts the JWT token.
3. Validates it (check signature + expiration).
4. If valid : create an Authentication object and put it into the SecurityContext.
5. If invalid : reject request with 401.
300
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
323 Spring 73: How does SecurityFilterChain works and list down the filters?
In Question No 320, Spring 68 we have seen Architecture of the Spring security. From here
we are going depth into every component of the Spring security.
In Spring Security, everything that protects the application runs through a chain of filters.
Think of it like airport security , we don’t just pass through one gate, we pass through a series of
checks: baggage scan, passport check, body scan, etc. Each check is a filter with a specific job.
The SecurityFilterChain is literally that chain of filters applied to incoming requests.
Every HTTP request enters the filter chain.
Each filter either does some security work (like authentication, authorization, CSRF
check, session check) or passes control to the next filter.
If a request fails a check (say invalid credentials), the chain is broken, and the request is
rejected immediately.
Without this chain, Spring Security can’t intercept and secure requests.
Types of filters:
Authentication Filter: Responsible for handling user authentication.
Authorization Filter: Enforces access control policies and checks whether a user is
authorized to access a resource.
CSRF (Cross-Site Request Forgery) Filter: Protects against CSRF attacks. (Refer Question
No )
UsernamePasswordAuthenticationFilter: Validates the username and password for the
URL (/login) with the default credentials provided at startup.
BasicAuthenticationFilter: This filter is responsible for processing any request that has
an HTTP request header of Authorization, Basic Authentication scheme, Base64 encoded
username-password.
BearerTokenAuthenticationFilter: Extracts JWT tokens for authentication.
FilterSecurityInterceptor : This filter is responsible for authorizing every request that
passes through the filter chain before the request hits the controller.
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity)
throws Exception {
httpSecurity
.csrf(csrf -> [Link]())
.authorizeHttpRequests(
request -> request
.requestMatchers("register","login").permitAll()
.anyRequest().authenticated()
)
.httpBasic([Link]())
.addFilterBefore(jwtAuthenticationFilter,
301
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]);
return [Link]();
}
Indirect Questions:
1. How you make certain APIs skip authentication?
Using requestMatchers
2. How can you disable the CSRF
Using CSRF filter and [Link]() method
302
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
FilterChainProxy is responsible for picking the right chain based on the request (URL
matching) and executing it.
Flow:
Request > DelegatingFilterProxy > FilterChainProxy > Security Filters > DispatcherServlet >
Controller
303
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Override
public UserDetails loadUserByUsername(String username) throws
UsernameNotFoundException {
UserEntity user = [Link](username)
.orElseThrow(() -> new UsernameNotFoundException("User not found: " +
username));
return [Link]
.withUsername([Link]())
.password([Link]()) // already encrypted
.authorities("ROLE_USER")
.build();
}
}
Key points
UserDetailsService does not authenticate. It only fetches user data.
Password check is done by an AuthenticationProvider (like DaoAuthenticationProvider).
We can have multiple UserDetailsService implementations if needed.
If we don’t configure one, Spring can use an in-memory we by default.
326 Spring 76: Explain about Password Encryption and why it is important?
When a user registers or logs in, their password is the most sensitive piece of data. If we
store or transmit it as plain text, anyone with database access (admins, hackers, even accidental
log dumps) can see it. That is a massive security risk.
Instead, Spring Security (and security best practices in general) never stores plain passwords.
Instead, it stores a hashed and salted representation of the password.
Hashing means converting the password into a fixed-length string using an algorithm
(like BCrypt).
304
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Salting means adding a random string before hashing, so that even if two users have the
same password, their stored hashes are different.
How Password Encryption Works in Spring Security
PasswordEncoder Interface
Spring Security provides PasswordEncoder, an interface for encoding and matching
passwords.
The most commonly used implementation is BCryptPasswordEncoder.
PasswordEncoder encoder = new BCryptPasswordEncoder();
String encodedPassword = [Link]("mySecretPassword");
305
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Using NGINX to handle CORS is common, especially when we want to manage it outside the
application.
NGINX acts as a reverse proxy in front of the Spring Boot app. we can configure it to add the
CORS headers in HTTP responses so browsers allow cross-origin requests.
How CORS works in Spring (Refer Question No. 378, Spring 126)
329 Spring 79: What is Outh2 and how does it differ from JWT?
OAuth2 is an authorization framework that allows a user to grant a third-party application
limited access to their resources without sharing credentials.
It is not an authentication protocol by itself, though it is often used with OpenID Connect
(OIDC) for authentication.
OAuth2 defines roles and flows for issuing access tokens to clients.
It is widely used for APIs, social logins, and microservices.
Core components in OAuth2:
1. Resource Owner: The person who owns the data or resources being accessed (e.g., the
Google account or Facebook profile).
2. Client: The app or service that requests access to the user's resources (e.g., a travel
booking app that wants access to your Google Calendar).
3. Authorization Server: The server responsible for authenticating the user and issuing
access tokens (e.g., Google's OAuth server).
4. Resource Server: The server that hosts the user's data (e.g., Google, Facebook, Twitter).
It verifies and grants access to the requested resources based on the token provided.
Flows / Grant Types:
Authorization Code: Web apps redirect users to login at the provider.
Client Credentials: Service-to-service communication.
Password Grant: User provides username/password directly to client (less secure, rarely
used).
Implicit Grant: For single-page apps (now discouraged).
Where as
JWT (JSON Web Token) is a token format, not a framework.
JWT can be used inside OAuth2 as the access token.
306
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
1. Resource Owner: It is the user, the Google account holder. The user owns the calendar
data.
2. Client: The third-party travel booking app that wants to read the user calendar to avoid
scheduling conflicts.
3. Authorization Server: Google’s OAuth server. It asks the user to log in and consent: “Do
you allow the travel app to read your calendar?”
4. Resource Server: Google Calendar API. Once the app has a valid access token, this server
returns the user calendar data to the travel app.
Flow in Simple Terms
1. Travel app redirects us to Google login page (Authorization Server).
2. You log in and consent.
3. Google issues an access token to the travel app.
4. Travel app calls Google Calendar API (Resource Server) with the token.
5. Resource server validates the token and sends back your calendar data.
307
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When the user tries to access /admin/dashboard, the system checks if they have
ROLE_ADMIN.
Implementation in Spring Security
Each role is represented as an authority (GrantedAuthority).
We can secure endpoints using:
Method-level security: @PreAuthorize("hasRole('ADMIN')")
HTTP configuration:
[Link]()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
Roles are usually prefixed with ROLE_ internally (ROLE_ADMIN).
Additional Questions:
1. How do you secure sensitive data in a Spring boot application that is accessed by multiple
users with different roles?
Securing sensitive data in a Spring Boot application accessed by multiple users with different
roles requires a multi-layered approach, primarily using Spring Security.
Authentication and Authorization with Spring Security:
User Authentication: Implement robust authentication mechanisms. This can involve
username/password authentication (using BCryptPasswordEncoder for secure password
hashing), JWT-based authentication for stateless APIs, or integrating with external
identity providers.
Role-Based Access Control (RBAC): Define distinct roles (e.g., ADMIN, USER, GUEST) and
assign them to users.
Method-Level Security: Use annotations like @PreAuthorize, @PostAuthorize,
and @Secured on service methods or controller endpoints to restrict access based on
roles or custom expressions.
URL-Based Security: Configure SecurityFilterChain to secure specific URL patterns based
on roles.
308
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
334 Spring 84: What is Spring Boot Actuator, and why is it useful?
Spring Boot Actuator is a sub-project of Spring Boot that provides production-ready features to
monitor and manage thw application.
It adds a set of built-in endpoints that expose information about the application, like
health, metrics, environment properties, and more.
These endpoints helps to understand, monitor, and manage the app without writing
extra code.
Key Features
1. Health Checks: Verify if the app and its dependencies (database, messaging queues, etc.)
are working properly.
2. Metrics: Access information about memory usage, CPU, active threads, HTTP request
statistics, etc.
3. Environment & Config Info: View active profiles, properties, and configuration settings.
4. Logging: Check and change logging levels at runtime.
5. Tracing & Auditing: Track HTTP requests and audit application events (with optional
integrations).
How do you check if a running service is up in microservice
309
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
335 Spring 85: How do you enable and configure Actuator endpoints?
1. Add Dependency
Add the Actuator dependency in the [Link] (Maven) or [Link] (Gradle):
Maven:
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2. Enable Endpoints
By default, only a few endpoints are exposed (/actuator/health, /actuator/info).
We can enable more endpoints in [Link] or [Link].
[Link]=health,info,metrics,loggers
Indirect Question:
1. How do you check how many times each API endpoint was called, along with timings?
We need to /actuator/metrics/[Link]
For a particular API: actuator/metrics/[Link]?tag=uri:/hello-
world&tag=method:GET
Reference: A Comprehensive Guide to Spring Boot Actuator | by Pratik T | Medium
310
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@ReadOperation
public Map<String, Object> customInfo() {
Map<String, Object> data = new HashMap<>();
[Link]("appName", "Payment-Service");
[Link]("version", "1.0.3");
[Link]("activeUsers", 153);
[Link]("lastDeployed", "2025-08-20 14:30:00");
return data;
}
}
311
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@ReadOperation
public Map<String, Object> activeUsers() {
Map<String, Object> metrics = new HashMap<>();
[Link]("activeUsers", activeUsers);
[Link]("pendingTransactions", pendingTransactions);
[Link]("currentLoad", currentLoad);
return metrics;
}
}
339 Spring 89: How to secure Actuator endpoints and why to secure?
Actuator exposes very sensitive information about the application:
/actuator/health: can tell if the app is up/down (attackers can use this).
/actuator/metrics: exposes internal performance metrics.
/actuator/env or /actuator/configprops: might reveal, API keys, or DB URLs if not
properly masked.
Custom endpoints: could leak business data if left open.
If we don’t secure them, anyone with the URL can hit those endpoints and can use the
information. That is why in production we always secure actuator endpoints.
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health", "/actuator/info").permitAll()
.requestMatchers("/actuator/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic();
return [Link]();
}
}
312
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Here:
/actuator/health and /actuator/info are public (safe for probes).
All other Actuator endpoints need ADMIN role.
Authentication is via basic auth.
Our business logic stays in different files and cross cutting concerns stays in separate files, both
can be managed separately
Example: Let’s say we have a payment service where we want to log when Payment started and
after payment ended.
Without AOP: (Note: Used [Link]() just for example purpose, In prod we should not
use it.)
class PaymentService {
public void processPayment() {
[Link]("Starting payment..."); // logging
// business logic
[Link]("Payment done."); // logging
}
}
With AOP:
class PaymentService {
public void processPayment() {
// only business logic
}
}
@Aspect
class LoggingAspect {
@Before("execution(* PaymentService.*(..))")
public void logBefore() {
[Link]("Starting payment...");
}
313
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@After("execution(* PaymentService.*(..))")
public void logAfter() {
[Link]("Payment done.");
}
}
Here the logging concern is completely separate and placed in something called @Aspect (Will
see next questions).
Reference: Spring AOP Explained: How to Implement Aspect-Oriented Programming in Your
Spring Application | by Alex Klimenko | Medium
Indirect Questions:
1. When will you use the AOP?
When we want to separate cross-cutting concerns from the main business logic.
2. What are cross cutting concerns?
3. How you implement AOP in Spring boot application?
To implement AOP, start with including the spring-boot-starter-aop module in the
application dependencies.
4. What is @EnableAspectJAutoProxy and when to use?
We use @EnableAspectJAutoProxy when we need to enable Spring's ability to
automatically create proxies for the beans. It used to implement AOP features like
@Transactional, @Secured, or the own custom @Aspect classes.
In practice, we often don't need to use it explicitly because many Spring modules (like
Spring Boot, Spring Transaction Management) already auto-configure it for us.
In a Non-Boot, Java-based Configuration Application, if we are building a standard Spring
application (not using Spring Boot) with @Configuration classes, and we want to use AOP, then
we must add this annotation to one of the configuration classes.
Code Link: Spring-Samples/aop at main · CodingLyf-Fullstack/Spring-Samples
Run this code and hit ` GET /users/1`. You will see the output
Around (Before): getUserById
Before method: getUserById | Args: [1]
After method: getUserById | Returned: CodingLyf
Around (After): getUserById
314
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Advice.
Weaving.
Proxy.
Aspect: It is basically a class where we define cross-cutting code. Ex: The class where our log
statements exist.
class PaymentService {
public void processPayment() {
// only business logic
}
}
@Aspect
class LoggingAspect {
@Before("execution(* PaymentService.*(..))")
public void logBefore() {
[Link]("Starting payment...");
}
@After("execution(* PaymentService.*(..))")
public void logAfter() {
[Link]("Payment done.");
}
}
3. @Around: Wraps the method, running both before and after. This is the most powerful
advice type. It surrounds a join point, such as a method invocation, and has the ability to
prevent the actual method execution. It takes a ProceedingJoinPoint as a parameter,
which is useful to execute the target method. By calling the proceed() method on the
ProceedingJoinPoint, we can proceed with the original method execution.
4. After Returning: Runs only if the method completes successfully. We can use it for
Auditing or logging after methods execution or resource clean up.
315
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Proxy: This is very important in Spring. All the cross-cutting concerns use Proxy. We will see it as
separate question (Refer Question No 362 Spring 110. then go to next question)
Here we have Class A, calling a method in classB and class AOP has a method which is
responsible for logging.
1. Class A
This is a normal class in the application.
It calls a method of Class B (let’s say methodOfClassB()).
2. Class B
This contains the business logic. For example, it may process payments, calculate
discounts, etc.
Normally, Class A would just call Class B directly.
But with AOP, it doesn’t call Class B directly; instead, it calls a proxy of Class B.
3. Class B Proxy
316
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
343 Spring 93: Which classes or methods in Spring cannot be declared as final, and why??
Spring creates proxies for certain features like @Transactional, @Async, @Configuration,
and AOP in general.
Why final matters in Spring
Spring often uses CGLIB proxies to add extra behaviour to the classes at runtime. CGLIB works by
subclassing the class and overriding methods.
If a class or method is final, it cannot be subclassed or overridden, so CGLIB cannot apply its
proxy. That breaks things like:
@Transactional
@Async
@Cacheable, @CacheEvict
@Configuration (when calling @Bean methods internally)
Rules
1. Classes
o We cannot make a class final if Spring needs to create a proxy for it (like a
@Service or @Configuration with transactional beans).
o We can make it final if no proxying is needed (simple component with no AOP
features).
317
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
2. Methods
o Any method annotated with @Transactional, @Async, @Cacheable, etc., cannot
be final, because the proxy needs to override it.
o Final methods are ignored by proxies.
@Service
@Transactional
public final class BankService { // final class breaks transactional proxy
public void transferMoney() { … } // if method is final, proxy cannot
intercept
}
@Service
@Transactional
public class BankService { // class is non-final
public void transferMoney() { … } // method is non-final
}
@Transactional
public void saveTransaction() {
[Link]("Saving transaction...");
}
}
318
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Question:
1. You have configured scheduled task only once but it is running twice. What might be the
issue?
319
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Multiple application instances: if the app is running on multiple servers or multiple Spring
contexts, each instance runs its own scheduler.
Use Distributed cache lock like Redisson’s RLock to ensure only one instance runs the
task.
Multiple bean definitions: if the same @Scheduled method is present in multiple beans or
contexts, it runs multiple times.
2. You have configured scheduled but it is not running. What might be the issue?
@EnableScheduling is missing in the configuration.
The scheduled method must be public and inside a Spring-managed bean (e.g.,
annotated with @Component, @Service, or defined as a @Bean). If it is private,
protected, or in a class Spring doesn’t manage, the scheduler won’t detect or run it.
The cron/fixedRate/fixedDelay expression is incorrect or misconfigured.
346 Spring 96: What is the difference between fixedDelay and fixedRate?
fixedDelay: This is used to give specific delay between the completion of one task execution and
the start of the next.
The next run starts only after the current run finishes + the delay time.
Example: If a task takes 4 seconds and delay is 3 seconds: then the next run starts at 7
seconds.
Use Case: Good for tasks where execution time may vary (like sending emails, file
processing, DB cleanup) and we always want a gap between runs.
fixedRate: This property schedules the task to run at a consistent, fixed interval, regardless of
how long the previous execution took.
Example: If rate is 5 seconds, it runs at 0s, 5s, 10s, 15s… even if the previous task is still
running.
Use Case: Best for tasks that need strict periodic execution, like health checks,
monitoring, refreshing cache, or fetching data at fixed times.
347 Spring 97: How can you make tasks run in parallel?
By default, Spring runs all @Scheduled tasks in a single thread. That means if one task
takes time, the next one waits. To make them run in parallel, we need to give Spring a thread
pool for scheduling.
We can use ThreadPoolTaskScheduler, a scheduler that supports various scheduling options and
manages a thread pool for task execution. The ThreadPoolTaskScheduler uses
a [Link] to manage a pool of threads.
We can configure the ThreadPoolTaskScheduler to suit the application's needs. Some common
configuration options include:
Pool size: The number of threads in the thread pool
320
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Thread name prefix: A prefix for thread names, useful for debugging
Wait for tasks to complete on shutdown: A flag to indicate whether the scheduler
should wait for scheduled tasks to complete before shutting down
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
[Link](5);
[Link]("MyTaskScheduler-");
[Link](true);
return scheduler;
}
}
Tasks:
@Component
public class MyTasks {
@Scheduled(fixedRate = 2000)
public void task1() throws InterruptedException {
[Link]([Link]().getName() + " running task1");
[Link](4000); // simulate long work
}
@Scheduled(fixedRate = 2000)
public void task2() {
[Link]([Link]().getName() + " running task2");
}
}
Without the thread pool: task2 will be delayed until task1 finishes.
With the thread pool: both can run at the same time.
@Override
public void handleError(Throwable t) {
// Custom logic for handling errors
[Link]("Error encountered in scheduled task: " +
[Link]());
321
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
To use this custom error handler, we would need to set it in the task scheduler.
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
[Link](5);
[Link]("scheduler-");
[Link](new MyErrorHandler()); //Error Handler
return scheduler;
}
}
349 Spring 99: How to run a task in the background in Spring boot?
In Spring Boot, if we want to run a task in the background (async execution), we typically
use @Async.
Step 1: Enable Async Support
In the main application class (or any config class), enable async execution:
@Configuration
@EnableAsync
public class Config {
@Async
public void process(String userEmail) {
try {
[Link](5000); // simulate delay
[Link]("Delayed task");
} catch (InterruptedException e) {
[Link]().interrupt();
}
}
}
322
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
323
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When the class has a method annotated with @Async, Spring doesn’t call the method
directly.
Instead, it creates a proxy object (using JDK dynamic proxies or CGLIB, depending on the
class).
The proxy intercepts method calls and decides how to execute them.
2. Intercepts the call
When we call a method, instead of running it on the caller’s thread, the proxy hands the
task over to a TaskExecutor (basically a thread pool).
By default, spring uses SimpleAsyncTaskExecutor if no executor is provided, but in real
projects we usually configure the own ThreadPoolTaskExecutor.
3. Method execution happens on a different thread
The proxy submits the method as a task (Runnable or Callable) to the executor.
The original caller thread doesn’t wait for the task to finish (unless we return
Future/CompletableFuture).
This is how it becomes asynchronous.
4. Return type decides behavior
void: fire and forget. Caller has no clue if the task succeeded/failed.
Future / CompletableFuture : Caller can track progress, get results, or handle exceptions.
Point to remember:
Due to the proxy-based nature of Spring’s AOP framework, if we call an @Async method
from another method within the same class, it will not actually execute asynchronously. This is
because the call won't go through the proxy but it is just a direct method call. Always be aware
of this limitation. (Self-invocation problem Refer Question 346 No. Spring 94)
@Service
public class MyAsyncService {
@Async
public void asyncVoidTask() throws InterruptedException {
[Link]([Link]().getName() + " running void
task");
[Link](1000);
[Link]([Link]().getName() + " finished void
task");
}
@Async
public CompletableFuture<String> asyncFutureTask() throws InterruptedException
{
[Link]([Link]().getName() + " running future
task");
[Link](1000);
[Link]([Link]().getName() + " finished future
task");
return [Link]("Task Done");
}
}
324
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
In this example, first method is not returning anything whereas second method is returning
CompletableFuture
@GetMapping("/runAsync")
public String run() throws Exception {
[Link](); // fire-and-forget
CompletableFuture<String> result = [Link](); // trackable
[Link]("Controller thread: " + [Link]().getName());
return "Async tasks triggered";
}
351 Spring 101: Can you run Database transactional tasks in Async?
It takes too long to write here. I would suggest you to go through the link, worth reading.
Link: Handling Asynchronous Execution with Transactions in Spring: A Common Pitfall and How
to Solve It - DEV Community
@Service
public class ProductService {
325
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
value = "products" is the cache name where Spring will store and look up the cached data
key = "'allProducts'" means Spring will always use the string "allProducts" as the cache key
354 Spring 104: What is the importance of the key while caching?
Keys are critical in caching because they uniquely identify the cached data.
When we call a cached method, Spring creates a key based on the method parameters
(by default all arguments are considered).
If two calls have the same key, Spring returns the cached result instead of executing the
method.
Without proper keys, data could be incorrectly reused or duplicated. We can customize
keys using SpEL (@Cacheable(key = "#id")) to cache only the values we need.
Good key strategy ensures accurate retrieval, avoids collisions, and optimizes memory
usage for the cache.
}
Here, caching happens only if id > 10.
}
This prevents caching null results.
326
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Whenever this method runs, the cache is updated with the latest product, ensuring consistency
between DB and cache.
It is great for development and testing, but not recommended for production because the cache
is limited to the JVM, not distributed, and is lost when the app restarts.
Point to remember: For production, Redis or Caffeine is usually preferred.
360 Spring 110: What is proxy and how does it work Spring?
A proxy is like a middleman (or wrapper) that Spring creates around the actual object
(the target).
When we call a method, we are not calling the real object directly but we are calling the proxy.
327
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The proxy can do extra work before or after calling the real method.
Point to remember: This is how Spring applies proxies like AOP, transactions, security, or caching
without writing extra code in our class.
Let’s see an example:
We have an interface called ‘Service’ and we created Payment Service class implementing the
‘Service’.
interface Service {
void processPayment();
}
//Proxy class
class PaymentServiceProxy implements Service {
private final PaymentService target;
@Override
public void processPayment() {
[Link]("Before: Logging before payment...");
[Link](); // call the real object
[Link]("After: Logging after payment...");
}
}
In our example, PaymentServiceProxy has been created and it will pass the real service to the
proxy. Now Proxy can do extra code before or after the original method (processPayment())
execution.
There are two types of proxies in Spring:
1. JDK Dynamic Proxies (Requires an Interface)
If the target class implements an interface, Spring will create a dynamic proxy that
implements the same interface.
2. CGLIB Proxies (No Interface Required)
328
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If there is no interface, Spring generates a subclass proxy using CGLIB (Code Generation
Library).
Reference: Understanding the Proxy Pattern in Spring Boot with Practical Insights | by Davoud
Badamchi | Medium (It contains how proxies work in AOP, @Transactional and Caching).
@Bean
public UserService userService() {
return new UserService(orderService()); // direct method call
}
@Bean
public OrderService orderService() {
return new OrderService();
}
}
362 Spring 112: What is filter in Spring boot and how it will used?
In Spring Boot, a Filter is a component that intercepts and processes HTTP requests and
responses at the web container level, before they reach the Spring DispatcherServlet and after
the DispatcherServlet has handled them. Filters are part of the Java Servlet API and are used to
implement cross-cutting concerns in web applications.
329
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
330
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Point to remember: If we annotate the filter with @Component, Spring Boot automatically adds
it to the filter chain.
Use cases of filters.
Authentication & Authorization: Check JWT tokens, session IDs, or API keys.
Logging & Auditing: Log request URLs, headers, or response times.
Compression or Transformation: Compress responses, modify headers, or transform
JSON.
Rate Limiting: Block excessive requests.
CORS Handling: Add headers for cross-origin requests.
Indirect Question:
1. How can you implement JWT token validation for all APIs without modifying each controller?
Use a custom filter (e.g., extending OncePerRequestFilter) and register it in the Spring
Security filter chain.
2. If you want to log every incoming API call and its response time, which component would you
use?
Implement a Spring Filter or HandlerInterceptor (Refer Question no 100 for Interceptor)
3. How does Spring Boot decide the order in which filters are executed?
Using @Order annotation
331
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
preHandle():
When an interceptor is implemented, any request before reaching the desired
controller will be intercepted by this interceptor and some pre-processing can be
performed like logging, authentication, redirection, etc.
Must return true to continue to the controller; false stops the request.
postHandle():
332
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
This method is executed after the request is served but just before the response
is sent back to the client. It intercepts the request in the final stage, giving us a chance to
make any final trivial adjustments.
afterCompletion():
This method is executed after the request and response mechanism is
completed. This method can turn out to be very useful in cleaning up the resources once
the request is served completely.
Step 2: Interceptors need to be registered with Spring MVC using WebMvcConfigurer:s
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
[Link](myInterceptor)
.addPathPatterns("/**"); // Apply to all endpoints
}
}
Access to Does not know about controllers or Has access to handler (controller
Handler handler methods method) and ModelAndView
333
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
367 Spring 117: Have you written any custom Annotation, if yes how you have written it?
Annotations are created by using ‘@’ sign, followed by the keyword interface, and
followed by annotation name as shown in the below example.
public @interface EnableRestCallLogs{
Generally, each Annotation can contain meta-annotations. Both of these are not mandatory. If
not applied, default values will be considered.
@Retention
@Target.
Retention policy(@Retention)
It specifies the Retention policy. A retention policy determines at what time annotation should
be discarded. Mainly java defined 3 types of retention policies.
Those are SOURCE, CLASS and RUNTIME.
The SOURCE policy will be retained only with source code, and discarded during compile
time. It effected on before compile the source code. Besides that very common java
annotations
like @Override, @Deprecated, @FunctionalInterface,@SuppressWarnings also uses
retention policy as SOURCE.
The retention policy CLASS will be retained until compiling the code, and discarded
during runtime.
Retention policy RUNTIME will be available to the JVM through runtime. If we not
specify the retention policy the default retention policy type is CLASS.
Target(@Target)
@Target annotation definition defines where to apply the annotation .
It takes ElementType enumeration as its only argument.
The ElementType enumeration is a constant which specifies the type of the program
element declaration (class, interface, constructor, etc.) to which the annotation can be
applied.
Type -> Class, interface or enumeration
Field -> Field
334
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
import [Link];
import [Link];
import [Link];
import [Link];
// Custom annotation
@Retention([Link]) // Annotation should be available at runtime
@Target([Link]) // Can be applied only on methods
public @interface LogExecutionTime {
}
@Bean
public UserService userService() {
return new UserService(orderService()); // creates new OrderService each
time
}
@Bean
public OrderService orderService() {
return new OrderService();
}
}
Here, userService() will get a new instance of OrderService() instead of the Spring-managed one.
@Configuration
@Configuration is a specialized form of @Component.
It not only registers the class as a bean but also enables full configuration features.
Specifically, it uses CGLIB proxies to intercept calls between @Bean methods and ensure
singleton semantics which means even if one @Bean method calls another, we still get
the same Spring-managed bean instance.
@Configuration
335
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Bean
public UserService userService() {
return new UserService(orderService()); // gets the Spring-managed
singleton
}
@Bean
public OrderService orderService() {
return new OrderService();
}
}
Here, userService() will get the same OrderService instance from the container.
Point to remember:
@Component: No proxying means calling one @Bean method from another creates a new
object.
@Configuration: Proxying enabled means Spring ensures that all @Bean methods return proper
container-managed singletons.
369 Spring 119: What are best techniques to handle exceptions in Spring?
[Link]-Catch Blocks (Local Handling)
The simplest approach is to use try-catch within a method.
Pros: Quick for simple cases.
Cons: Leads to duplicate code if many methods need similar handling.
Example:
try {
[Link](id);
} catch (UserNotFoundException e) {
// handle exception locally
}
@RestController
public class UserController {
@ExceptionHandler([Link])
public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) {
return [Link](HttpStatus.NOT_FOUND).body([Link]());
}
}
336
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@ExceptionHandler([Link])
public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException
ex) {
ErrorResponse error = new ErrorResponse("USER_NOT_FOUND",
[Link]());
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
@ExceptionHandler([Link])
public ResponseEntity<ErrorResponse> handleGenericException(Exception ex) {
ErrorResponse error = new ErrorResponse("INTERNAL_ERROR", "Something went
wrong");
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
4. ResponseEntityExceptionHandler
Spring provides a base class ResponseEntityExceptionHandler with default handling for
common exceptions.
We can extend it in the @ControllerAdvice to customize default exception handling.
Useful for exceptions like MethodArgumentNotValidException (validation errors).
@RestControllerAdvice
public class CustomResponseEntityExceptionHandler extends
ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatusCode status,
WebRequest request) {
[Link]("errors", errors);
337
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](body);
return new ResponseEntity<>(body, status);
}
5. Custom Exceptions
We can define our own exception classes to make the code readable and meaningful.
Combine with @ExceptionHandler or @ControllerAdvice.
public class UserNotFoundException extends RuntimeException {
public UserNotFoundException(String message) {
super(message);
}
}
Indirect Questions
1. Define @ExceptionHandler or @ControllerAdvice
@ExceptionHandler handles exceptions inside one controller, while @ControllerAdvice
applies globally across controllers.
2. If I define @ExceptionHandler for a custom exception in a controller and also in a
@ControllerAdvice, which one gets executed and why
If both exist, the local @ExceptionHandler in the controller wins, because Spring gives
priority to controller-scoped handlers.
3. If you don’t define any @ControllerAdvice or @ExceptionHandler, what kind of response does
Spring Boot return for an exception thrown in a REST API?
Without custom handlers, Spring Boot returns a default JSON error response (status,
error, message, timestamp, path) using BasicErrorController.
4. If multiple @ControllerAdvice classes handle the same exception type, how does Spring
decide which one to use?
If multiple @ControllerAdvice match, Spring picks the most specific one (by exception
hierarchy or @Order annotation).
5. If a service method annotated with @Async throws an exception, will your @ControllerAdvice
catch it? If not, how would you handle it
Exceptions from @Async methods don’t reach @ControllerAdvice. We need to handle
them via AsyncUncaughtExceptionHandler
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler
{
@Override
public void handleUncaughtException(Throwable ex, Method method, Object...
params) {
[Link](
"Exception occurred in async method: " +
[Link]()
+ " with message: " + [Link]());
// Log the exception, send notifications, etc.
338
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
7. How can you restrict @ControllerAdvice only to controller or exceptions from specific
packages
We can restrict @ControllerAdvice with basePackages, basePackageClasses, or
annotations so it only applies to specific controllers or packages.
//Applies only to controllers in package "[Link]"
@ControllerAdvice(basePackages = "[Link]")
public class ApiExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<String> handle(Exception ex) {
return [Link]().body("API error: " +
[Link]());
}
}
8. What is ProblemDetails?
ProblemDetails is a standard format that is defined in RFC 7807 for describing errors and
exceptions in HTTP APIs. The format includes a set of predefined fields, such as the error type,
error code, error message, and additional details about the error.
@RestControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = { [Link] })
protected ResponseEntity<Object> handleCustomException(CustomException ex,
WebRequest request) {
ProblemDetails problemDetails = new ProblemDetails();
[Link](HttpStatus.BAD_REQUEST);
[Link]("Custom Exception");
[Link]([Link]());
return handleExceptionInternal(ex, problemDetails, new HttpHeaders(),
HttpStatus.BAD_REQUEST, request);
}
339
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Without Index:
With Index:
The database goes to the index on email, finds the location of the matching row(s) quickly, and
jumps directly there.
It is like going straight to the correct shelf in a library rather than checking every book.
This is much faster, often reducing lookup time from seconds to milliseconds.
Please note: If we create too many indexes, it may hurt write performance and increase storage
usage.
340
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
371 Spring 121: What is externalization and how would you achieve it?
When we build applications, one of the fundamental principles is separation of
configuration from code. We don’t want to hardcode things like database URLs, API keys, file
paths, or feature toggles directly into the Java classes. Why? Because those values often change
between environments like development, testing, staging, and production.
Externalization is the practice of moving configuration values outside the application
code so they can be changed without modifying or recompiling the application. Instead of
editing Java classes, we adjust a configuration file, an environment variable, or even a command-
line argument.
How Spring Achieves Externalization
1. Using Application Properties/YAML Files: Configurations placed in [Link] or
[Link]
[Link]=jdbc:mysql://localhost:3306/mydb
[Link]=root
[Link]=secret
2. Using Command-Line Arguments: we can override properties at runtime without touching the
code.
java -jar [Link] --[Link]=9090
3. Using Environment Variables: It is useful in cloud or containerized deployments. Example:
setting SPRING_DATASOURCE_PASSWORD in Docker or Kubernetes.
How Spring read external configurations?
1. Using @Value annotation
The @Value annotation in Spring Boot is used to inject values into fields, method
parameters, or constructors of Spring-managed beans.
@Value("${[Link]}")
private String dbUrl;
Main disadvantage of @value is , It is not type-safe; wrong values can cause runtime errors.
To overcome this, we can use @ConfigurationProperties.
2. @ConfigurationProperties
Instead of injecting individual values like @Value, it binds a whole set of related properties
into a strongly typed POJO.
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String name;
private int timeout;
[Link]:
341
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
app:
name: MyApplication
timeout: 5000
Here, name and timeout are mapped to the fields of AppProperties file.
Spring Data JPA auditing hooks into the entity lifecycle. When we save or update an entity, Spring
automatically fills in fields like:
@CreatedBy
@Column(updatable = false)
private String createdBy;
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdDate;
@LastModifiedBy
private String lastModifiedBy;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
}
342
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Any entity that extends this base class will automatically get audit fields populated.
@Entity
public class Product extends Auditable {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
Spring needs to know who the current user is. We do that by providing a bean of type
AuditorAware<T>.
@Bean
public AuditorAware<String> auditorAware() {
// In real apps, fetch from SecurityContextHolder
return () -> [Link]("system_user");
}
}
Step 5: Save
Whenever we save or update a Product, Spring will automatically fill in audit fields.
Product product = new Product();
[Link]("Laptop");
[Link](product);
// createdBy = "system_user"
// createdDate = current timestamp
// lastModifiedBy = "system_user"
// lastModifiedDate = current timestamp
@EnableJpaAuditing: This annotation is placed on a Spring configuration class (e.g., the main
application class ).Its purpose is to activate the JPA auditing features provided by Spring Data.
When this annotation is present, Spring Data JPA automatically detects and processes entities
that are configured for auditing.
343
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The AuditingEntityListener is a Spring Data JPA class that listens for JPA lifecycle events (like pre-
persist and pre-update).
When these events occur, the AuditingEntityListener automatically populates the auditing fields
within the entity, such as: @CreatedDate, @LastModifiedDate, @CreatedBy
Reference: Database Auditing in Spring boot with spring security context and spring data JPA |
by Mayank Yaduvanshi | Medium
373 Spring 123: Explain application flow of the Spring boot or What will happen when we call
run ()?
When we create a Spring Boot app, we typically start with something like:
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
[Link]([Link], args);
}
}
Under the hood, a lot of things will happen. Let’s walk through the flow step by step.
[Link] Method.
[Link]()
2. Environment Setup.
Spring Boot sets up the Environment, means it loads all the configurations like
[Link], system variables, and command line arguments.
3. ApplicationContext Creation.
Creates the ApplicationContext, it is the heart of Spring that manages all the beans.
applicationContext as the container that holds all the beans.
4. Bean Definitions
Now Spring boot scans all the beans. Spring detects them and registers it in the context.
@Configuration - This annotation indicates that the class is a source of bean definitions for the
Spring application context.
@ComponentScan: This annotation instructs Spring to scan for components within a specified
package (and its sub-packages). It automatically discovers and registers classes annotated
with @Component, @Controller, @Service, @Repository
344
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
5. Auto-Configuration
It is one of best features in Spring boot. Based on classpath and environment, Boot decides what
to configure.
For example:
If spring-boot-starter-web is present, Boot auto-configures Tomcat, DispatcherServlet,
etc.
If spring-boot-starter-data-jpa is present, it configures Hibernate, DataSource, etc.
6. Context Refresh
9. Application Ready
Finally, ApplicationReadyEvent is published.
At this point:
All beans are ready.
The server is up.
And the application is running.
345
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
JPA allows Hibernate (or the JPA provider) decide which strategy to use based on the
underlying database. MySQL uses IDENTITY. Oracle uses SEQUENCE.
2. IDENTITY
The database auto-generates the primary key using an auto-increment column. The ID is
assigned only after insert.
@Entity
class User {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
}
3. SEQUENCE
Uses a database sequence object to generate IDs. Hibernate fetches the next value from
the sequence before the insert. Best for Oracle, PostgreSQL, or any DB that supports sequences.
@Entity
class User {
@Id
@GeneratedValue(strategy = [Link], generator = "user_seq")
@SequenceGenerator(name = "user_seq", sequenceName = "user_sequence",
allocationSize = 1)
private Long id;
}
4. UUID
Generates a globally unique ID (UUID) instead of a numeric value.
@Entity
class User {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String id;
}
Point to remember: @GenericGenerator is deprecated from Hibernate 6.5, we will have to use
alternatives like @UuidGenerator, @IdGeneratorType
Tricky question:
You have an entity with a @GeneratedValue(strategy = [Link]), but while
inserting records, IDs are not generating sequentially. Why?
We are basically telling JPA: “Pick the generation strategy based on the underlying database.”
On PostgreSQL / Oracle, it might use a sequence.
On MySQL, it usually maps to AUTO_INCREMENT.
On H2 / some others, it could choose a table generator.
And here is why we don’t see sequential IDs:
Sequences and identity columns often allocate IDs in blocks for performance. For
example, Hibernate might reserve 50 IDs at a time (allocationSize=50 by default). If the
app restarts, unused IDs are skipped, so gaps appear.
346
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Singleton in Plain Java Before Spring, we create a singleton in Java using private constructors
and static methods.
class CoffeeMachine {
private static CoffeeMachine instance;
347
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Now, when we inject this bean in multiple places: Even though Employee1 and Employee2 have
their own copies of coffeeMachine variable, Spring gives them the same instance of
CoffeeMachine bean.
@Service
class Employee1 {
@Autowired
private CoffeeMachine coffeeMachine;
@Service
class Employee2 {
@Autowired
private CoffeeMachine coffeeMachine;
Additional Questions:
1. In Singleton, what problems may occur with serialization and reflection?
Serialization Problem
When we serialize a singleton object and then deserialize it, Java creates a new instance
of the class.
This breaks the singleton guarantee because now we have two instances.
Use readResolve() method to preserve singleton:
Reflection Problem
Reflection can bypass the private constructor and create a new instance of the singleton.
This also breaks the singleton guarantee.
Reference for reflection: Java Reflection (With Examples)
2. How to break Singleton design pattern?
348
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference: How to BREAK and FIX Singleton Design Pattern | Interview Question
3. How singleton work in multithread environment?
By using synchronized keyword, we can create Singleton object in multithread environment.
Reference: Singleton Design Pattern In Java With All Scenarios Examples
4. How spring's singleton scope is different than GOF singleton?
GoF Singleton (Gang of Four Singleton Design Pattern):
It is a creational pattern where we make sure only one instance of a class exists in the
entire JVM.
The class itself controls its lifecycle, usually with a private constructor and a getInstance()
method.
public class GoFSingleton {
private static GoFSingleton instance;
private GoFSingleton() {}
When we open a website, the browser usually only allow us to talk to the same server it
came from. That is called the Same-Origin Policy. But sometimes we want a page to talk to
349
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
another server; for example, your frontend at [Link] needs to call a Spring Boot
backend at [Link] That is where CORS (Cross-Origin Resource Sharing) comes in.
Here is how Spring handles it internally:
350
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
That is exactly where Spring’s @Retryable comes in. It is part of Spring Retry, and it gives us a
neat way to retry failed operations automatically without writing boilerplate loops.
How it Works
When we put @Retryable on a method:
1. Spring wraps that method in a proxy.
2. If the method throws an exception that we havemarked for retry, Spring will call the
method again.
3. It repeats this until either:
o The method succeeds
o The maximum retry attempts are exhausted
4. If retries are exhausted, we can handle the failure using @Recover.
Example:
Step 1: Add Dependency
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
Step 2: Enable Retry
@SpringBootApplication
@EnableRetry
public class MyApplication {
public static void main(String[] args) {
[Link]([Link], args);
}
}
Step 3: Use @Retryable
@Service
public class PaymentService {
@Retryable(
value = [Link], // Which exception to retry
maxAttempts = 3, // How many times
backoff = @Backoff(delay = 2000) // Wait 2s between retries
)
public void makePayment() {
[Link]("Trying payment... attempt " + counter);
351
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
counter++;
throw new RuntimeException("Payment failed!");
}
@Recover
public void recover(RuntimeException e) {
[Link]("All retries exhausted. Payment failed permanently: " +
[Link]());
}
}
Key Points to Remember
@Retryable works only on Spring-managed beans.
It needs Spring AOP (that is why we added spring-boot-starter-aop).
Use @Recover to define a fallback method after retries fail.
We can control retries with:
o maxAttempts means how many times
o backoff means delay, multiplier (exponential backoff)
o value to which exceptions trigger retry
378 Spring 128: How proxyMode works in Spring and how does it help?
Problem: Injecting a Short-Lived Bean into a Long-Lived Bean
Imagine we have a singleton bean (default scope) and a request-scoped bean. We want to inject
the request-scoped bean into the singleton:
Singleton bean:
@Service
public class SingletonService {
@Autowired
private RequestService requestService; // Problem!
352
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
What happens: Spring will throw an error or inject the same instance of the request bean into
the singleton. That is wrong, because request-scoped beans are supposed to be new for each
HTTP request.
The core issue: singleton lives longer than request, so Spring doesn’t know which request
instance to inject.
Solution: Use proxyMode
Definition: In Spring Framework, proxyMode = ScopedProxyMode.TARGET_CLASS is used in
conjunction with the @Scope annotation to define how a scoped bean (like a prototype,
request, or session-scoped bean) should be injected into other beans, especially singleton
beans.
Spring provides a way to inject a proxy instead of the actual request bean. The proxy acts like a
placeholder and resolves the actual bean at runtime based on the current request.
@Component
@RequestScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestService {
private final String id = [Link]().toString();
379 Spring 129: How to deploy Spring boot application using jar or war?
When we finish building a Spring Boot project, the next big step is deployment.
This means taking the application out of the IDE and running it in the real world means on a
server, or even in the cloud.
Spring Boot makes this surprisingly simple, and it gives, two main ways to package and deploy
the application:
As an executable JAR
As a traditional WAR
By default, Spring Boot applications are packaged as JAR files. Because Spring Boot already
bundles an embedded web server (Tomcat, Jetty, or Undertow). That means the app carries its
own server inside, like a backpack. We don’t need to install Tomcat separately.
1. Open the [Link] and make sure the packaging is set to jar:
<packaging>jar</packaging>
353
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
4. Run it just like any other Java program: java -jar target/[Link]
Before Spring Boot came along, Java web apps were typically packaged as WAR files and
deployed into external servers like Tomcat, JBoss, or WebLogic.
This approach is still used in companies that maintain older infrastructures.
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder)
{
return [Link]([Link]);
}
Drop this WAR file into the external server’s webapps/ directory (for Tomcat, it is usually
/apache-tomcat/webapps/).
Additional Questions:
A JAR file stands for Java Archive. It is a package file format used to aggregate many Java classes,
associated metadata, and resources (like images or text) into one file for easy distribution. JAR
files are primarily used for deploying standalone Java applications or libraries that other projects
can reference.
A WAR file stands for Web Application Archive. It is a specialized JAR file specifically for web
applications. It has a standardized structure for deploying to a Servlet Container (like Tomcat,
Jetty) or Application Server (like WildFly, WebSphere).
354
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Standalone Applications: Any application that has its own main() method and is run from the
command line (e.g., using java -jar [Link]). This is the standard for:
o Microservices
o Batch jobs (e.g., using Spring Batch)
o CLI tools and utilities
o Desktop applications (though less common now)
Modern Spring Boot Applications: This is a crucial point. Spring Boot uses an "embedded
server" approach.
355
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The [Link](1, 2) means page index 1 (remember it starts at 0), with 5 items per page.
Spring takes care of building the LIMIT and OFFSET query for us.
Reference: Spring Boot Pagination and Sorting Example
Offset pagination works for small datasets, imagine if we request for 10,000th page, then
Database has to scan first 10000 records to skip them when slows down the process. For very
large datasets we use Keyset/Cursor pagination.
2. Keyset Pagination (Also known as Cursor Pagination):
Keyset pagination retrieves records based on a specific key (usually a unique, indexed
column like ID or timestamp). This makes it faster and more scalable, especially for large
datasets.
Example, Let’s say we are using “timestamp” as key:
In the first API call clients send without any key: GET /products?&size=10, so Backend has to first
10 records, SQL for this is
SELECT * FROM products ORDER BY timestamp ASC LIMIT 10;
The backend returns those 10 products and also includes the last product’s timestamp in the
response (let’s say 2025-01-01).
From next request, Client to has to send latest timestamp in the key GET /products?key=2025-
01-01&size=10. SQL:
SELECT * FROM products WHERE timestamp > 2025-01-01 ORDER BY timestamp ASC LIMIT
10;
Which means client wants the 10 records after Jan 1st 2025. From there every request should
contain the key.
Code Example:
public interface OrderRepository extends JpaRepository<Order, Long> {
356
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Below service decides which query to call depending on whether a cursor is provided.
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
if (cursor == null) {
return [Link](pageable);
} else {
return [Link](cursor, pageable);
}
}
}
REST APIs
381 Rest 1: What is REST API and what are its uses?
REST (Representational State Transfer) API is a way for two systems (like a frontend app and a
backend server) to talk to each other over HTTP using a set of rules. Instead of inventing new
ways to exchange data, REST relies on standard HTTP methods like:
GET: fetch data
POST: create data
PUT/PATCH: update data
DELETE: remove data
The data is usually sent in formats like JSON or XML (JSON is the most common).
Example:
GET /users/1: Get details of user with ID 1
POST /users: Create a new user
Uses of REST API
1. Communication between applications: Web app or mobile app can fetch data from a
backend server via REST APIs.
357
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Bean
358
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
PATCH: It is used for Partially updates means only the fields we send are updated, the rest stay
unchanged.
@PatchMapping("/{id}")
public ResponseEntity<User> patchUser(@PathVariable Long id, @RequestBody
Map<String, Object> updates) {
return [Link](id)
.map(user -> {
[Link]((key, value) -> {
switch (key) {
case "name": [Link]((String) value); break;
case "age": [Link]((Integer) value); break;
case "city": [Link]((String) value); break;
}
});
359
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
return [Link]([Link](user));
})
.orElse([Link]().build());
}
Tricky Question:
In both the methods we are using [Link](user), then how does PUT
different from PATCH?
Let’s see How save() works under the hood
In JPA/Hibernate, save() doesn’t directly do an SQL UPDATE of everything.
It checks if the entity already exists (id is present).
o If new, it runs INSERT.
o If existing, it compares fields in the managed entity with what’s changed and
generates an UPDATE ... SET ... WHERE id=?.
Here the thing is it is not about what Hibernate does, it is about semantics of the API contract.
Technically, both may call save()
But from a REST design perspective:
Use PUT if clients must send the entire object.
Use PATCH if clients can send only the fields they want to change.
383 Rest 3: Can you tell what are the annotations you used while developing REST APIs?
@RestController: Marks the class as a REST controller (returns JSON/XML instead of views).
@RequestMapping: Defines the base URL for all methods in the controller.
@GetMapping, @PostMapping, @PutMapping, @PatchMapping, @DeleteMapping: HTTP-
specific shortcuts for CRUD endpoints.
@PathVariable: Extracts values from the URI path.
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
360
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Spring will look for a template called Hello [Link] instead of returning "Hello World" as text.
To return raw data (like JSON, String, etc.), we must use @ResponseBody or just switch to
@RestController.
3: Can we use @RestController and still return a view (HTML)?
By default, no. @RestController forces @ResponseBody on all methods, so it always returns
JSON/XML.
If we really want to return a view, we must explicitly use ModelAndView.
@RestController
public class PageController {
361
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@GetMapping("/page")
public ModelAndView getPage() {
return new ModelAndView("home"); // renders [Link]
}
}
@GetMapping
It is the Shortcut (specialization) of @RequestMapping(method = [Link]).
It is Cleaner, more readable when the method is only handling GET requests.
@GetMapping("/users")
public List<User> getUsers() {
Tricky Questions
1. Can @RequestMapping handle multiple HTTP methods in a single method?
Yes. Example:
@RequestMapping(value = "/users", method = {[Link],
[Link]})
public String handleUsers() {
return "Handled GET or POST";
}
362
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@GetMapping("/users")
public List<User> getAllUsers() {
return [Link](new User(1L, "CodingLyf"));
}
}
Final endpoint = /api/users.
@GetMapping("/users")
public String getUsersByCity(@RequestParam String city) {
return "Users in city: " + city;
}
363
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
// Optional PathVariable
@GetMapping({"/info", "/info/{id}"})
public String getUserInfo(@PathVariable(required = false) Integer id) {
return id == null ? "No ID provided" : "User Info for ID: " + id;
}
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest request) {
String token = [Link](request);
return [Link]()
.header("Authorization", "Bearer " + token)
.body("Login successful");
}
This login APIresponse includes a header + body + status.
1. Can we return ResponseEntity without a body? If yes, what will happen?
Use [Link]().build()
2. How do you map exceptions to different HTTP status codes in a RESTFul Spring boot
application?
1. @ResponseStatus on custom exceptions
Attach the status code directly to an exception class.
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
364
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Whenever this exception is thrown, Spring will return 404 Not Found.
2. @ExceptionHandler inside a @ControllerAdvice
Centralized place to catch exceptions and return proper status codes.
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<String> handleNotFound(ResourceNotFoundException ex) {
return [Link](HttpStatus.NOT_FOUND).body([Link]());
}
@ExceptionHandler([Link])
public ResponseEntity<String> handleBadRequest(IllegalArgumentException ex) {
return
[Link](HttpStatus.BAD_REQUEST).body([Link]());
}
}
HTTP status codes provide a standardized way to indicate the success or failure of an
HTTP request. In REST APIs, they inform the client about the result of their request, such as
success (2xx codes), client errors (4xx codes), or server errors (5xx codes). Proper use of
these codes enhances API usability and debugging.
365
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
389 Rest 9: How Spring send JSON by default / How Spring converts Java object to JSON
while returning response from API?
Here is what happens behind the scenes:
Spring MVC + @RestController
When we return a Java object from a controller method (inside a @RestController or with
@ResponseBody), Spring doesn’t just return the object directly. It delegates to a
HttpMessageConverter to serialize it into the desired format (usually JSON).
class User {
private String name;
private int age;
Response JSON:
{
"name": "CodingLyf",
"age": 1
}
366
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
367
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Controller
@RequestMapping("/users")
public class UserController {
// Returns JSON
@GetMapping("/json")
@ResponseBody
public User getUserJson() {
return new User(1, "CodingLyf");
}
}
368
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
392 Rest 12: How can Spring send XML if default is JSON?
By default, Spring Boot uses Jackson to convert Java objects to JSON. But it can also produce
XML if we include the right dependency.
Steps:
1. Add Jackson XML dependency: If we use Maven, add this to [Link]:
<dependency>
<groupId>[Link]</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
2. Controller Example
@RestController
@RequestMapping("/api")
public class EmployeeController {
369
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
396 Rest 16: How do REST APIs handle versioning, and why is it important?
Once we release an API, people use it. If we change the endpoints, request/response
formats then clients can break mean they may get errors eventually apps fail.
To avoid failures to the existing clients, we use something called API Versioning.
REST API versioning is all about how we manage changes to the API without breaking existing
clients
There are various approaches to versioning a RESTful API, including:
URL Versioning: Adding a version number to the API endpoint (e.g., /api/v1/resource).
Query Parameter Versioning: Specifying the version as a query parameter
(e.g., /api/resource?version=1).
Header Versioning: Sending the version information in a custom header (e.g., X-API-
Version: 1).
397 Rest 17: How do you validate the Request from client in Spring boot?
Spring Boot provides a clean way to handle validation using annotations, binding, and
exception handling.
1. Using Validation Annotations
Spring Boot supports the Jakarta Validation API with annotations like:
@NotNull – ensures the value is not null
370
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
To trigger validation automatically when a client sends a request, we need to use the
@Valid annotation in the controller method
@PostMapping("/users")
public ResponseEntity<String> createUser(@Valid @RequestBody UserRequest request)
{
return [Link]("User created successfully");
}
We can handle errors gracefully using @ControllerAdvice and a global exception handler:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler([Link])
public ResponseEntity<String>
handleValidationErrors(MethodArgumentNotValidException ex) {
String errorMessage = [Link]()
.getFieldErrors()
.stream()
.map(err -> [Link]() + ": " +
[Link]())
.collect([Link](", "));
return [Link]().body(errorMessage);
}
}
This way, we can send a clear message about what went wrong instead of a generic server error.
Let’s say we are creating custom validator to check Strong password. Password should
contain at least 8 chars, 1 digit, 1 uppercase.
371
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2. Create a Custom Constraint Annotation.
Define an annotation that will be used to mark fields or classes for validation. This
annotation needs to specify the validator class and other metadata.
import [Link];
import [Link];
import [Link].*;
@Documented
@Constraint(validatedBy = [Link])
@Target({ [Link] })
@Retention([Link])
public @interface StrongPassword {
String message() default "Password is too weak"; //Default error message
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@Constraint declares the class which will implement our interface and define its
behaviour, StrongPasswordValidator is the class which will implement
StrongPassword interface
@Target defines the program element types to which our custom annotation will apply,
@Retention defines when our annotation will be available.
@Override
public boolean isValid(String password, ConstraintValidatorContext context) {
if (password == null) return false;
// simple example: at least 8 chars, 1 digit, 1 uppercase
return [Link]() >= 8 &&
[Link](".*[A-Z].*") &&
[Link](".*\\d.*");
}
}
4. Apply the Custom Annotation.
Annotate the fields or parameters in the model or DTOs where you want to apply the
custom validation.
public class UserRequest {
372
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@StrongPassword
private String password;
@RestController
@RequestMapping("/users")
public class UserController {
@PostMapping
public String createUser(@Valid @RequestBody UserRequest request) {
return "User created with password: " + [Link]();
}
}
That is it. Now if the password doesn’t meet the rule, Spring Boot will throw a
MethodArgumentNotValidException with the custom message.
Reference: Spring Boot Custom Validation. Creating custom validation in a Spring… | by Bereket
Berhe | Medium
Creating Spring Boot Custom Validators | by Catherine Edelveis | Medium
373
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Example: Cache all product details for 10 minutes in Redis, so repeated API calls don’t hit
the database.
400 Rest 20: How can you handle rate limiting in REST API?
Rate limiting is the process of restricting the number of requests a client can make to an
API within a given time frame. It helps prevent abuse, protects server resources, and ensures fair
usage. Rate limiting can be implemented by tracking the number of requests per client and
enforcing limits using techniques like token bucket or fixed window algorithms
Refer Question No 434, Spring Scenario 23 for the implementation
402 Rest 22: What are different types of authentications used in REST APIs?
Basic Authentication: The client includes the username and password in the request headers.
This method is simple but not recommended for sensitive data as it transmits credentials in
plaintext.
Token-based Authentication: The server generates and returns a token (e.g., JSON Web Token or
JWT) upon successful login. The client includes this token in subsequent requests to access
protected resources.
OAuth: A protocol that allows users to authorize third-party applications to access their
resources without sharing credentials. It involves obtaining an access token from an
authorization server and using it to make authenticated requests.
374
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Scope: All URLs are URIs, but not all URIs are URLs. A URI can be a URN (Uniform
Resource Name) which identifies a resource by its name without specifying its location
(e.g., urn:isbn:0451450523 identifies a book by its ISBN).
Purpose: URIs are for identification, while URLs are for location and access.
Components: URLs always include a protocol (like [Link] [Link] [Link] a domain
name, and potentially a path and file name, all of which are essential for locating and
accessing the resource. URIs can be simpler, focusing solely on identification.
405 Rest 25: What is the difference between synchronous and asynchronous communication
in RESTful web services?
When building RESTful APIs, how the client and server communicate matters. Communication
can either be synchronous or asynchronous.
Synchronous Communication
In synchronous communication, the client sends a request and waits for the server to respond
before doing anything else. The client is essentially “blocked” until the response arrives.
For example, when a client requests user information with GET /users/123, it waits until the
server returns the user data. This approach works well for operations where the result is needed
immediately, such as retrieving, updating, or deleting a resource.
Asynchronous Communication
In asynchronous communication, the client sends a request but does not wait for the server to
respond. Instead, the client continues with other tasks. Later, it can check back for the response
or receive a callback when the server has completed processing.
For instance, if a client requests generating a large report with POST /generate-report, the server
might immediately return a job ID. The client can continue with other work and later query the
status of the report or get notified when it is ready.
406 Rest 26: What are the best practices while designing the REST API?
Designing a RESTful API involves following several best practices. These practices ensure a
reliable, scalable, and easily understandable RESTful API design:
Use meaningful and consistent resource names for the API endpoints.
375
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Use HTTP verbs (GET, POST, PUT, DELETE) correctly to perform the corresponding actions
on the resources.
Ensure that the API is stateless and authentication is handled using tokens or OAuth.
Use descriptive error messages and correct HTTP status codes for responses.
Versioning the API can help manage changes over time.
Lastly, document the API comprehensively, including endpoint details, request and
response formats, and examples.
407 Rest 27: How do you document the APIs and their details?
Swagger allows developers to describe APIs in a structured JSON or YAML format. This
description includes all the endpoints, request parameters, response formats, authentication
methods, and even error codes. Once the API is described, Swagger can automatically generate
human-readable documentation that is easy to navigate.
376
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
409 Rest 29: How do you invoke the other APIs or Inter-service communication in a
microservice in Spring?
In modern applications, it is common for any service to call other APIs, whether internal
microservices or third-party services. Spring provides simple, flexible ways to make these HTTP
requests and handle responses.
1. Using RestTemplate
RestTemplate is the classic way to call REST APIs in Spring. It is synchronous, meaning the
call will block until a response is received.
@Autowired
private RestTemplate restTemplate;
2. Using WebClient
WebClient is part of Spring WebFlux and supports reactive, non-blocking calls. It is the
preferred approach for modern, scalable applications.
@Autowired
private WebClient webClient;
377
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Spring recommends using WebClient (from Spring WebFlux) for new projects because it
supports non-blocking, reactive calls and is more flexible for modern applications.
378
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
return users;
}
We can use an APM (Application Performance Management) tool (like New Relic, Spring
Boot Actuator).
These tools show a detailed breakdown: how much time was spent in controller, service,
repository, etc.
379
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
380
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Steps:
1. To handle database migrations, we can use migrations tools like Flyway or Liquibase.
2. Write SQL changes in separate files and place them in `src/main/resources/db/migration`:
V1__create_users_table.sql
V2__add_email_to_users.sql
The numbering (V1, V2, V3) ensures order, and the tool keeps track of what’s already been
applied.
3. Spring Boot can run Flyway or Liquibase migrations at startup. That means whenever the app
boots, it checks which migrations are pending and applies them. This keeps development and
test environments in sync automatically.
4. Always run them in a staging database first. This helps catch performance issues (like adding
an index on a huge table) or mistakes (like dropping a column that is still used).
5. It always good have rollback mechanism in place. Tools like Liquibase useful to define rollback
scripts. Flyway doesn’t encourage rollbacks but suggests creating a new “fix” migration if
needed.
381
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@GetMapping("/download/{fileName}")
public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) {
try {
Path path = [Link]("uploads/" + fileName);
Resource resource = new UrlResource([Link]());
if (![Link]()) {
return [Link]().build();
}
return [Link]()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + [Link]() + "\"")
.body(resource);
} catch (Exception e) {
return [Link](HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
Additional Questions.
By default, Spring Boot accepts file uploads up to 1MB (per file) and 10MB (per request).
Spring itself doesn’t impose any maximum size, but very large uploads are limited by
memory, disk, and timeout constraints.
382
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
This is where tools like Spring Batch or @Async with ExecutorService comes into picture.
Spring Batch is built exactly for this kind of job like chunked reading, processing, and
writing to DB.
If we don’t want the overhead of Spring Batch, we can write our own async task using
@Async (Refer Question no.351 Spring 99) or even put it on a queue system (like
RabbitMQ, Kafka).
[Link]
[Link]=jdbc:mysql://localhost:3306/devdb
[Link]=devuser
[Link]=devpass
[Link]
[Link]=jdbc:mysql://localhost:3306/proddb
[Link]=produser
[Link]=prodpass
2. Activate the Right Profile
We tell Spring Boot which environment to use by setting the active profile.
This can be done in different ways:
3. Inject Properties.
Use @ConfigurationProperties, this annotation helps us to map the entire content of the
properties file to a POJO (Plain Old Java Object). A property file can be
either [Link] or [Link].
383
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Configuration
@ConfigurationProperties(prefix = "[Link]")
public class DataSourceConfig {
private String url;
private String username;
private String password;
@Profile("dev")
@Service
public class DummyEmailService implements EmailService {
public void send(String to, String msg) {
[Link]("DEV mode: Email not really sent to " + to);
}
}
@Profile("prod")
@Service
public class RealEmailService implements EmailService {
public void send(String to, String msg) {
// actual implementation
}
}
Explanation:
Normally, Spring Boot reads its configuration from [Link] or [Link] files
at startup. So, if we change them, we need to restart the app
To solve this, Spring provides ways to dynamically refresh configurations without restarting.
384
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Create a Git repository (say config-repo). Inside it, place environment-specific property files:
[Link]
[Link]
[Link]
import [Link];
@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
public static void main(String[] args) {
[Link]([Link], args);
}
}
@EnableConfigServer. This annotation tells Spring Boot to enable the Config Server
functionality for the application.
385
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@GetMapping("/feature-status")
public String featureStatus() {
return "Feature X is " + (featureEnabled ? "ENABLED" : "DISABLED");
}
}
The @RefreshScope annotation in Spring Cloud is used to enable dynamic refreshing of
configuration properties within a Spring Boot application without requiring a full application
restart.
How it works?
386
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
In many production systems, we don’t use REST API handle GBs of data directly.
Instead, we issue a pre-signed URL from S3, GCS, or Azure.
Client uploads file directly to cloud while your API just coordinates.
Sample code for GCS (Google cloud storage):
import [Link].*;
import [Link].*;
import [Link];
import [Link];
@RestController
@RequestMapping("/files")
public class FileController {
@GetMapping("/presigned-url")
public String getPresignedUrl(@RequestParam String fileName) {
BlobInfo blobInfo = [Link]("my-bucket-name",
fileName).build();
387
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@EnableCaching:
This annotation is placed on a configuration class or the main application class to enable
Spring's annotation-driven cache management.
@Cacheable:
This annotation marks a method whose result can be cached. When a method annotated
with @Cacheable is invoked, Spring checks if the result for the given arguments is already
present in the cache. If found, the cached value is returned, avoiding method execution. If not
found, the method is executed, and its result is stored in the cache for future use.
@CachePut:
This annotation is used to update the cache with the new result of a method execution
without skipping the method execution itself.
Unlike @Cacheable, @CachePut always executes the method and then places its return
value into the cache, ensuring the cache is refreshed with the latest data.
@CacheEvict:
This annotation is used to remove one or more entries from a cache. It is typically
applied to methods that modify data, ensuring that stale cached data is removed after an update
or deletion operation. This forces subsequent requests for that data to fetch it from the
underlying source (e.g., database), ensuring data consistency.
388
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@PostMapping
public ResponseEntity<String> createUser(@Valid @RequestBody UserRequest
userRequest) {
return [Link]("User created: " + [Link]());
}
}
Here:
@Valid triggers validation on the incoming JSON.
If validation fails, Spring throws MethodArgumentNotValidException.
Then catch the exception with @ExceptionHandler
2. Now, let’s see the job that will run every night at midnight.
@Component
public class SalesReportScheduler {
3. Spring will handle them in the background using a default thread pool. If we need a custom
thread pool, configure a TaskScheduler bean.
389
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@GetMapping("/user")
public String getUser() {
return [Link]();
}
}
We don’t have to write any extra code.
Spring sees UserService in the context, sees that both controllers need it, and injects the same
bean instance into both places (because by default, Spring services are singleton scoped).
390
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
Since it is a utility class, it would be idle to use @Bean in Configuration class.
public class DiscountCalculator {
@Bean
public DiscountCalculator discountCalculator() {
return new DiscountCalculator();
}
}
@Configuration tells Spring this class provides bean definitions.
@Bean tells Spring “whenever someone needs DiscountCalculator, use this method to create
and manage it.”
Additional Question:
Why don’t you use @Service or @Compnent to DiscountCalculator?
Service and @Component are meant for general Spring-managed beans. Generally,
@Service class is to maintain the business logic. DiscountCalculator is more like a utility/helper
without business logic. So, annotating it with @Service or @Component adds no real value here.
Common examples are
RestTemplate: we usually create it as a @Bean in a config class so we can reuse the
same instance across the app.
DataSource : Defined as a @Bean to configure database connections (URL,
username, pool size).
ObjectMapper: Registered as a @Bean when we want custom JSON
serialization/deserialization rules.
Example:
public interface PaymentService {
void pay(double amount);
}
391
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Service
@ConditionalOnProperty(name = "[Link]", havingValue = "card")
class CardPaymentService implements PaymentService {
public void pay(double amount) {
[Link]("Paid by Card: " + amount);
}
}
@Service
@ConditionalOnProperty(name = "[Link]", havingValue = "upi")
class UpiPaymentService implements PaymentService {
public void pay(double amount) {
[Link]("Paid by UPI: " + amount);
}
}
Only one bean is created at runtime, depending on the condition ([Link] in
[Link] file). This avoids conflicts and makes bean injection flexible.
Additional Question:
1. Why can’t you use @Profile.
@Profile will be used for environment specific like to load beans based on environment
(Dev or Prod)
Suppose if we have more complex logic that can’t be resolved in @ConditionalOnExpression and
same condition is being used in multiple times , then we need to go with custom Condition class
public class LinuxAndPropertyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata
metadata) {
String os = [Link]("[Link]").toLowerCase();
String brokerType = [Link]().getProperty("[Link]");
392
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
427 Spring Scenario 17: Dynamic bean selection, based on parameter from client.
Imagine you are building a payment service. Your app supports multiple payment
gateways like PayPal, Stripe, and Razorpay.
You cannot solve this with @Profile or @ConditionalOnProperty because that work only
at application startup based on config/environment.
Means, when client send paypal (POST /pay?type=paypal&amount=100), paypal service should
be invoked.
Explanation:
In this case, we inject all candidate beans and pick one dynamically at runtime. Spring
won’t create/destroy beans per request, but we can route requests to the right bean.
Strategy pattern means: instead of writing many if-else for different logics, we keep each logic in
a separate class and pick the one we need at runtime. This makes code clean, flexible, and easy
to change without touching the main class.
393
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
@Component("stripe")
class StripeProcessor implements PaymentProcessor {
public void processPayment(double amount) {
[Link]("Paid " + amount + " via Stripe");
}
}
Step 4: Controller
@RestController
class PaymentController {
private final PaymentService paymentService;
@PostMapping("/pay")
public void pay(@RequestParam String type, @RequestParam double amount) {
[Link](type, amount);
}
}
Now On POST call /pay?type=paypal&amount=100 , Spring routes to PaypalProcessor.
Explanation:
394
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@PostConstruct is useful when we want to run some initialization logic right after Spring creates
and injects the bean, without needing a CommandLineRunner or ApplicationRunner. It Runs
right after bean creation and dependency injection is done. Best when we need to initialize
resources
CommandLineRunner: Runs after the whole Spring context is ready. Best when we need
application-wide startup logic. Example: inserting the database
@PostConstruct runs right after the bean is created, before the full Spring Boot context
is ready.
At that time, all beans (like EntityManager, TransactionManager, Repositories) may not
be fully available. This can cause errors or missing transaction issues when we try
inserting data.
On the other hand, CommandLineRunner or ApplicationRunner run after the entire
Spring context is ready, meaning our DB connections, repositories, and transactions are
fully initialized. Perfect for inserting.
Spring Boot provides support for various logging frameworks such as Logback, Log4j2, and SLF4J.
SLF4J
It is not a logging implementation. It is a facade means a common API that routes all the logging
calls to a real logging backend like Logback or Log4j.
Think of SLF4J as: “The common interface the code uses to log, while the actual logging engine
does the actual work.”
Logback
Log4j2
Successor of Log4j (fixed performance & security issues).
Offers advanced features like asynchronous logging (much faster in high-load apps), garbage-free
logging (less memory churn).
Additional Questions:
Explanation:
Spring Boot Actuator provides a powerful set of tools for monitoring and managing applications.
Add Actuator Dependency.
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
396
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
But HTTP POST is not idempotent by design (every call can cause a new resource).
So you need to make POST “behave idempotently” in your scenario. How do you achieve it?
Solutions
1. Idempotency Key
The client (e.g., frontend or mobile app) generates a unique key (like UUID) for every
“intent to place order”.
It sends this key in the request header or body:
POST /orders Headers: Idempotency-Key: abc123
The server stores this key.
o If the same key comes again, it returns the same order response instead of
creating a new one.
2. Database Constraints (Transactional Safety)
}
1. Create Interceptor
In Pre Handle method.
@Component
public class DeleteApiInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) {
if (handler instanceof HandlerMethod handlerMethod) {
AdminOnly adminOnly =
[Link]([Link]);
if (adminOnly == null) {
// Check if user has ADMIN role
[Link](HttpServletResponse.SC_FORBIDDEN);
397
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
return false;
}
}
return true;
}
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
[Link](deleteApiInterceptor)
.addPathPatterns("/delete/*"); // Apply only to /delete/*
}
}
3. Controller
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
We have registered the DeleteApiInterceptor so that it runs for every request under delete/*.
Inside the interceptor, we use HandlerMethod to check if the controller method handling this
request is annotated with @AdminOnly.
398
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If the method does not have the annotation, we block the request and return a 403
Forbidden.
This way, even though the interceptor is invoked for all delete/* APIs, only the methods explicitly
marked with @AdminOnly are allowed to execute.
Steps
FilterRegistrationBean
399
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Solution
Spring Data JPA has a feature called Derived Query Methods. Instead of writing the
whole query, we just follow a naming convention in our repository method. Spring automatically
interprets it into SQL/JPQL for us.
Example:
Repository:
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByEmailEndingWith(String domain);
}
When we call the method
List<User> gmailUsers = [Link]("@[Link]");
Solution
Here we need to write query that involves joins, filtering, or multiple conditions that we
cannot achieve with Derived Query Method.
1. JPQL (object-oriented query, works with entity names and fields), using @Query
Example:
400
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Entity
public class Order {
@Id
private Long id;
private String status;
private double productPrice;
@ManyToOne
private User user;
}
So, a User can have many Orders. That is why Order holds a reference to User.
Now, derived queries (like findByStatus) won’t help here, because we need conditions across
two tables. This is where @Query comes into play
public interface OrderRepository extends JpaRepository<Order, Long> {
401
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
For each of those 100 users, the system again runs one separate query to fetch that user’s
orders.
So that becomes 100 individual queries.
Total: 1 (users query) + 100 (orders queries) = N + 1 queries, where N = number of users.
That’s why with 100 users; you end up with 101 extra queries. Which is N+1 problem. (Refer
Question No. 303,304 Spring 51,52);
[Link] JOIN FETCH: This fetches all the data in one query (Like a join query in SQL)
@Query("SELECT u FROM User u JOIN FETCH [Link] WHERE [Link] = :id")
User findUserWithOrders(@Param("id") Long id);
Solution:
402
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](users);
But here is the catch. saveAll() internally runs for loop and save() each record. If there are 10000
records, it will loop 10000 times. Best technique to persist N number of records is by batching.
Hibernate can group those inserts into batches. All we need is to configure it:
[Link].batch_size=500
[Link].order_inserts=true
[Link].order_updates=true
Now, if we call saveAll() with 10000 records:
Instead of 10000 separate INSERTs, Hibernate will do them in batches of 500.
That means only 20 round trips to the database. Much faster.
You want to update only the status of a user (say from INACTIVE to ACTIVE) without fetching the
entire User object first.
@Modifying
403
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Point to remember: We can achieve Delete also with @Modifying. We can also use it for bulk
updates where can update the record without fetching it first
Solution:
The @SQLDelete annotation is a Hibernate-specific annotation (not part of the standard JPA
specification) which is useful to override the default SQL statement that Hibernate uses to
delete an entity from the database.
Instead of the standard DELETE FROM table_name WHERE id = ?, we can define a custom SQL
query to be executed when [Link]() is called.
404
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Solution:
The naive way is to add two fields: createdDate and updateDate and then, every time we
save an entity, set them manually:
But Spring Data JPA has built-in support for auditing using annotations:
And all of this works by simply enabling auditing (Refer Question No. 373 Spring 122).
Example:
@SpringBootApplication
@EnableJpaAuditing // switch ON auditing
public class App {
@Entity
@EntityListeners([Link])
public class Order {
@Id
@GeneratedValue
private Long id;
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime updatedDate;
}
405
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Approach:
Sampel code
Create Entity:
@Entity
public class Book {
@Id
private Long id;
private String title;
private String author;
}
Create Repository:
public interface BookRepository extends JpaRepository<Book, Long> {
}
Custom Exception:
public class BookNotFoundException extends RuntimeException {
public BookNotFoundException(Long id) {
super("Book with id " + id + " not found");
}
}
Service
@Service
public class BookService {
@Autowired
private BookRepository repository;
@ExceptionHandler([Link])
406
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
In Service, we are invoking findById() which returns Optional, if not found we are throwing a
custom exception. That custom exception will be caught by Global exception handler and returns
NOT_FOUND message to User.
When we use rollbackFor, it adds to the default rollback behaviour, rather than replacing it. This
means that if we specify rollbackFor = {[Link]}, the transaction will still roll
back on RuntimeExceptions and Errors, in addition to MyCheckedException.
407
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Solution:
445 Spring Scenario 35: Improve initial loading time or Cold Start Optimization Techniques
Your Spring Boot application is taking too much time during the initial load. Users notice
that the application takes 10–15 seconds before the first API call responds after startup.
Solution.
When we start the application, following things will happen:
Loading JVM
Initializing the Spring context.
408
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
We use Spring Security (SecurityFilterChain) to configure which URL endpoints are public
and which require authentication.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
409
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
// Admin-only pages
.requestMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin() // default login page
.and()
.logout();
return [Link]();
}
}
Using requestMatchers we can mention which APIs are public and which are should be accessed
by admin.
Solution:
Spring Security gives a clean way to enforce this kind of restriction at the method level use
PreAuthorize or PostAuthorize.
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long userId) {
// delete logic here
}
When anyone calls deleteUser(...), Spring Security checks the logged-in user.
If that user doesn’t have the role ADMIN, Spring throws an AccessDeniedException
before the method body is even executed.
If the user does have the role, then and only then the deletion happens.
410
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
But, Since deleting employees is a sensitive business action, method-level security is the safer
choice. Why? Because:
1. Security should be with the business logic (the delete method), not just with one
endpoint.
Solution:
Spring Boot provides Actuator which gives production-ready monitoring APIs. By enabling it, we
can expose endpoints that the Operations team can consume (Refer Questions No.336 Spring
84)
Approaches:
1. Synchronous Communication:
Example: The Order Service makes a REST API call to the Payment Service (POST /payments) and
waits until it gets a success or failure response.
Tools we can use:
REST (HTTP/JSON): simple and widely used
gRPC: faster, binary protocol, good for high-performance communication
411
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
In Spring, we can use RestTemplate or WebClient(Refer Questions No. 411 Rest 29)
2. Asynchronous Communication (Message driven)
Example: The Order Service publishes an event like OrderCreated to a message broker. The
Payment Service listens for that event, processes payment
Tools we can use:
Kafka
RabbitMQ
Google Pub/Sub / AWS SQS
Explanation:
if we use simple LIKE %keyword% queries on such a huge dataset, performance will degrade
badly because SQL has to look at every single row, one by one.
For large datasets, we cannot rely on plain database queries. You need a search optimization
strategy.
Full-Text Search:
FULLTEXT is a special index designed for text search. It helps you search big text fields
(like names, descriptions, articles, blogs) much faster and smarter.
When we add a FULLTEXT index, SQL creates its own “search-friendly” copy of the text
data. So instead of checking row by row, SQL jumps directly to matching results.
Reference:
412
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
451 Spring Scenario 41: Process Million Records (NOTE: It is about processing not searching)
How would you handle a situation where a Java application needs to process millions of
records efficiently?
Explanation:
If we just load everything into memory and loop over it, the JVM will blow up with
OutOfMemoryError. So, we need to design this smartly.
Instead of pulling all records into memory, fetch them in chunks (pagination).
Instead of fetching everything at once. Fetch records little by little, and process them as
they come. SQL databases can return results in a streaming fashion instead of dumping all rows
at once
Example:
@Repository
interface PostRepository extends JpaRepository<Post, Long> {
@Query("""
select p
from Post p
where date([Link]) >= :sinceDate
"""
)
@QueryHints(
@QueryHint(name = AvailableHints.HINT_FETCH_SIZE, value = "25")
)
Stream<Post> findPosts(@Param("from") LocalDate fromDate);
}
This repository method fetches posts created on or after a given date using JPQL.
The @QueryHint sets the fetch size to 25, so JPA loads rows in chunks instead of all at
once.
It returns a Stream<Post>, allowing lazy, memory-efficient processing of results.
Reference: Spring Data JPA — batching using Streams | by Patrik Hörlin | Predictly on Tech |
Medium
The best way to use Spring Data JPA Stream methods - Vlad Mihalcea
413
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Millions of records usually mean independent tasks. We can opt for parallel processing. Or use a
thread pool (ExecutorService) if we want more control.
[Link]()
.forEach(this::processRecord);
[Link] processing
If the job involves writing back to DB, instead of writing them row by row better to
collect and write in batches.
List<Customer> batch = new ArrayList<>();
for (Customer c : records) {
[Link](c);
if ([Link]() == 1000) {
[Link](batch);
[Link]();
}
}
We can use Kafka, RabbitMQ, etc. for high scalability. Pust the records into Queue and
let consumers process them in parallel.
Instead of fetching all 500,000 users into memory, always use pagination (Pageable in Spring
Data JPA) or Java Streams with @QueryHint(FETCH_SIZE) where supported.
Often memory leaks happen because objects stay referenced longer than needed (e.g., static
caches, thread locals).
Use WeakReference or SoftReference for caches where data can be reloaded instead of holding
strong references forever.
private Map<String, WeakReference<Product>> cache = new ConcurrentHashMap<>();
414
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Solution:
When two threads trying to update the same record in the database at the same time.
This creates a race condition. Sometimes one thread’s changes would overwrite the other’s,
leading to inconsistent data.
We need to use a technique called “Optimistic Locking.”
In Hibernate/JPA, this is simple to set up. We add a @Version field to the entity. Hibernate
automatically manages this field whenever an update happens.
How It Works
1. Each record has a version number (integer or timestamp).
2. When Thread A reads the record, it sees version = 1. Thread B gets the same version = 1.
3. Thread A updates the record, Hibernate increments version : 2.
4. Thread B tries to update based on version = 1. Hibernate detects mismatch (because DB
now has version = 2).
5. Thread B’s transaction fails with an OptimisticLockException.
6. Instead of silently losing data, we catch this exception and retry the operation with fresh
data.
Whenever we get OptimisticLockException, we can retry
Example:
@Entity
public class Product {
@Id
private Long id;
@Version
415
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Transactional
public void updateProduct(Long productId, String newName) {
boolean success = false;
int retries = 3;
416
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If we use on Spring WebFlux, WebClient is non-blocking and much more efficient for
massive N.
[Link](users)
.flatMap(user ->
[Link]()
.uri("[Link] [Link]())
.retrieve()
.bodyToMono([Link]),
100 // max 100 parallel calls
)
.collectList()
.block();
Here max concurrency is 100, means Only 100 calls will run at the same time. The remaining 900
will wait in the reactive pipeline queue.
3. Implement Authorization, means Apply role-based (RBAC) for access control. Example: Admin
can delete users; a normal user cannot.
4. Encrypt the sensitive data: For example, passwords must be encrypted before saving to DB.
Use BCryptPasswordEncoder
5. Transport Security (TLS): To protect data in transit, always use HTTPS instead of plain HTTP.
Redirect all HTTP traffic to HTTPS so no user accidentally connects over an insecure [Link]
Spring Boot, enable SSL in the application:
server:
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: yourpassword
key-store-type: PKCS12
417
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
This can happen when user input is inserted directly into SQL queries without any safety
checks. This allows an attacker to manipulate the query and run any SQL they want.
Example:
Let’s say we have written query like this to accept a username from Frontend and
return user details based on username
String username = [Link]("username");
String query = "SELECT * FROM users WHERE username = '" + username +"'";
Then the resulting SQL becomes, where attacker can delete users table
Common Causes
1. String concatenation in queries : building SQL using raw input.
2. No input validation : allowing unexpected characters like ', ;, --.
Prevention Techniques
a) Use Parameterized Queries / Prepared Statements
Always let the database handle user input safely.
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement ps = [Link](sql);
[Link](1, username);
[Link](2, password);
ResultSet rs = [Link]();
418
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Here, even if the user types '; DELETE FROM users; --, it is treated as a literal value, not
SQL code.
b) Use ORM Properly (JPA / Hibernate)
Avoid concatenating strings in queries. Use parameters:
@Query("SELECT u FROM User u WHERE [Link] = :email")
User findByEmail(@Param("email") String email);
The attacker looks for a web page where users can submit input, like a comment box,
without proper validation or escaping.
They write a small JavaScript snippet to do something harmful, like stealing cookies or
session info.
The attacker submits the script in the comment box. The backend stores it in the
database without cleaning it.
When other users visit the page and see the comment, their browsers automatically run
the attacker’s script, letting the attacker steal information or manipulate the page.
Causes of XSS:
No input validation
The app doesn’t check or clean what users type before showing it.
Example: allowing <script> in a comment.
No output escaping
Special characters like < and > aren’t converted, so the browser treats them as code
instead of plain text.
Using innerHTML unsafely
Setting innerHTML with raw user input can run scripts directly on the page.
Prevention
Input Validation
Always validate and escape all user input to ensure it is treated as text, not executable
code.
Sanitize Output
419
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws
Exception {
http
.headers(headers -> headers
// 1. Content Security Policy
.contentSecurityPolicy(csp ->
[Link]("default-src 'self'; script-src 'self'"))
// 2. XSS Protection
.xssProtection(xss -> [Link](true))
// 3. Clickjacking prevention
.frameOptions(frame -> [Link]())
);
return [Link]();
}
}
default-src 'self': only allow scripts from your own domain.
xssProtection(true): blocks some reflected XSS attacks.
frameOptions sameOrigin: prevents your pages from being loaded in a malicious iframe.
458 Spring Scenario 48: Best Practices while designing the REST API
When we design REST APIs, the first thing to keep in mind is clarity. Our endpoints should tell a
story. For example, if we want all users, use /users. If we want a specific user, use
/users/{id}. Avoid vague names like /getUserInfo.
Next comes HTTP methods. Use them for their true purpose. GET for fetching data, POST for
creating, PUT or PATCH for updating, and DELETE for removing. Don’t mix them up. A GET
request should never modify data.
Status codes are the language back to the client. If something is created successfully, say 201
Created, not just 200 OK. If input is wrong, return 400 Bad Request. These codes make
debugging and integration easier.
Now, validation. Never trust incoming data blindly. Use Spring’s validation annotations (@Valid,
@NotNull, etc.) to ensure the request is clean before processing it.
420
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
For error handling, don’t scatter try-catch blocks everywhere. Centralize them with
@ControllerAdvice. This way, clients get consistent error responses instead of random stack
traces.
Security is important. Use authentication (JWT, OAuth2, BasicAuth if simple), and always
validate who is accessing the endpoint. Also, never return sensitive details from the responses.
Finally, consider versioning. APIs evolve, and breaking old clients is a bad move. Start with
/api/v1/... and move to /api/v2/... when needed.
And one last thing, document the APIs. Whether it is Swagger or OpenAPI, make sure anyone
can understand and test the endpoints without guessing.
Entities
[Link]
@Entity
public class Department {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
[Link]
421
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Entity
public class Student {
@Id
@GeneratedValue(strategy = [Link])
private Long id;
In Department Entity, In @OnetoMany, we have used mappedBy, mappedBy tells “Don’t create a
separate join table or foreign key for this collection. The ownership is on the Student entity, look
at its department field for the actual mapping.”
On the Student side, we define @JoinCloumn which tells “In the students table, create a column
department_id and use it as a foreign key referencing the department table.”
This is how tables look like:
department Table
student Table
422
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation of Relationship
Each student has a department_id foreign key that links to the department table.
A department can have many students, but each student belongs to only one
department.
So, in DB terms:
department_id in student is a foreign key referencing department.department_id.
Start by clearly defining the problem and scope. Identify core entities and their
relationships.
Choose technologies for backend, frontend, database, cloud and include best
practices.
Design the APIs and clearly mention HTTP methods that are going to used.
Explain architecture layer by layer, including async processing if needed.
Cover scalability, reliability, CI/CD, logging and monitoring.
Optionally, mention extra features like real-time notifications or analytics,
Disaster recovery and failure alerts.
1. Backend (Server-side)
Framework: Spring Boot
Responsibilities:
o Manage Users, Restaurants, Menu Items, Orders, Delivery Agents.
o Business logic like calculating delivery ETA, order status updates, and payment
processing.
o Authentication & authorization for customers, restaurants, and admins.
Architecture:
o Controller > Service > Repository layers.
o DTOs for requests/responses.
Best Practices:
o Implement Pagination for restaurant listings.
o Have proper status codes for order creation, cancellation, etc.
o Handling Exceptions with @ControllerAdvice.
2. Frontend (Client-side)
423
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Framework: React or Angular for web; React Native or Flutter for mobile.
Responsibilities:
o Show restaurant menus, allow searching/filtering, place orders.
o Customer dashboard to track orders.
o Restaurant dashboard to manage menu and order queue.
Integration:
o Communicate with backend via REST APIs or GraphQL.
UX Considerations:
o Lazy loading restaurant images and menu items.
3. Database (Storage Layer)
Choice: SQL (PostgreSQL/MySQL)
Why SQL?
o Structured data: Users, Orders, Menu, Restaurants.
o ACID compliance for payments and order status.
o Relationships:
User > Orders (One-to-Many)
Restaurant > Menu Items (One-to-Many)
Order > Menu Items (Many-to-Many)
Optional NoSQL: MongoDB for storing analytics, logs, or user activity streams.
4. Cloud Deployment
Provider: AWS / GCP / Azure
Services:
o Backend: Spring Boot on Kubernetes / App Engine.
o Frontend: React hosted on Kubernetes.
o Database: Managed RDS (SQL) or Cloud SQL.
Benefits: Scalability, automatic backups, monitoring, and resilience.
5. Containerization
Docker for backend, frontend, and worker services (like sending notifications).
Kubernetes to manipulate multiple services and scale dynamically.
6. CI/CD Pipeline
Tools: GitHub Actions, Jenkins,
Pipeline:
1. Code pushed > run unit tests.
2. Build Docker images.
3. Push images to container registry.
424
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Scenario: Your API performance is degrading, and you want to know which method is slow.
Question: How can you capture execution time automatically?
Solution:
Spring AOP gives us a cleaner way: write the logic once, and apply it across multiple
methods using an aspect.
We need to use @Around, it defines an advice that executes both before and after a matched
method execution (join point)
@Aspect
@Component
public class ExecutionTimeAspect {
@Around("execution(* [Link]..*(..))")
public Object measureTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = [Link]();
return result;
}
}
425
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When we call [Link](), the aspect intercepts it, and we will get the output:
void [Link]() executed in 501ms
426
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When Spring sees @Transactional, it doesn’t change the method code directly. Instead, it creates
an AOP proxy around that bean. This proxy intercepts method calls, starts a transaction before
the actual method runs, and then decides what to do afterwards, means it commit if everything
goes fine, or roll back if an exception occurs.
So, we write plain business logic in the service methods, while the transactional concerns (begin,
commit, rollback) are handled transparently by the AOP proxy.
464 Spring Scenario 54: Validate Tenant for all service methods
Scenario: Every service method should validate a tenant ID for multi-tenant architecture.
Question: How do you enforce it without duplicating code in every method?
Solution:
If we add tenant checks manually in every service method, we end up duplicating code and
developers will forget it in some place. That is exactly the kind of cross-cutting concern AOP is
meant to solve.
Custom Annotation:
@Aspect
@Component
public class TenantValidationAspect {
@Before("within(@[Link] *)")
public void validateTenant() {
String tenantId = [Link](); //Read tenant from Context
427
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Around("@annotation([Link])")
public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
long start = [Link]();
return result;
}
}
466 Spring Scenario 56: Load huge data where pagination is not possible
Here we need all the data at once. And it takes multiple tables to join and fetch the data. how
you implement it and how will you reduce the latency?
Solution:
Backend aggregation
Don’t push raw massive datasets to the frontend. Instead, fetch and aggregate them on the
backend . Return the graph-ready format (series, categories, values).
Database level
Add proper indexes on join keys and filter columns.
Partition tables if data is huge (time-based partitioning is common).
Avoid SELECT *. Only fetch what we need for the graph.
Caching
428
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Unit Testing: Testing individual classes or methods in isolation. Example: testing a service
method that calculates discount.
Integration Testing: Testing how multiple components work together. Example: making sure the
Spring Service talks correctly to a Repository and database.
Functional/End-to-End Testing: Testing the actual flow from API layer to DB. Example: hitting a
REST endpoint and checking the full response.
Unit testing means testing a small piece of code (like one method) without external systems (DB,
network).
With JUnit 5 and Mockito (Mockito is a popular open-source mocking framework for Java used
in automated unit tests), a simple test looks like this:
//Service we want to test
public class CalculatorService {
public int add(int a, int b) {
return a + b;
}
}
//Test Class
import static [Link].*;
import [Link];
class CalculatorServiceTest {
private final CalculatorService calculator = new CalculatorService();
@Test
void testAdd() {
int result = [Link](2, 3);
assertEquals(5, result); // expected = 5
}
}
429
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Key points:
Use @Test annotation to mark test methods.
Assertions like assertEquals, assertTrue, etc., check the result.
For Spring components, we often mock dependencies using Mockito.
Integration testing checks how layers work together, like Controller > Service > Repository >
Database.
@Autowired
private MockMvc mockMvc;
@Test
void testGetUser() throws Exception {
[Link](get("/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"));
}
}
TDD: Test Driven Development is an iterative development process where tests for new
functionality are written before the actual code. The standard TDD cycle is often summarized as
“Red-Green-Refactor.”
1. Red: Write a failing test. This ensures that the test is valid.
3. Refactor: Optimize the code, ensuring that the test still passes after refactoring.
430
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Lifecycle includes:
@Test tells the JUnit framework that a particular method should be treated as a test and
executed when tests are run
In JUnit 4, @Test came from the [Link] package. Test methods had to be declared as public,
and if we wanted to check for an exception, we used a special syntax inside the annotation itself
@Test(expected = [Link])
public void shouldThrowException() {
// code that throws exception
}
JUnit 5 changed the experience by introducing a new architecture called Jupiter. The @Test
annotation moved to [Link], and we no longer had to make them public. Exception
handling became cleaner too, because instead of writing expected exceptions in the annotation,
we could simply use an assertion like assertThrows, which made the test more readable
@Test
void shouldThrowException() {
assertThrows([Link], () -> {
// code that throws exception
});
}
We usually begin with unit tests. These tests focus on individual classes, like a service
method or a utility function. They don’t load the full Spring context, and dependencies
are mocked.
431
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
REST APIs can be tested in two main ways. If we want to test only the controller , we use
@WebMvcTest, which loads just the web layer.
If we want to test the whole flow like controller, service, repository, and even database
then we use @SpringBootTest combined with MockMvc.
For database-specific testing, Spring Boot gives @DataJpaTest, which brings up an in-
memory database like H2 so that we can test the JPA repositories without touching a real
database.
8. How do you perform unit testing in Spring Boot?
Performing unit testing in Spring Boot usually involves JUnit 5 and Mockito. The idea is to
test only one class at a time while mocking out its dependencies.
@MockBean
private UserRepository userRepository;
@Autowired
private UserService userService;
@Test
void shouldReturnUserById() {
when([Link](1L)).thenReturn([Link](new User(1L,
"John")));
assertEquals("John", [Link]());
}
}
9. Which starter package do you need to test the spring boot application?
We simply add spring-boot-starter-test in the [Link], and we get access to all the
popular testing libraries without having to add them one by one.
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
432
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Integration testing in Spring Boot is all about verifying how different layers of the application
work together.
For example, suppose we have a UserController that talks to a UserService, which in turn talks to
a UserRepository. An integration test makes sure that the flow works correctly end to end. In
Spring Boot, the simplest way to do this is with @SpringBootTest. This annotation starts the
entire application context and allows us to send HTTP requests to the controllers using MockMvc
or TestRestTemplate.
MockMvc is used to simulate HTTP requests to a controller. It allows the test to send requests
such as GET or POST without starting a real web server. This means we can test API endpoints
while staying inside the test environment.
Example controller
@RestController
class UserController {
@Autowired
UserService userService;
@PostMapping("/users")
public String createUser() {
[Link]();
return "User created";
}
}
Test Example
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {
433
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Autowired
MockMvc mockMvc;
@Test
void testCreateUser() throws Exception {
[Link](post("/users"))
.andExpect(status().isOk());
}
}
When the test starts, Spring Boot loads the entire application context. The controller, service,
and repository beans are created.
}
In Spring Boot, we rarely need @ContextConfiguration directly because @SpringBootTest
usually handles context loading. However, we might still see it in cases where we want fine-
grained control over which beans are loaded, or if we are testing a very specific slice of the
application without starting the full Boot context.
13. What does @SpringBootTest do? How does it interact with @SpringBootApplication and
@SpringBootConfiguration?
When we annotate a test class with @SpringBootTest, we are telling Spring Boot to start
up the full application context, almost as if we run the application with @SpringBootApplication.
That means all the beans, properties, and auto-configurations are loaded.
434
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@ContextConfiguration belongs to the core Spring framework and is mainly used to load a
minimal or custom context, typically pointing to specific configuration classes. It doesn’t know
about Spring Boot’s auto-configuration or starters.
@SpringBootTest, on the other hand, is Boot related. It not only loads the application’s
configuration but also applies all the auto-configuration and Boot-specific features.
If we only want to test the controller layer in isolation, without loading services or
repositories, we use @WebMvcTest. This annotation creates a minimal context that includes
only the web components. Dependencies like services can be mocked with @MockBean.
@WebMvcTest([Link])
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void shouldReturnUserById() throws Exception {
when([Link](1L)).thenReturn(new User(1L, "John"));
[Link](get("/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"));
}
}
If we prefer to test the full flow, including database calls, then we use @SpringBootTest with
MockMvc or TestRestTemplate. This way we are not mocking the service or repository; instead,
we are checking if everything works together.
@SpringBootTest(webEnvironment = [Link].RANDOM_PORT)
class UserControllerFullStackTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void shouldReturnUserById() {
User user = [Link]("/users/1", [Link]);
assertEquals("John", [Link]());
}
435
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When we are testing REST controllers in Spring Boot, two annotations often come up:
@AutoConfigureMockMvc and @WebMvcTest. At first glance, they might look like they serve
the same purpose, but they actually live at different levels.
@WebMvcTest only work on Web layer like controllers, JSON converters, filters, and so on.
Nothing else is loaded. Services and repositories don’t exist in this slice unless we explicitly mock
them. This is perfect when the goal is to check whether a controller maps endpoints correctly,
validates input, or serializes output.
@WebMvcTest([Link])
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void shouldReturnUserById() throws Exception {
when([Link](1L)).thenReturn(new User(1L, "John"));
[Link](get("/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"));
}
}
Notice what happens here: the web context is bootstrapped, but UserService doesn’t exist until
we create a mock with @MockBean. That is because @WebMvcTest doesn’t load the service or
repository layer at all.
On the other side, @AutoConfigureMockMvc comes into play when we already using
@SpringBootTest. While @SpringBootTest starts the full application context (controllers,
services, repositories, database connections), adding @AutoConfigureMockMvc wires up the
MockMvc bean so that we can test our REST endpoints without starting a real HTTP server. In
other words, we are testing the controller in the context of the whole application.
Example:
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerIT {
@Autowired
private MockMvc mockMvc;
@Test
void shouldReturnUserFromDatabase() throws Exception {
[Link](get("/users/1"))
436
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"));
}
}
In this setup we don’t create fake services or repositories. The test uses the real database (often
an in-memory one like H2 or sometimes Testcontainers), runs the actual service code, and then
calls the controller.
Repositories in Spring are gateway to the database. They handle queries, inserts, updates, and
deletes. Testing them isn’t about mocking, because mocking defeats the purpose, we want to be
sure that the queries we write actually work against a real database.
The usual way is to use an in-memory database like H2 or a lightweight containerized database
(with Testcontainers). Spring Boot makes this super easy.
@DataJpaTest
class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
void shouldFindUserByEmail() {
User saved = [Link](new User("macha@[Link]"));
User found = [Link]("macha@[Link]");
assertThat([Link]()).isEqualTo([Link]());
}
}
Here, we didn’t spin up the whole application. Just the JPA part and an in-memory DB. This test
checks if the query method in the repository is actually returning what we expect.
We use @DataJpaTest for writing tests for repositories or JPA logic. It auto-configures everything
we need for JPA:
Scans only for @Entity classes and Spring Data JPA repositories.
So instead of loading the entire Spring context, You are just testing the persistence layer in
isolation. It is lightweight and fast.
437
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Services are where our business logic lives. Unlike repositories, here we don’t want a real
DB most of the time. Instead, we mock the repository layer and just test the logic.
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void shouldReturnUserWhenEmailExists() {
when([Link]("test@[Link]"))
.thenReturn(new User("test@[Link]"));
assertThat([Link]()).isEqualTo("test@[Link]");
}
}
Here, we don’t test how the repository works (that is tested elsewhere). we only test if the
service is working correctly or not.
Mockito is a Java testing framework that helps to create mocks. A mock is a fake object
that simulate the behaviour of real objects, so we can test our class without worrying about
dependencies.
Imagine the service depends on a repository. Instead of hitting the real DB, Mockito gives a fake
repository. We tell it how to behave (like “if someone calls findByEmail, return this dummy
user”). That way, we test only the logic in the service, not the repository itself.
When the code talks to the outside world like a payment gateway, weather API, or an
email service, we don’t want our tests to actually call them. That would be slow and might even
cost money. Instead
In Spring Boot, we usually wrap the external API in a service class (say, WeatherClient). Then in
your tests, we mock that client.
class WeatherServiceTest {
@Mock
private WeatherClient weatherClient;
@InjectMocks
private WeatherService weatherService;
438
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Test
void shouldReturnSunnyWeather() {
when([Link]("Hyderabad"))
.thenReturn("Sunny");
assertThat(result).isEqualTo("Sunny");
}
}
The actual HTTP call never happens. We just “pretend” the client gave a response. This keeps our
tests fast and focused only on how our code handles the response.
If we want to test the whole HTTP layer itself, we can also use tools like WireMock or
MockWebServer (These act like fake servers that the code hits during the test.)
The @Spy annotation in Mockito is used to create a spy instance of a real object. Spies
are useful to perform partial mocking, where some methods of the object are mocked while
others retain their original behavior. This is particularly useful when we want to test a class with
some real method calls and some mocked method calls.
Example:
@Spy
private Calculator calculator;
@Test
void spyExample() {
// Real add method will be called
assertThat([Link](2, 3)).isEqualTo(5);
assertThat([Link](2, 3)).isEqualTo(100);
}
}
439
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
23. What are the differences between @MockBean and @Mock annotations?
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService; // replaces bean in context
@Test
void shouldReturnUser() throws Exception {
when([Link]("test@[Link]"))
.thenReturn(new User("test@[Link]"));
[Link](get("/users/email/test@[Link]"))
.andExpect(status().isOk());
}
}
@MockBean tells Spring: “Don’t load the real UserService, use this fake one instead.”
If we use @Mock, the Spring context won’t know about it, and the test would fail because the
controller still expects a bean.
Whenever the Spring-managed class depends on another bean, and we don’t want the real one,
we just replace it with @MockBean.
When we start writing tests with Mockito, these two annotations often sit next to each
other. At first, they look similar, but they actually serve two very different purposes.
class OrderService {
private final PaymentService paymentService;
440
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Now, suppose we want to test OrderService. You don’t really care about whether money is
transferred , we just want to check that OrderService behaves correctly when the payment goes
through. This is where @Mock and @InjectMocks come in.
@Mock: When we put @Mock on a class, Mockito creates a fake version of it. None of the real
logic runs unless we tell it to. Instead, we control its behaviour in the test.
@Mock
private PaymentService paymentService;
@InjectMocks: Now comes @InjectMocks. This tells Mockito: “Create the real object of this
class, but if it has dependencies, inject the mocks into it.”
@InjectMocks
private OrderService orderService;
Mockito sees that OrderService needs a PaymentService, and since we already created a mock
of it, it wires the fake into the real OrderService.
Complete sample:
class OrderServiceTest {
@Mock
private PaymentService paymentService; // fake dependency
@InjectMocks
private OrderService orderService; // real class, mock injected
@Test
void shouldReturnApprovedWhenPaymentSucceeds() {
when([Link]()).thenReturn("Approved");
assertThat(result).isEqualTo("Approved");
In this test, OrderService is real, but the PaymentService inside it is fake. That is exactly what we
want in a unit test: test one class in isolation, while replacing its dependecies with mocks.
441
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Use @Mock whenever we want to create a fake version of a class and fully control its
behaviour in tests. We don’t want the real logic at all.
Use @InjectMocks when we are testing a class that has dependencies. It creates the real
object and injects the mocks automatically, so we don’t need to manually set up the
class.
In a Spring Boot project, we normally write tests using JUnit. JUnit runs the test methods, but it
does not know anything about Spring.
Generally, to perform the integration test, we use @SpringBootTest. It loads the Spring
application context while running the test.
The application context is the place where Spring creates all beans such as services, repositories,
controllers, and configurations.
First it scans the project and finds the main Spring Boot configuration class.
Then it creates all beans that are normally created when the application runs.
After that the test class gets access to those beans.
Because of this, the test behaves almost like the real application.
@SpringBootTest
class UserServiceTest {
@Autowired
UserService userService;
@Test
void testCreateUser() {
[Link]();
}
}
In this example Spring Boot loads the application context and creates the UserService bean.
The test then calls the service method.
When @SpringBootTest loads the application context, Spring creates all beans. After creating the
beans, Spring injects them into the test class wherever @Autowired is used.
Example
@SpringBootTest
442
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class OrderServiceTest {
@Autowired
OrderService orderService;
@Test
void testOrderCreation() {
[Link]();
}
}
In this example Spring creates the OrderService bean while starting the application context.
The same bean is then injected into the test class using @Autowired.
Because the real application context is used, the injected object is the real service, not a fake
object.
Example
@SpringBootTest
class OrderServiceTest {
@MockBean
OrderRepository orderRepository;
@Autowired
OrderService orderService;
}
Here Spring replaces the real repository with a mock object. But the service remains a real bean.
In BDD, instead of writing tests directly in Java, we first describe the behavior of the system using
feature files.
These files use simple sentences that explain what the system should do.
443
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
In many Spring Boot applications, the step definition classes need to use Spring components
such as services or repositories.
For example, a login step may need to call a LoginService. However, Cucumber by itself does not
start the Spring environment. Without Spring, beans like services or repositories cannot be
injected.
This annotation belongs to Spring Boot and it loads the Spring application context while the
tests run.
This configuration tells Spring Boot to start the application context before executing the
Cucumber scenarios. Once the context is started, Spring creates all the beans that normally exist
when the application runs.
After the application context is loaded, step definition classes can use Spring features such as
dependency injection.
@Autowired
LoginService loginService;
When the scenario runs, the step method calls the real service method. This means the test is
interacting with the real application logic.
So, the testing style is BDD, but the test behaves like an integration test because real
components are used together.
In unit testing we often use Mockito to replace real objects with test objects. Two
commonly used annotations in Mockito are @Mock and @Spy.
444
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The real logic inside the class will not run. Instead, we define the behavior manually using
Mockito.
This is useful when a class depends on another component such as a repository, an external API,
or a service.
We replace that dependency with a mock so that the test focuses only on the class we want to
test.
class PaymentTest {
@Mock
PaymentService paymentService;
@Test
void testPayment() {
[Link]();
}
}
Here paymentService is not a real object. Mockito creates a mock version of it. If we call
process(), nothing inside the real method runs unless we define behavior using when().
@Spy
@Spy
Calculator calculator;
@Test
void testAdd() {
int result = [Link](2,3);
[Link](result);
}
}
445
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Here the add method runs normally because the object is real. If needed, Mockito can override
specific methods.
Overriding a Method
Now suppose we want to change the behavior of the add() method during the test. We override
it using Mockito.
@Test
void testAdd() {
doReturn(100).when(calculator).add(2,3);
[Link](result);
}
Given int[] arr = {2, 5, 6, 4, 1, 3, 10, 8, 7}; Second largest is 8 and second smallest is 2
Code link: [Link]
Fullstack/Arrays/edit/main/[Link]
3. Find the repeating elements / duplicates from an array
Given int[] arr = { 2, 5, 6, 2, 1, 3, 1, 8, 3 }; In this array {2,1,3} are duplicates
Write a function that should return {2,1,3}
Code link: [Link]
446
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Given int arr[] = {9, 8, 4, 9, 5, 4, 9, 1}. Here 9 repeated 3 times and 4 repeated 2 times
etc. Expected output: {1=1, 4=2, 5=1, 8=1, 9=3}
Code Link: Arrays/[Link] at main · CodingLyf-Fullstack/Arrays
6. Find all non-repeating or unique elements in an array.
Given int[] arr = {4, 5, 2, 4,, 2, 1}; 5 and 1 and not repeated.
Excpected output : {5,1}.
A leader in an array is an element that is greater than all the elements to its right.
The rightmost element is always a leader because there are no elements to its right.
You need to check each element and see if it is bigger than all the elements that come
after it in the array.
Input [16, 17, 4, 3, 5, 2] and the leaders are [2,5,17]
Code link: [Link]
447
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
448
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
449
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Given an integer array nums and an integer k, return the k most frequent elements. You
may return the answer in any order.
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
Code link: Arrays/[Link] at main · CodingLyf-Fullstack/Arrays
20. Check if a Pair with Given Sum Exists in Array ( Two Sum Problem )
You are given an array of integers and a target sum. You need to check if there exists any
pair of numbers in the array whose sum is equal to the target.
Input: arr = [8, 4, 1, 6], target = 10
Output: true because there is pair 4 and 6 whose sum is 10
Code Link: Arrays/[Link] at main · CodingLyf-Fullstack/Arrays
Additional Question: Same question can be asked to the pair instead of true/false.
Hint: return new int[]{[Link](complement), i};
Note: we can also solve with two pointer technique, but we need to sort arrray (Refer Question
21)
450
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore, its length is 4.
Code link: Arrays/[Link] at main · CodingLyf-Fullstack/Arrays
24. Create a function that takes input as 7 and returns 11. if we give input 11, it should return 7.
Don’t use if-else conditions.
public class Main {
[Link](toggle(7));
[Link](toggle(11));
}
Characters: s, i, l, e, n, t
All are different return true
Input: "hello"
Characters: h, e, l, l, o
l repeats return false
Code Link: Strings/[Link] at main · CodingLyf-Fullstack/Strings
452
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Input: s = "bcabc"
Output: “bca"
Code Link: Strings/[Link] at main · CodingLyf-Fullstack/Strings
12: Remove characters from first string that are present in the second string
You are given two strings:
First string: the base string
Second string: contains characters that need to be removed from the first string
First string = "computer"
Second string = "cat"
Remove ‘c’ and ‘t’ from first String
Code link: Strings/[Link] at main · CodingLyf-Fullstack/Strings
13. Implement a method to compare two Strings for equality (don’t use .equals)
Code Link: Strings/[Link] at main · CodingLyf-Fullstack/Strings
14. Isogram
An isogram is a word or phrase where no letter repeats. Every character appears only once.
Example 1:
Word: machine
Letters: m, a, c, h, i, n, e
453
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
15. Replace all instances of a Substring with another sub string. – Sliding Window
String input = "abc123abc456abc";
String target = "abc";
String replacement = "XYZ";
Then all the “abc” should be replaced with “XYZ”
Code Link: Strings/[Link] at main · CodingLyf-Fullstack/Strings
18. Count the number of times one string occurs in another - Sliding Window
Given two strings, s1 (the pattern) and s2 (the text), count how many times s1 occurs
contiguously in s2.
Contiguously means the characters of s1 appear together in order, without any gaps.
Example 1:
s1 = "abc"; s2 = "abcabcabc"; Output: 3
Explanation:
"abc" appears starting at index 0, 3, and 6.
Total occurrences = 3
454
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Example 2:
s1 = "xyz"; s2 = "xyabcz"; Output: 0
Explanation:
" xyz" is not there “xyabcz”.
Code Link: Strings/[Link] at main · CodingLyf-Fullstack/Strings
19. Find the longest substring without repeating the characters – Siding Window
Given a string s, find the length of the longest substring and substring without duplicate
characters.
Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.
Code Link: Strings/[Link] at main · CodingLyf-Fullstack/Strings
455
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Additional questions:
26. Write a program to sort characters in a string - Use any sorting technique like Bubble sort
456
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
27. Write a program to find a substring within a string. If found display its starting position -
Sliding Window ()
Hint: Refer question 18. Write a function and instead of incrementing the count. return i
and break the loop.
if(i == [Link]) > index not found
else index found at i
28. Change case of each character in a string
29. String Palindrome
30. Reverse the String
2. What is spring version you are using, what are major issues you have seen when updated from
2.x to 3.x
3. What are the third-party libraries you have used in your project?
7. What if your product owner expecting a task in 1 sprint but it takes 2 sprints? how would you
convey this?
10. How would you debug the priority issue from the Prod?
12. What is the Java version you are using in your project? - Prepare the features of the version
you are using
13. What is the Spring version you are using in your project? - Prepare the features of the version
you are using
16. What are the design patterns you have used in your project?
457
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
18. How build automation works in your project? Using Jenkins or GitHub actions?
19. How do you start working on some tasks after it was assigned to you?
20. How security is implemented and what checks you do in your project?
24. How will you ensure compatibility when upgrading the dependencies?
25. What are the testing tools you used in your project?
26. You started working on a task but after couple days new requirements are been added. How
would you make sure to complete within the Sprint?
29. If you were assigned a task, how you proceed it, right from story points to hand over it to QA.
30. How do you make sure all the acceptance criteria are working fine.
31. How do you handle a situation where it takes 2 sprints but product owner is expecting to be
finished in 1 sprint?
458
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
OOP Concepts
Strings
Collections
Exception Handling
459
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Spring Core
Spring Boot
REST
OOPs
23. What are Sealed Classes (Java 17)? Why are they introduced?
24. Shallow copy vs Deep copy , when do you need each?
25. How does cloning work (Cloneable)? Why is it tricky?
26. Stack vs Heap memory , what goes where?
27. What is Garbage Collection? Can you explain different types of GCs (briefly)?
28. How do you handle OutOfMemoryError in production?
Multithreading & Concurrency Basics
29. What is the role of synchronized keyword?
30. Thread-local variables, where do they help in real-world projects?
461
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Spring Core
Spring Boot
49. How does auto-configuration in Spring Boot work?
50. What is @Configuration vs @Bean?
51. How do profiles work in Spring Boot (@Profile use case)?
52. How do you handle global exception handling in Spring Boot (@ControllerAdvice)?
53. [Link] vs [Link] , when to prefer which?
54. What is the use of CommandLineRunner or ApplicationRunner?
55. What happens if two beans of the same type are created? How do @Qualifier and
@Primary help?
56. How does the embedded Tomcat server work in Spring Boot?
REST API
57. Difference between @RequestMapping and @GetMapping.
58. @PathVariable vs @RequestParam.
59. How do you validate request inputs in Spring Boot REST APIs?
60. How would you secure a REST endpoint?
61. How do you handle exceptions in REST APIs and return proper status codes?
62. Difference between @RequestBody and @ResponseBody.
63. How to implement global exception handling in REST?
64. How do you secure REST APIs with Spring Security?
65. What are Spring Boot Actuator endpoints?
66. How do you enable pagination and sorting in Spring Data REST?
Database & JPA
67. What is ORM and why do we use it?
68. What is JPA vs Hibernate?
462
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
463
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
21. Explain the Spring bean lifecycle. How can you hook into it?
22. What are proxies in Spring (JDK vs CGLIB)? Where do they matter?
23. How do you inject a prototype bean into a singleton?
24. How does Spring Boot Actuator help in production monitoring?
25. How would you build a custom health check endpoint?
26. What is @ConditionalOnProperty, and where have you used it?
27. How do you implement custom metrics & monitoring with Micrometer/Prometheus?
28. What are Scopes in Spring? How do they affect microservices apps?
29. How does Spring Boot auto-configuration work internally?
30. How does Spring handle circular dependencies?
31. Explain difference between JDK dynamic proxies and CGLIB proxies.
32. How would you profile and optimize a Spring application?
33. How do you implement distributed caching in Spring (Redis/Hazelcast)?
34. How does @Transactional work under the hood with proxies?
464
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Type Casting: Widening (automatic, safe: int to long), Narrowing (manual, may lose
data: double to int).
Keywords: Reserved words like final, static, this, super, transient, volatile, synchronized.
2. Object-Oriented Programming (OOP)
Classes & Objects: Class = blueprint with fields + methods, Object = runtime instance of
the class.
Constructors: Used to initialize objects; can be overloaded; if none defined, Java
provides a default.
Inheritance: extends lets child reuse parent behaviour. Single inheritance for classes,
multiple inheritance via interfaces.
Polymorphism: Overloading = same method name with different signatures; Overriding
= subclass redefines parent method (runtime dispatch).
Encapsulation: Hide variables with private and expose via getters/setters. Helps
maintain control & validation.
Abstraction: Abstract classes (partial abstraction) and Interfaces (full abstraction till Java
7; default methods allow behaviour from Java 8).
this & super: this: reference current object, super: call parent’s methods/constructors.
final: Used to create constants, prevent inheritance, prevent method overriding.
static: Belongs to class, not object. Used for utility methods, static blocks, static nested
classes.
3. Core Concepts
Methods: Modularize code; have parameters, return types, and may throw exceptions.
Overloading & Overriding: Overloading = compile-time resolution; Overriding = runtime
resolution (polymorphism).
Arrays: Fixed-length container for same-type elements; multi-dimensional arrays for
matrices.
Strings: Immutable (String), mutable alternatives are StringBuilder (not thread-safe, fast)
and StringBuffer (thread-safe).
Wrapper Classes: Provide object representation of primitives (useful for collections,
autoboxing/unboxing).
Enums: Represent constant sets with methods and fields (can have constructors too).
4. Collections Framework
List: Ordered, duplicates allowed (ArrayList = dynamic array, LinkedList = doubly linked).
Set: No duplicates (HashSet = unordered, LinkedHashSet = insertion order, TreeSet =
sorted).
Map: Key-value pairs (HashMap = unordered, LinkedHashMap = ordered, TreeMap =
sorted keys).
Queue/Deque: FIFO (Queue), double-ended (Deque, e.g., ArrayDeque). PriorityQueue
orders by comparator.
466
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
467
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Stack vs Heap: Stack = method calls, local vars; Heap = object instances, GC-managed.
Garbage Collection: JVM automatically reclaims memory. Different algorithms: Serial,
Parallel, G1, ZGC.
Memory Leaks: Commonly due to unclosed streams, static collections holding
references.
JVM Tuning: Configure heap size (-Xmx), GC behavior, thread stack size for optimization.
10. Java 8+ Features
Lambdas: Concise anonymous functions (x -> x*x).
Functional Interfaces: Interfaces with one abstract method (Supplier, Consumer,
Predicate).
Streams: Declarative style for processing collections with intermediate ops (map, filter)
and terminal ops (collect, reduce).
Optional: Container to avoid NullPointerException (orElse, ifPresent).
Default & Static Methods in Interfaces: Provide implementations in interfaces without
breaking old code.
New Date/Time API: Immutable, thread-safe API (LocalDate, Period, ZonedDateTime).
11. Advanced
Generics: Add type safety (List<String> vs List<Object>). Avoids casting errors.
Annotations: Metadata used at compile or runtime (@Override, custom annotations,
@Retention).
Reflection API: Inspect and modify classes, fields, methods dynamically (used in
frameworks).
JDBC: API for DB connectivity using SQL queries (Connection, PreparedStatement,
ResultSet).
JPA/Hibernate: Object Relational Mapping (ORM) to simplify DB interaction via entities.
Spring Integration: Use with Java for dependency injection, AOP, REST APIs,
microservices.
12. Testing in Java
JUnit (annotations: @Test, @BeforeEach, @AfterEach, @BeforeAll, @AfterAll)
Mockito: mocks, spies, stubbing
TestContainers (integration testing with DBs.)
13. Performance & Best Practices
StringBuilder vs String concatenation
Use primitives when possible
Object pooling (where needed)
Avoid unnecessary synchronization
Caching results (Memoization)
468
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
469
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
470
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Transactions:
o @Transactional.
o Propagation: REQUIRED, REQUIRES_NEW, MANDATORY, etc.
o Isolation: READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE.
Lazy vs Eager Loading
o Default to [Link].
o Avoid [Link] (leads to N+1 problems and large queries).
N+1 Query Problem
o Use JOIN FETCH in JPQL or @EntityGraph to pre-fetch relationships when
needed.
2nd Level Cache (L2 Cache)
o Enable Hibernate L2 cache with Ehcache/Redis.
o Cache static reference data.
Query Cache
o Enable query caching for repeated queries.
o Use carefully.
Batch Inserts/Updates
o Group writes using Hibernate batching.
Avoid Select
o Explicitly fetch only needed columns.
471
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
8. Web Security
CSRF Protection
o Enabled by default in Spring Security (CsrfFilter)
o Use CSRF tokens in forms (<input type="hidden" name="_csrf">)
o Disable only for stateless APIs with JWT
XSS Protection
o Escape output in views (Thymeleaf auto-escapes by default)
472
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
9. Testing
Test Annotations:
o @SpringBootTest: full context.
o @WebMvcTest: controllers only.
o @DataJpaTest: JPA only.
Mocking:
o @MockBean, Mockito.
o MockMvc for REST testing.
Database Tests:
o @AutoConfigureTestDatabase, H2 in-memory DB.
[Link] & Interceptors
Servlet Filters ([Link] / OncePerRequestFilter)
o Run before request reaches DispatcherServlet
o Used for logging, authentication, CORS, request wrapping
Spring Interceptors (HandlerInterceptor)
o Run before and after controller execution
o Good for auditing, request validation, modifying model attributes
Difference:
o Filters: generic to all requests (Servlet level)
o Interceptors: Tied to Spring MVC request lifecycle, Tied to controllers
473
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
474
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
17. Performance
Startup Optimization
Lazy Init: [Link]-initialization=true
Limit @ComponentScan scope
Remove unused starters/dependencies
Analyze startup with Spring Boot Startup Actuator
Runtime Performance Optimization
Switch to WebClient (reactive, non-blocking) instead of RestTemplate
Connection pooling: HikariCP (tune max pool size)
Cache: Spring Cache (Redis, Caffeine)
Asynchronous processing: @Async, Kafka, queues
Batch inserts/updates: JPA batching, bulk APIs
Database Performance
Use proper indexes (single, composite, covering indexes)
Optimize queries with JPQL/Criteria instead of fetching everything
Fetch strategies: prefer lazy loading but balance with JOIN FETCH where needed
Pagination with Pageable to avoid loading huge datasets
Avoid N+1 problem: use @EntityGraph, JOIN FETCH, or DTO projections
Statement batching in JPA ([Link].batch_size)
Connection pool tuning (HikariCP settings)
Use database-specific features (partitions, materialized views, query hints)
API Performance Optimization
Compression: Enable GZIP ([Link]=true in Spring Boot)
Response Size : Use pagination (Pageable, Slice), projections, and DTOs to avoid over-
fetching
Caching Strategies
o Client-side: Cache-Control, ETag, Last-Modified headers
o Server-side: Spring Cache (Redis, Caffeine), HTTP response caching
Connection Keep-Alive: Reduce handshake overhead
Rate Limiting / Throttling: Bucket4j, Resilience4j
Asynchronous APIs: WebFlux, @Async, message queues (Kafka/RabbitMQ)
476 November
[Link] between JVM vs JRE vs JDK
475
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
JVM is the heart of Java. When we write Java code, it does not directly run on our computer’s
operating system. Instead, it runs inside the JVM.
JVM reads the .class file (which has bytecode) and converts it into machine code that our
computer can understand.
This is what makes Java platform independent, the same Java code can run on Windows, Mac,
or Linux, as long as a JVM is installed.
JRE provides everything that JVM needs to run a program. It has the JVM, plus libraries and
other files required during execution.
If the JVM is the engine, the JRE is the car that holds the engine and the fuel. We use JRE when
we only want to run Java programs, not write them.
JDK is the complete package for developing Java applications. It includes the JRE, the JVM, and
also tools to write, compile, and debug Java code, like the javac compiler.
Example:
1. We write a program: [Link]
2. JDK compiler (javac) compiles it into bytecode: [Link]
3. JVM runs that bytecode inside the JRE.
476
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
In Java, Throwable is the parent class for everything that can be thrown as an error or
exception during program execution. It has two main types: Exception and Error.
Exception represents problems that can be handled, like dividing by zero or accessing a file that
does not exist.
Error represents serious problems that usually cannot be fixed, like running out of memory.
try {
int a = 5 / 0;
} catch (Exception e) {
[Link](e);
}
Here, Exception is a type of Throwable that the program catches and handles.
If no access modifier is specified in Java, the default access level is called package-private.
It means the class, method, or variable is accessible only within the same package. It cannot be
used by classes from a different package.
Example:
class MyClass {
void showMessage() {
[Link]("Hello");
}
}
Here, both MyClass and showMessage() have default access.
They can be used by other classes inside the same package but not from outside packages.
String test() {
return "";
}
Explanation:
No, it will not compile. Both methods have the same name and same parameters, but only
return type is different.
In Java, method overloading requires a either different number of parameters or different type
of parameters, not just the return type.
477
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
No, this code will not work if we try to serialize the Student object.
Since File does not implement Serializable, Java will throw a NotSerializableException at runtime
when we attempt to serialize it.
Point to remember:
If a Serializable class has a member that is not serializable, the program will throw a
NotSerializableException at runtime when we try to serialize that object.
This happens because every member inside a Serializable class must also be serializable.
To fix this, we can mark that non-serializable member as transient. This tells Java to skip that
field during serialization.
Fix:
class Student implements Serializable {
transient File file; // not serialized
}
The diamond operator (<>) in Java helps write cleaner code when working with generics.
It was introduced in Java 7 to remove the need for repeating type information on both sides of
an assignment.
Here, we use <> instead of writing new ArrayList<String>(). The compiler automatically
understands that this list stores String values.
7. What are static imports and any example from Java SDK?
Static import in Java allows us to use static members of a class directly without writing
the class name every time. It helps make the code shorter, cleaner, and easier to read when the
same static methods or constants are used often.
import static [Link].*;
class Test {
void show() {
[Link](sqrt(16)); // instead of [Link](16)
[Link](max(10, 20)); // instead of [Link](10, 20)
}
}
Here, we use static import from the Math class. Without static import, we would have to write
[Link] and [Link]. It is useful when we call many static methods or constants repeatedly
in our program.
8. Java Scenario 51
478
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
while (hasMoreBatches()) {
[Link](); // reuse the same list
[Link](fetchNextBatch()); // add around 1000 records
process(records); // process the data
}
Question: How can we decide the right initial capacity for an ArrayList in this case?
Explanation:
When an ArrayList grows, it keeps creating new internal arrays as elements are added,
which costs memory and time. It is better to set an initial capacity close to the average number
of elements it usually holds.
List<String> names = new ArrayList<>(100);
If the list generally stores around 100 items, this avoids repeated resizing. It improves
performance when the same list is used many times.
Follow-up question:
If we create an ArrayList without specifying an initial capacity, it starts with a default capacity of
10.
Now, when we keep adding elements:
Once it reaches 10, it resizes to make room.
Then again at 15, 22, 33, and so on (roughly 1.5 times each time).
By the time we add 1000 items, it will have resized many times internally.
Each resize creates a new array, copies all existing elements to it, and discards the old one.
The list will still work and hold 1000 items, but it will perform much slower compared to a list
created with an initial capacity of 1000.
9. Spring Scenario 57
How can we migrate an existing Spring Boot application to a new database schema without
any downtime?
When an application is running in production, stopping it even for a few minutes can
cause problems for users. So, when we move to a new database schema, the goal is to make the
change while the application is still live.
To achieve this safely, we need a clear plan.
1. Plan the schema changes
Start by listing what needs to change in the database. For example, adding a new
column, renaming a table, or changing a data type.
479
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Timeout errors in Spring applications can arise from various sources, including long-
running operations, network issues, or misconfigured timeout settings. Addressing these errors
involves identifying the source and implementing appropriate solutions.
Spring MVC Async Request Timeout: For asynchronous requests in Spring MVC, configure
the [Link]-timeout property in [Link] or [Link]. This
sets the maximum time a request can take before being terminated.
480
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout([Link](5)) // Connection timeout
.setReadTimeout([Link](10)) // Read timeout
.build();
}
Asynchronous Processing:
For tasks that are inherently long-running, consider using asynchronous processing
with CompletableFuture, @Async, or message queues to offload the work and prevent blocking
the main request thread.
Caching:
Implement caching strategies to store frequently accessed data and reduce the need for
repeated expensive operations.
Database Query Optimization:
Optimize slow database queries by adding indexes, rewriting queries, or adjusting database
configurations.
477 December
1 (Output-Based 70). Guess the output?
public class FinallyBlockTest {
public static void main(String[] args) {
try {
[Link]("Inside try block");
[Link](0);
} catch (Exception e) {
[Link]("Inside catch block");
} finally {
[Link]("Inside finally block");
}
[Link]("Outside try-catch-finally block");
}
}
Output: Inside try block
Explanation: The call to [Link](0) causes the JVM to terminate immediately, so
the finally block is not executed, and the program terminates without printing "Inside finally
block" or "Outside try-catch-finally block".
481
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]();
[Link](s);
}
}
Output: abc
Explanation: Strings are immutable in Java. The toUpperCase method returns a new string, but
it does not modify the original string.
{
[Link]("2");
}
public A() {
[Link]("3");
}
}
Output: 12323
Explanation:
In Class A, we have three things: a static block, an instance block, and a constructor.
The static block runs only once when the class is loaded into memory. Even if we create
ten objects, this block does not run again.
The instance block runs every time we create an object, and it runs before the
constructor. This block is usually used for common code that should run for all objects.
The constructor runs after the instance block and is used to set values and prepare the
object.
The static block prints 1 only once when the class loads.
Every object prints 2 from the instance block and 3 from the constructor.
Here, two objects are created, so we get 2 and 3, two times after the initial 1.
482
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Both Serializable and Externalizable help in saving an object's state into a file or sending
it across a network. The idea looks same, but the control we get is different
Serializable is a marker interface. It does not have any methods. Once a class implements it, Java
automatically takes care of reading and writing object data. We get no control over which fields
are stored and how they are written.
Key Points
Java handles everything behind the scenes
Easy to use, less code
Slower when compared to Externalizable because Java decides what to store
Transient fields are not saved
import [Link].*;
[Link]([Link]); // 101
[Link]([Link]); // Ravi
[Link]([Link]); // null
}
}
Externalizable extends Serializable but gives full control over the serialization process. The class
must implement two methods:
writeExternal(ObjectOutput out)
readExternal(ObjectInput in)
We decide what fields to write and in which format. Nothing happens automatically.
Key Points
We control what to save and how to save
483
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
import [Link].*;
public Employee() {
// mandatory zero-arg constructor
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
[Link](id);
[Link](name);
// password intentionally not written
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
id = [Link]();
name = [Link]();
// password is not read, so it becomes null
}
[Link]([Link]); // 201
[Link]([Link]); // Kiran
[Link]([Link]); // null
}
}
484
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class Counter {
AtomicInteger count = new AtomicInteger(0);
void increment() {
[Link](); // atomic
}
int getValue() {
return [Link]();
}
[Link]();
[Link]();
[Link]();
[Link]();
485
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
findFirst() always returns the first element in the stream. The order matters here. If the stream
has an order, findFirst() gives it every time.
import [Link];
.boxed()
.findAny()
.get();
[Link](num);
// could be 10, 20, 30, 40, 50, 60, 70, 80, 90, or 100
}
[Link](1) pauses the current thread for one millisecond.
This delay makes each thread finish its work at different times.
Because threads complete unevenly, the first available result changes frequently.
This helps show the true nature of findAny(), where any matching element can be
returned.
Without the sleep, threads finish too quickly and often pick the same element, looking
the output look fixed.
[Link] the use of Collectors in Java 8?
Streams help in processing data, but after working on them we often need the result in some
form, like a list, a set, a map, or a single value. This is where the Collectors class comes in. It
provides ready-made methods that help collect the output of a stream into a final result.
The idea is simple. We perform operations on a stream and then use a collector to gather the
result.
Why Collectors are useful
486
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Useful Collectors
Collect to a Set
Set<Integer> set = [Link](10, 20, 30, 20)
.collect([Link]());
[Link](set); // [10, 20, 30]
Count elements
long count = [Link]("apple", "orange", "banana")
.collect([Link]());
[Link](count); // 3
Join strings
String result = [Link]("Java", "Streams")
.collect([Link](" "));
[Link](result); // Java Streams
Grouping example
import [Link].*;
import [Link].*;
487
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
8. when you have [Link] and [Link]. and it contains same key and
value. Which one spring consider?
If a property appears in both [Link] and [Link], the value from
[Link] wins (it overrides the same key from [Link]).
Because of this behavior, it is generally recommended to use only one format in a
project. Mixing both may lead to confusion.
[Link] the difference between git clone, git pull and git fetch?
git clone is used when we work on a project for the first time. It creates a full copy of the remote
repository on our system, including all history and branches.
git fetch downloads the latest changes from remote but does not apply them to our branch. Our
current code stays the same.
git pull first fetches the changes and then merges them into our current branch. This updates
our local code.
488
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
4. How do you merge code from main branch to your feature branch
While working on a feature, the main branch keeps changing. To stay updated, we bring main
branch changes into our feature branch.
First, we switch to our feature branch. Then we get the latest main branch changes from remote.
We can merge main into our branch. This keeps both histories and creates a merge commit.
git fetch origin
git merge origin/main
Or we can rebase our branch on top of main. Rebase rewrites your commits on top of main so
the history looks cleaner and linear. Merge just brings them in as a commit.
git fetch origin
git rebase origin/main
7. Scenario: A bug was fixed on a hotfix branch. You want that fix on both main and your feature
branch without merging the entire hotfix branch. How you do it?s
We use cherry pick with the commit id. Git applies only that commit to our current branch.
git checkout feature
git cherry-pick <commit-id>
8. Scenario: A new commit is pushed to the repository and the application build starts failing,
how do you handle this?
First, check the build logs to understand where the failure is happening. If needed, use
Git history or tools like git bisect to find the exact commit that introduced the issue
490
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
To quickly stabilize the project, undo the wrong commit using git revert so the build becomes
green again. After that, work together to correct the issue, test the fix properly, and push the
updated commit.
9. Scenario: A developer commits some changes locally, but later realizes the commit was a
mistake. The code is wrong, incomplete, or added to the wrong branch. The commit has not
been pushed to the remote repository yet.
Since the commit exists only in the local branch, we can safely remove it.
We use git reset --hard HEAD~1 to move the branch pointer one commit back and discard the
last commit completely. This also removes the related file changes from the working directory.
10. Difference between git reset –hard and git reset –soft?
Both commands move the branch pointer to a previous commit, but they handle code changes
very differently.
git reset –soft
This command removes the commit but keeps all the changes.
The code changes stay in the staging area.
It is useful when a commit message is wrong or when we want to modify the commit
without losing work.
After a soft reset, we can recommit with a better message or add more changes.
git reset –hard
This command removes the commit and also removes all related code changes.
The working directory and staging area are cleaned completely.
It is used when the last commit is totally wrong and we do not need the changes
anymore.
This should be used only for local commits, because the changes are permanently lost.
Reference: (17) Mastering Git: Commands, Workflows, and Real-Life Scenarios | LinkedIn
491
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
putIfAbsent() takes the value directly. If the key exists (even if mapped to null), it won't
be added, and the existing value is returned.
This method is ideal when you have the value ready and simply want to avoid
overwrites.
Map<String, Integer> map = new HashMap<>();
[Link]("apple", 10);
[Link]("apple", 20);
[Link]([Link]("apple"));
First line adds apple = 10.
Second line tries to add apple = 20.
But apple already exists, so nothing changes.
computeIfAbsent(key, mappingFunction):
key: The key you want to check for existence.
mappingFunction: A function that computes the value if the key is absent. This function
receives no arguments and returns the value to be added.
Key Points:
computeIfAbsent() provides more flexibility. If the key is missing, the mappingFunction is
called to calculate the value, which is then added to the map.
This method is perfect when you need to create the value on the fly based on the key.
Map<String, List<String>> map = new HashMap<>();
[Link](map);
492
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
int roll;
}
TreeMap<Student, String> map = new TreeMap<>();
At this point, TreeMap is confused. It does not know how to compare two Student objects
So, we need to provide the rules
Option 1: Make the class Comparable.
class Student implements Comparable<Student> {
int roll;
public int compareTo(Student s) {
return [Link] - [Link];
}
}
493
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The hash of Person depends on its fields. When name changes, the hash also changes. But
HashMap already stored the value using the old hash.
Now when we try: [Link](p);
HashMap looks in a new place (because the hash changed). But the value is sitting in the old
place. Result: we get null
The data is still inside the map, but HashMap cannot find it anymore.
So what this really means is:
If a key changes after we store it in HashMap, HashMap can no longer find the value. It looks in
the wrong place while the data is still in the old place. That is why keys must not change. Once a
key is used, it should stay the same forever.
@Test
void addTest() {}
@Test
void subtractTest() {}
}
JUnit builds a tree structure of tests before execution. Every item in that tree is called a node.
In the example:
There are 3 nodes:
1. CalculatorTest: a container node (represents the test class)
2. addTest: a test node (represents a test method)
3. subtractTest: another test node
494
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@BeforeEach
void setup() {
[Link]("Before each test");
}
@RepeatedTest(3)
void repeatTest() {
[Link]("Running test");
}
}
In this example, test method has @RepeatedTest(3), the test runs 3 times, so @BeforeEach will
also be invoked 3 times, once before each execution.
495
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
O(1) if node
Remove O(n)
known
5. CompletableFuture methods
get() → wait for result, throws checked exception
join() → wait for result, throws unchecked exception
allOf() → wait for multiple futures to finish
thenCombine() → merge results of two independent futures
thenApply() → transform the result of a future
thenCompose() → chain another async future
class Employee {
int id;
String name;
496
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](map);
}
}
Answer: Runtime Exception: [Link]
TreeMap always keeps keys in sorted order.
If we don’t provide a Comparator, Java automatically tries to sort keys using the Comparable
interface.
Here, the Employee class does not implement Comparable, so TreeMap doesn’t know how to
compare two Employee objects. During insertion, it throws ClassCastException at runtime.
class SQLDataSource {
class UserService {
Solution
class SQLDataSource {
class UserService {
497
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
void save() {
[Link]("Data saved in MySQL");
}
}
void registerUser() {
save();
[Link]("User Registered");
}
}
This design is not good because UserService is not a MySQLDatabase. UserService only needs
database functionality. It should not become a database class.
Better Design using Composition
class MySQLDatabase {
void save() {
[Link]("Data saved in MySQL");
}
498
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class UserService {
UserService(MySQLDatabase database) {
[Link] = database;
}
void registerUser() {
[Link]();
[Link]("User Registered");
}
}
UserService uses MySQLDatabase instead of extending it. This is composition.
Now the code is more flexible. Later, if we want to switch from MySQL to PostgreSQL, we can
change only the database class without changing much in UserService.
In Spring Boot, composition is commonly used through dependency injection.
Instead of creating objects using new inside the class, Spring automatically provides the required
objects from outside.
For example, UserService may need UserRepository to access database data. Rather than
extending the repository class, Spring injects the repository object into UserService.
This keeps classes loosely coupled, easier to test, easier to replace, and easier to maintain in
large real-world applications.
9. What happens when multiple threads enter a synchronized block?
When multiple threads try to enter the same synchronized block, Java allows only one thread to
execute that block at a time.
The first thread gets the lock and starts execution. Other threads cannot enter immediately, so
they wait until the lock is released.
After the first thread finishes the synchronized block, the lock becomes free. Then another
waiting thread gets the chance to execute.
This is done to protect shared data from being modified by multiple threads at the same time.
10. But what if the thread calls nofityAll() then which thread gets the access to synchronized
block
When a thread calls notifyAll(), all waiting threads are moved from the waiting state to the
blocked/runnable state.
But this does not mean all threads enter the synchronized block immediately. The lock can still
be owned by only one thread at a time.
After the current thread releases the lock, one of the waiting threads gets the lock and enters
the synchronized block. Which thread gets the lock first is decided by the thread scheduler, so it
is not guaranteed or predictable.
499
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
11. How do you handle method overloading when the number of parameters keeps increasing
(e.g., 100) without creating multiple overloaded methods
If the number of parameters keeps increasing, creating many overloaded methods becomes
difficult to manage. The code becomes lengthy, confusing, and harder to maintain.
In real projects, instead of creating 10, 20, or even 100 overloaded methods, we use group
related data into a separate class or use the Builder Pattern.
Problem with Multiple Overloaded Methods
createUser(String name)
String name;
int age;
String city;
String email;
[Link] = name;
[Link] = age;
[Link] = city;
[Link] = email;
}
}
class UserService {
[Link](
"User Created : " + [Link]
);
}
}
Main:
User user = new User(
"CodingLyf",
2,
"Hyderabad",
"codinglyf@[Link]"
);
500
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](user);
In modern applications, we should prefer passing objects instead of handling too many method
parameters.
501