Java & Spring Interview Prep Guide
Java & Spring Interview Prep Guide
1
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
2
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Table of Contents
1 Why datatypes are important in Java? ..................................................................... 19
2 What is reference type in java? ................................................................................ 20
3 In how many ways we can create the object? .......................................................... 20
4 Explain about 4 pillars of Object-oriented programming (OOPS) (Frequent Question).
21
5 How is abstraction different from encapsulation? .................................................... 23
6 Questions on Encapsulation? ................................................................................... 24
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? ............................................................................... 29
11 Difference between final, finally, and finalize()? ....................................................... 29
3
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
8
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
167 Output-Based 62: Thread: Call run() and start()? ................................................... 181
168 Output-Based 63: Thread: Join ? ........................................................................... 181
169 Output-Based 64: Thread: Create a deadlock ........................................................ 182
170 Output-Based 65: Instance vs Static ? .................................................................... 183
171 Output-Based 66: Static variable declaration? ........................................................ 184
172 Output-Based 67: Tricky question on runnable ..................................................... 184
173 Java Scenario 1: If – Else Conditions or Switch. ...................................................... 185
174 Java Scenario 2: ATM Operations - Switch. ............................................................. 185
175 Java Scenario 3: Traffic Light Action - Switch. ......................................................... 186
176 Java Scenario 4: E-commerce Cart Total Calculation (For loop). .............................. 186
177 Java Scenario 5: Password Strength Checker. ......................................................... 186
178 Java Scenario 6: Printing Even and Odd Numbers with Two Threads ...................... 187
179 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…) ............................................................ 188
180 Java Scenario 8: Producer Consumer Problem ...................................................... 188
181 Java Scenario 9: Simulating the deadlock .............................................................. 190
182 Java Scenario 10: Increment the shared counter with threads .............................. 190
183 Java Scenario 11: Bank Account Withdrawal ......................................................... 191
184 Java Scenario 12: CompletableFuture Scenario ..................................................... 191
185 Java Scenario 13: Payment Gateway Integration ................................................... 192
186 Java Scenario 14: Notification Service ................................................................... 193
187 Java Scenario 15: File Export System ..................................................................... 193
188 Java Scenario 16: Authentication Strategies .......................................................... 193
189 Java Scenario 17: Employee Payroll System ........................................................... 194
190 Java Scenario 18: Bank Account Types .................................................................. 194
191 Java Scenario 19: Custom Exceptions .................................................................... 195
192 Java Scenario 20: Closing resources ...................................................................... 196
193 Java Scenario 21: Creating Custom Exception ........................................................ 196
194 Java Scenario 22: Global Math Operations ............................................................ 197
195 Java Scenario 23: Logging...................................................................................... 198
196 Java Scenario 24: Creating Custom Functional Interface ........................................ 198
197 Java Scenario 25: Collections - 1 ............................................................................ 198
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
12
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
290 Spring 38: What are best practices or rules while creating the Entity? .................. 270
291 Spring 39: What are the different types of relationships in JPA and explain
@OneToOne with example ................................................................................................ 270
292 Spring 40: Explain @OneToMany or @ManytoOne with example ......................... 272
293 Spring 41: Explain @ManytoMany with example .................................................. 274
294 Spring 42: What is cascading in JPA and when would you use it? .......................... 275
295 Spring 43: How does eager loading and lazy loading works in JPA? ....................... 276
296 Spring 44: Explain Repositories, like CrudRepository, JpaRepository, and
PagingAndSortingRepository? ........................................................................................... 278
297 Spring 45: What is JPQL and how does it different from HQL? ............................... 280
298 Spring 46: What is @Query (Custom Queries) and why should we use them?? ..... 280
299 Spring 47: What is @NamedQuery and @NamedNativeQuery? ............................ 281
300 Spring 48: What is the use of @Transactional?...................................................... 282
301 Spring 49: What is propagation in Transaction? ..................................................... 285
302 Spring 50: How transaction works under the hood? .............................................. 288
303 Spring 51: What is N+1 problem how do you fix it? ............................................... 290
304 Spring 52: Difference Between JOIN and JOIN FETCH? .......................................... 290
305 Spring 53: How does locking works in Spring JPA? ................................................. 291
306 Spring 54: Explain JPA Architecture? ..................................................................... 293
307 Spring 56: what is Persistence context in JPA? ....................................................... 298
308 Spring 57: what are different states on an Entity? ................................................. 300
309 Spring 58: How Cache works in JPA? ..................................................................... 300
310 Spring 59: How to connect to multiple databases? ................................................ 302
311 Spring 60: How do you create Custom repository in Spring JPA? ........................... 306
312 Spring 61: What is connection pooling, how it helps in Spring? ............................. 306
313 Spring 62: What do you know about @NoRepositoryBean? .................................. 307
314 Spring 63: What is Spring Security? ....................................................................... 308
315 Spring 64: How do you enable Security in Spring applications? ............................. 309
316 Spring 65: What is @EnableWebSecurity? ............................................................ 310
317 Spring 66: What are the key features of Spring Security? ...................................... 311
318 Spring 67: What is authentication and different types of it? .................................. 311
319 Spring 68: What is the authentication flow in Spring security? .............................. 312
13
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
320 Spring 69: What is JWT and how does it differ from Basic auth? ........................... 314
321 Spring 70: What is structure of the JWT? .............................................................. 316
322 Spring 71: How server validates the JWT token? ................................................... 317
323 Spring 72: How to implement JWT authentication in Spring boot? ........................ 318
324 Spring 73: How does SecurityFilterChain works and list down the filters? ............. 319
325 Spring 74: Internals on SecurityFilterChain? .......................................................... 321
326 Spring 75: What is UserDetailsService and how it works? ..................................... 322
327 Spring 76: Explain about Password Encryption and why it is important? ............... 323
328 Spring 77: What is CSRF and how it works in Spring? ............................................ 324
329 Spring 78: What is CORS, how we need to resolve it? ............................................ 325
330 Spring 79: What is Outh2 and how does it differ from JWT? ................................. 325
331 Spring 80: How do you implement Oauth2 in Spring? ........................................... 326
332 Spring 81: What is role-based access?................................................................... 326
333 Spring 82: Difference between Role and Grant? .................................................... 328
334 Spring 83: What is method level security? ............................................................ 328
335 Spring 84: What is Spring Boot Actuator, and why is it useful? .............................. 329
336 Spring 85: How do you enable and configure Actuator endpoints? ....................... 329
337 Spring 86: List out some important Actuator endpoints? ...................................... 330
338 Spring 87: What is Micrometer?............................................................................ 330
339 Spring 88: How to create Custom Endpoint in Actuator? ....................................... 330
340 Spring 89: How to secure Actuator endpoints and why to secure? ........................ 332
341 Spring 90: What is AOP? ....................................................................................... 332
342 Spring 91: What are the core components of AOP?............................................... 334
343 Spring 92: How proxy works in AOP?..................................................................... 336
344 Spring 93: Which classes or methods in Spring cannot be declared as final, and
why?? 337
345 Spring 94: What is Self-Invocation Problem? ......................................................... 338
346 Spring 95: How to do Scheduling in Spring boot? .................................................. 339
347 Spring 96: What is the difference between fixedDelay and fixedRate? .................. 340
348 Spring 97: How can you make tasks run in parallel? .............................................. 341
349 Spring 98: How can we handle scheduled task failures? ........................................ 342
350 Spring 99: How to run a task in the background in Spring boot? ........................... 342
14
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
351 Spring 100: How @Async works behind the scenes? ............................................. 344
352 Spring 101: Can you run Database transactional tasks in Async? ........................... 345
353 Spring 102: How cache works in spring boot? ....................................................... 345
354 Spring 103: How @cachable works? ..................................................................... 346
355 Spring 104: What is the importance of the key while caching? .............................. 346
356 Spring 105 Can you cache based on the condition? ............................................... 346
357 Spring 106: How to update the cache? .................................................................. 347
358 Spring 107: How to delete the cache? ................................................................... 347
359 Spring 108: How cache work behind the scenes? .................................................. 348
360 Spring 109: How CocurrentMapCacheManager works? ........................................ 348
361 Spring 110: What is proxy and how does it work Spring? ...................................... 348
362 Spring 111: How a CGLIB Proxy works with @Bean? ............................................. 350
363 Spring 112: What is filter in Spring boot and how it will used? .............................. 350
364 Spring 113: How do you create a custom filter? .................................................... 351
365 Spring 114: What is interceptor and its uses?........................................................ 352
366 Spring 115: How to create an Interceptor? ............................................................ 353
367 Spring 116: Difference between Filter and Interceptor? ........................................ 354
368 Spring 117: Have you written any custom Annotation, if yes how you have written it?
355
369 Spring 118: @Configuration vs @Component? ..................................................... 356
370 Spring 119: What are best techniques to handle exceptions in Spring? ................. 357
371 Spring 120: How Database indexing improves the performance? .......................... 362
372 Spring 121: What is externalization and how would you achieve it? ...................... 362
373 Spring 122: Auditing in Spring JPA? ....................................................................... 363
374 Spring 123: Explain application flow of the Spring boot or What will happen when we
call run ()? ......................................................................................................................... 366
375 Spring 124: What are different strategies of ID generation in Hibernate? .............. 367
376 Spring 125: What is singleton? .............................................................................. 369
377 Spring 126: How Cross Origin works in Spring? ..................................................... 372
378 Spring 127: How @Retryable works in Spring? ...................................................... 373
379 Spring 128: How proxyMode works in Spring and how does it help? ..................... 375
380 Spring 129: How to deploy Spring boot application using jar or war? .................... 376
15
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
381 Spring 130: Explain different kind of paging techniques? ...................................... 378
382 Rest 1: What is REST API and what are its uses? .................................................... 380
383 Rest 2: What is difference between PUT and PATCH? ............................................ 382
384 Rest 3: Can you tell what are the annotations you used while developing REST APIs?
383
385 Rest 4: Difference between @RestController and @Controller? ............................ 384
386 Rest 5: Difference between @RequestMapping and @GetMapping? .................... 385
387 Rest 6: Difference between @PathVariable and @RequestParam?........................ 386
388 Rest 7: What is Response Entity and how it will be used?...................................... 387
389 Rest 8: Different types of HTTP status codes?........................................................ 388
390 Rest 9: How Spring send JSON by default / How Spring converts Java object to JSON
while returning response from API? .................................................................................. 389
391 Rest 10: Different types of headers? ..................................................................... 390
392 Rest 11: What is content negotiation? .................................................................. 391
393 Rest 12: How can Spring send XML if default is JSON? ........................................... 392
394 Rest 13: What is Idempotency? ............................................................................. 393
395 Rest 14: Why Patch is not idempotent? ................................................................. 393
396 Rest 15: Can we make POST as idempotent? ......................................................... 393
397 Rest 16: How do REST APIs handle versioning, and why is it important?................ 394
398 Rest 17: How do you validate the Request from client in Spring boot? .................. 394
399 Rest 18: How to create custom validators in spring? ............................................. 395
400 Rest 19: How do you implement caching in REST APIs? ......................................... 397
401 Rest 20: How can you handle rate limiting in REST API? ........................................ 398
402 Rest 21: Rate limiting vs API throttling? ................................................................. 398
403 Rest 22: What are different types of authentications used in REST APIs?............... 398
404 Rest 23: Difference between URI and URL? ........................................................... 398
405 Rest 24: How do you implement pagination in REST API? ...................................... 399
406 Rest 25: What is the difference between synchronous and asynchronous
communication in RESTful web services? .......................................................................... 399
407 Rest 26: What are the best practices while designing the REST API? ..................... 400
408 Rest 27: How do you document the APIs and their details?................................... 400
409 Rest 28: SOAP VS REST? ........................................................................................ 400
16
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
410 Rest 29: How do you invoke the other APIs or Inter-service communication in a
microservice in Spring? ..................................................................................................... 401
411 Rest 30: How do you implement search functionality? .......................................... 402
412 Spring Scenario 1: Get by User ID or Email. ........................................................... 403
413 Spring Scenario 2: Debug the slow API. ................................................................. 403
414 Spring Scenario 3: Performance optimization. ....................................................... 404
415 Spring Scenario 4: DB Migrations .......................................................................... 405
416 Spring Scenario 5: File upload and download ........................................................ 405
417 Spring Scenario 6: Asynchronous Processing ......................................................... 407
418 Spring Scenario 7: Handling Configuration ............................................................ 407
419 Spring Scenario 8: Apply configuration without reboot ......................................... 409
420 Spring Scenario 9: Large file handling. ................................................................... 411
421 Spring Scenario 10: Caching. ................................................................................. 412
422 Spring Scenario 11: Validations. ............................................................................ 413
423 Spring Scenario 12: Scheduling the task. ............................................................... 414
424 Spring Scenario 13: Dependency Injection. ........................................................... 415
425 Spring Scenario 14: Custom Bean. ......................................................................... 416
426 Spring Scenario 15: Inject bean on condition. ....................................................... 417
427 Spring Scenario 16: Inject bean on multiple conditions. ........................................ 417
428 Spring Scenario 17: Dynamic bean selection, based on parameter from client. ..... 418
429 Spring Scenario 18: Load initial cache data. ........................................................... 420
430 Spring Scenario 19: Logging in Spring boot............................................................ 421
431 Spring Scenario 20: Monitoring the Spring application .......................................... 422
432 Spring Scenario 21: Post idempotency .................................................................. 422
433 Spring Scenario 22: Custom Annotation + Interceptor ........................................... 423
434 Spring Scenario 23: Rate Limiting .......................................................................... 425
435 Spring Scenario 24: Custom Query method ........................................................... 426
436 Spring Scenario 25: Custom Query ........................................................................ 426
437 Spring Scenario 26: Lazy vs Eager / N+1 problem .................................................. 427
438 Spring Scenario 27: save() or saveAll() ................................................................... 428
439 Spring Scenario 28: Partial Update ........................................................................ 429
440 Spring Scenario 29: Soft Deletes............................................................................ 430
17
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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.
19
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
2. Using clone():
class Car implements Cloneable {
int speed = 100;
20
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions
1. In which ways of object creation, the constructor doesn’t get called?
Constructors don’t get called during cloning (clone()) and deserialization
([Link]()), as they copy the object state directly.
2. how to create an object without using a new keyword?
We can create an object without new by using clone(), deserialization, or reflection
[Link] interface is must to clone the object?
Cloneable interface
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
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");
}
}
22
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]("Drawing a circle");
}
}
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();
}
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.
Example: We press a button to start a washing machine. we don’t know (or care) how it
fills water, rotates the drum, or drains it, we just know it washes clothes.
In code: Interfaces and abstract classes are typical tools used for abstraction.
23
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Encapsulation is about hiding data and keeping it safe from outside interference.
Example: A car’s internal data like engine temperature or fuel injection logic is hidden from
the driver.
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 keeps data safe from unwanted changes. It hides internal logic and only
exposes what is necessary. This leads to cleaner, more reliable code because other parts of the
program can’t directly mess with the internal state.
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
24
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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?
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.
25
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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
26
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
4. How is a constructor invoked in Java?
A constructor is automatically called when we create a new object using the new keyword.
For example: new Student("John") invokes the constructor of the Student class
5. What happens if you don't provide a constructor in a class?
If we don’t write any constructor, Java automatically provides a default no-arg constructor. It
initializes object fields with default values, like 0 for numbers or null for objects.
6. Can you have both a default constructor and a parameterized constructor in the same class?
Yes, and it is very common. The compiler will invoke correct one based on the arguments.
7. Explain the concept of constructor Overloading?
Constructor overloading means writing multiple constructors in the same class with different
parameter lists. It allows you to create objects in various ways
8. Can a constructor call another constructor of the same class? How?
Yes, using this(...). It is called constructor chaining. We can call another constructor in the same
class from within a constructor using this() as the first line.
9. What is the purpose of a static block in Java, and how is it related to constructors?
A static block runs once when the class is first loaded, before any object is created or
constructor is called. It is used to initialize static variables. It is not directly related to
constructors. Static blocks are for class-level setup, while constructors deal with object-level
initialization.
10. Explain the difference between an instance initialization block and a constructor.
An instance initialization block is a code block that runs before the constructor, every time an
object is created. It is useful for common setup across multiple constructors. Constructors run
after that. Both help initialize the object, but constructors are more flexible and commonly used.
11. Can we override the constructor?
No. Constructors are not inherited, so they cannot be overridden.
12. Can we overload the constructor?
Yes. We can have multiple constructors in the same class with different parameter lists.
13. Can a constructor be static or final?
Static: No, constructors are instance-level, not class-level.
27
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Final: No, constructors cannot be final because they are not inherited and final applies to
methods to prevent overriding.
14. Can a constructor have return type?
No, a constructor cannot have a return type, not even void.
If we declare a return type, it is treated as a regular method, not a constructor.
But every time we call new, the constructor implicitly returns the instance of the class itself.
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.
28
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");
}
29
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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. Is it possible to declare a variable as both final and abstract?
No, that is not allowed. final means the variable can’t change, while abstract means it has no
value or implementation and must be defined later.
3. Can you have static final variables in Java?
Yes, and it is very common. A static final variable is basically a constant. it belongs to the class
and its value never changes. For example: static final double PI = 3.14;. It is shared across all
instances.
4. Are there any built-in classes in Java that are declared as final?
Yes. Classes like String, Integer, and Math are declared as final. That means we can't extend or
subclass them
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).
30
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
Reference: Java: Pass By Value Or Pass By Reference | by Ananya Sen | Nov, 2020 | Medium |
Medium
31
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
32
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.
33
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.
34
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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);
}
}
35
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
36
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
37
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
int Integer
char Character
float Float
double Double
boolean Boolean
long Long
short Short
byte Byte
int a = 10; // primitive
[Link](10);
int x = [Link](s);
38
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
class Animal {
void makeSound() {
[Link]("Animal sound");
}
}
[Link](); // Allowed
// [Link](); // Not allowed – Animal reference can't access Dog methods
When we want to keep a single copy of a variable that should be shared by all instances of the
class.
For constants that belong to the class rather than any specific instance
class Counter {
static int count = 0; // shared variable
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 {
static int square(int n) {
return n * n;
}
}
3. Static Blocks
Static blocks are used for static initialization of a class. They run when the class is loaded.
42
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
24 What is the difference between method overloading and method overriding? (Commonly asked
question)
One of the most common interview questions in Java is the difference between
method overloading and method overriding. These two concepts fall under polymorphism
but they work very differently.
Method Overloading (Compile-time Polymorphism)
Method overloading means having multiple methods with the same name but different
parameter lists (either in number, type, or order). It is resolved at compile time.
class Calculator {
int add(int a, int b) {
return a + b;
}
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, parameters, and return type must match exactly.
- 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).
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)
}
}
}
}
27 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]();
}
}
50
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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");
}
}
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]();
}
}
51
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
4. In what situations would you use super() or this() in a constructor?
Use super() when we want to call a parent class constructor. Use this() to call another constructor in
the same class.
5. Can it be possible to put super() or this() anywhere in a Java program?
No. We can only use super() or this() as the very first line inside a constructor. If we try to place it
anywhere else, the compiler will throw an error.
void move() {
[Link]("Moving the shape"); // concrete method
}
}
void draw() {
[Link]("Drawing a circle");
}
}
class AbstractClassDemo {
public static void main(String[] args) {
Shape s = new Circle(); // Allowed, reference is abstract, object is
concrete
[Link]();
[Link]();
}
}
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
}
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();
}
54
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
- Interfaces support default and static methods (since Java 8)
55
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
But if both interfaces have default methods with same name, we must override it.
Java forces to resolve conflicts manually.
3. Can an interface have a constructor?
Interfaces can't have constructors because they can't be instantiated directly.
Interfaces are meant for defining contracts, no for object creation.
Only classes have constructors in Java.
4. What’s the difference between abstract class and interface if both can have abstract methods?
Abstract class can have state (variables, constructor, etc), interfaces can't (except constants).
We can extend only one abstract class, but implement multiple interfaces.
Interfaces are ideal when we just need to define a structure.
5. Have you used any built-in Java interfaces in your code?
Yes, common ones are `Runnable`, `Comparable`, `Serializable`, `AutoCloseable`.
These are part of core Java libraries.
6. What happens if you don't implement all methods of an interface?
Then the class must be declared `abstract`.
Java will not compile it if we don’t implement all the methods.
7. Can we define variables inside an interface?
Yes, but all variables are implicitly `public static final` (constants).
We cannot define instance variables.
8. Can interface methods be private or protected?
No, all methods are `public` by default in classic interfaces.
Since Java 9, `private` methods are allowed for internal use only. `protected` is not allowed.
9. Can an interface extend another interface?
Yes. One interface can extend one or more interfaces.
This helps in grouping related contracts.
10. Why are default methods introduced in Java 8 interfaces?
To allow interfaces to have some method implementation.
This helps add new methods without breaking existing code.
Mainly used for backward compatibility and utility methods.
11. Can an interface have variables? What type are they by default?
56
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Yes, interfaces can have variables, which are by default public, static, and final constants. This
means they are accessible from anywhere, belong to the interface itself rather than any specific object,
and their values cannot be changed after being initialized.
Access Modifiers Can use any (private, protected, etc.) All members are public by default
57
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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?
`serialVersionUID` is a unique identifier for a `Serializable` class. It is used during deserialization to
ensure that the sender and receiver of a serialized object have loaded classes for that object that are
compatible
3. What happens if you don’t define `serialVersionUID` in a Serializable class?
If `serialVersionUID` is not explicitly defined, the Java runtime will generate one automatically based on
various aspects of the class. This can lead to unexpected `InvalidClassException` errors if the class is
modified, as the generated `serialVersionUID` might change
4. When will be serialization useful?
Serialization is useful when we need to convert an object into a byte stream so it can be stored or
transferred, then later rebuilt.
Typical cases:
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.
59
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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);
}
@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;
}
61
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.
4. Is a bank and account aggregation or composition?
That is aggregation, accounts can be moved to another bank.
They don't die with the bank.
5. Can an object be part of multiple compositions?
No, in composition, the parent fully owns the child.
One child can’t belong to multiple owners like that.
62
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
where one object contains or uses another object. A Car has an Engine; a Dog has a Tail; this
relationship is realized through composition
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)
37 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.
63
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
64
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
65
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
66
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The OS switches between them so fast that it feels like they are all running at the same time.
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:
class MyThread extends Thread {
public void run() {
[Link]("Thread is running...");
}
}
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.
68
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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]();
}
}
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.
69
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]("Cancelling task...");
[Link](true);
70
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
71
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
45 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
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.
72
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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. Does synchronized make Java objects thread-safe?
Only the synchronized parts are safe, the rest of the object can still be accessed unsafely.
5. How would you ensure that a piece of code is executed by only one thread at a time?
Use synchronized block or method.
6. 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
73
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. Can I use multiple locks in one class?
Yes, we can create different lock objects and sync on each. It is useful when we want to protect
different data separately.
Think of it like having separate keys for different drawers instead of locking the whole cupboard.
4. 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.
74
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
5. 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.
6. Can a thread acquire multiple locks?
Yes, a thread can acquire multiple locks.
7. What if order of acquiring multiple locks is inconsistent by threads?
If multiple threads acquire multiple locks in different orders, it can lead to a deadlock.
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)
Atomic:
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.
Mention about apply volatile for shared flags where visibility matters, but remember it doesn’t
ensure atomicity.
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.
78
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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]"));
String line = [Link]();
[Link](line);
} catch (IOException e) {
[Link]("Something went wrong while reading the file.");
[Link]();
} finally {
[Link]("Cleanup code goes here.");
}
At the top:
Throwable: The root of all errors and exceptions in Java.
Two main branches:
Error
oSerious problems that applications shouldn’t try to handle.
oExamples: OutOfMemoryError, StackOverflowError.
oUsually caused by the JVM or environment.
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
80
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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;
balance -= amount;
}
}
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]();
}
}
Indirect Questions:
1. Can we use throw without throws?
We can use throw for unchecked exceptions (like NullPointerException) without throws.
82
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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);
}
}
Let’s say we are implementing Registration API where age must be greater than 0. In such
scenarios we want to terminate the program by throwing the exception.
public class InvalidAgeException extends RuntimeException {
public InvalidAgeException(String message) {
super(message);
}
}
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.
If we override only equals() but not hashCode(), the collection might put the same “equal” object in
multiple places because the hash codes differ.
If we override only hashCode() but not equals(), we might get weird equality results where two
objects in the same bucket are still considered different.
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?
85
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.
86
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
So, the Java Collection Framework is a group of interfaces and classes that helps to work with different
types of data structures easily.
87
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.
88
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
58 ArrayList vs LinkedList?
Internal Structure:
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.
LinkedList: Accessing an element by index is slower (O(n) time complexity) because we need to
traverse the list from the beginning or end until we reach the desired index.
Insertions/Deletions:
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.
89
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference: Difference Between ArrayList and LinkedList in Java | by Ramesh Fadatare | Medium
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?
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.
90
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
59 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).
If we insert/delete in the middle or beginning, performance is bad O(n) , because elements
have to be shifted.
So again, they behave similarly here.
Memory Usage
ArrayList is more memory-efficient. It resizes conservatively.
Vector tends to waste memory by doubling its size on every resize.
That means if we are tight on memory, go with ArrayList.
Thread Safety: This is the biggest difference.
Vector is synchronized , meaning all its methods are thread-safe.
ArrayList is not synchronized , it is not safe to use with multiple threads unless we handle
locking yourself or wrap it with [Link]().
Synchronized does not mean fast. Vector is thread-safe but slower due to locking. if we need
thread safety, we need to use CopyOnWriteArrayList or ConcurrentLinkedQueue depending on
the use case.
91
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?
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);
92
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person p = (Person) o;
return [Link](name, [Link]);
}
}
// Lookup works
[Link]([Link](p1)); // Engineer
// Lookup fails
[Link]([Link](p1)); // null
}
}
93
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
61 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
When to Use Which
Choose HashMap , when performance is critical and thread safety is handled externally or is not a
concern.
Choose HashTable , when thread safety is a requirement and performance is less of a priority.
In modern Java, ConcurrentHashMap is often preferred over HashTable for concurrent access scenarios
as it provides better performance while maintaining thread safety.
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.
94
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
62 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.
On the other hand, minimum 16 threads can perform update operations on ConcurrentHashMap at a
time
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.
95
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
96
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();
ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
// To "put null"
[Link]("key", value == null ? NULL_VALUE : value);
97
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
98
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
99
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
// 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:
101
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
When we call add(element):
It first checks if there’s room in the array
If yes -> Just put it at the next available index
If no -> Resize the array, then add
So, add () is usually O(1) time, but occasionally it can be slower when resizing happens.
5. Accessing Elements
We can access any element by its index using .get(index)
[Link](2);
This is super-fast; O(1) time
6. Inserting or Deleting in the Middle
Here is the catch:
If we insert or remove from the middle, it has to shift elements to keep the order.
That takes time; O(n) time
[Link](2, "hello"); // shifts everything from index 2 onward
[Link](2); // also shifts everything back
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).
102
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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:
hashCode(): A method that returns an integer representation of an object. It is crucial for determining
the bucket index.
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:
103
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
cross the load factor as if the load factor is 0.75 and when becoming more than 75% full then resizing
trigger which involves array copy.
[Link] does resize happens in HashMap?
The resizing happens when the map becomes full or when the size of the map crosses the load
factor. For example, if the load factor is 0.75 and then becomes more than 75% full, then resizing trigger,
which involves an array copy. First, the size of the bucket is doubled, and then old entries are copied
into a new bucket.
3. What is the difference between the capacity and size of HashMap in Java?
The capacity denotes how many entries HashMap can store, and size denotes how many mappings
or key/value pair is currently present.
4. Apart from String, what else predefined class we can use as Keys in A Map?
Wrapper classes: Integer, Long, Double, Float, Boolean, Character
5. If a poorly designed hash function causes all elements to collide in a HashMap, what would be the
performance impact?
Normally, HashMap lookup is O(1) on average. But If all elements collide, every key ends up in the
same bucket. But with collisions, it degrades to O(n) because it must scan through a linked list. That is
why Java 8 improved this by switching to a balanced tree after many collisions
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:
LinkedHashMap : How does LinkedHashMap work internally? | VS Hashmap internals? | LRU cache | Is
it synchronized?
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🔴]
/ \
105
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[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:
Custom Ordering
Operations:
106
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
/ \
[5🔴] [15🔴]
/
[1🔴]
But now 5 and 1 are both red. That breaks the red-red rule, so the tree recolors and rotates:
[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
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.
107
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
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.
108
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Question:
109
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:
Starting Point:
110
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
76 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.
111
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");
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.
78 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.
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.
80 [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.
114
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;
115
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
T get() {
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
116
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
It divides the heap into small regions and prioritizes collecting regions with the most garbage first.
5. ZGC (Z Garbage Collector)
These are modern, advanced GCs designed for very large heap sizes (often 10 GB or more).
They are capable of ultra-low pause times (often under 10 milliseconds), even as memory usage
grows.
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:
118
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
119
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Example: WeakHashMap uses weak references for its keys, so if a key is no longer strongly referenced
elsewhere, the entry will be removed automatically during GC.
[Link](); // Suggest GC
[Link]();
120
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
87 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.
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)
121
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
.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.
122
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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]();
}
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) {
123
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
return [Link]([Link]());
}
[Link]() vs [Link]():
[Link](value): Use it when the value is guaranteed to be non-null. If value is null, it throws
a NullPointerException.
[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:
null: Represents the absence of a reference to an object. It can lead to NullPointerExceptions if not
handled carefully and doesn't explicitly convey the intent of "no value." Optional aims to reduce the
need for null checks.
124
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<>();
125
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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:
126
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> {
127
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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);
}
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);
128
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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() {
129
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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!");
It can extend abstract and concrete class. It can't extend abstract and concrete class.
It can implement an interface that contains any It can implement an interface which contains a
number of abstract methods. single abstract method.
130
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
It works fine. What we are doing is, taking “s” and passing it to [Link].
Instance Method Reference of a Particular Object: Refers to an instance method of a specific object.
class Printer {
public void print(String message) {
[Link](message);
}
}
131
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.
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)
132
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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().
[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.
133
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
96 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.
2. Intermediate Operators: Transform or filter data without executing immediately (lazy evaluation).
3. Terminal Operators: Trigger execution and produce a final result, consuming the stream.
134
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
[Link]()
.map(n -> n * factor) // accessing outside variable
.forEach([Link]::println);
135
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If we really need to update state from inside a stream, we can use Mutable containers like
AtomicInteger or a list.
AtomicInteger sum = new AtomicInteger(0);
[Link](n -> [Link](n));
[Link]([Link]());
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().
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
136
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
137
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](count); // Output: 3
101 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)
.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:
138
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
We will use sequential streams when the order of operations matters or when we have a small amount
of data.
Ex: Read data in sequential manner and processing it.
2. When to use Parallel Streams?
Use parallel streams for large, CPU-intensive tasks where the order of elements doesn't matter.
Example. If we have a million numbers and we need to calculate the square of each one; a parallel
stream can split the work and do it much faster
3. When not to use Parallel Streams?
Avoid parallel streams when order is must, the operations are fast and the dataset is small, as the
overhead of managing threads will hit the performance.
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.
[Link]()
.map(s -> {
try {
return [Link](s); // throw NumberFormatException
139
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
} 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);
}
})
.forEach([Link]::println);
140
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
}
141
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Streams don’t handle checked exceptions well inside functions like map() or filter().
We need to wrap the code in try-catch blocks, which makes it messy and hard to read.
With loops, you can just handle exceptions normally.
4. When the Code Has Side Effects
Streams are meant for pure functions, can not change the outside variables.
If we are updating variables outside the stream (like counters or flags), it can lead to bugs, especially if
the stream is parallel. Loops are safer and more predictable in such cases.
5. When We Need to Use Indexes
Streams don’t give the easy access to element positions.
If the logic depends on knowing the index (like comparing the current and next item), a regular loop is
much easier to write and understand.
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";
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:
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)
144
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Java 12:
[Link](): The [Link]() method in Java was introduced in Java 12 as part of the
Stream API. It allows us to collect the same stream using two different collectors at once, and then
combine their results using a merging function (BiFunction).
Reference: Mastering [Link]() in Java Streams (With Examples) | by A cup of JAVA coffee with
NeeSri | Medium
[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.
[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";
}
145
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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>
""";
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]());
}
146
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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:
Sealed classes provide a mechanism to restrict the inheritance hierarchy of a class or interface. This
means we can explicitly control which classes are allowed to extend a sealed class or implement a
sealed interface.
public sealed class Shape permits Circle, Square, Triangle {
// ...
}
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.
147
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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);
}
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
148
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
SequencedMap
SequencedSet
SequencedCollection works with ArrayList and LinkedList, it gives new methods like
107 Output-Based 1: How many String objects will be created in memory from below code?
String s1 = new String("hello");
String s2 = "hello";
149
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
108 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.
[Link](a == b);
[Link](a == c);
[Link]([Link](c));
150
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
Explanation:
"hello" is stored in the String Pool, “a” points to it.
[Link](0) returns the same object when the whole string is taken.
151
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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));
[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));
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:
154
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}.
155
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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',
156
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]([Link](arr));
Explanation:
final means, we can’t reassign the value to ‘arr’ but we can change the content.
So arr[0] = 99 is allowed and updates the original array.
Output is [99, 2, 3]
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
return;
} finally {
[Link]("In finally");
}
Explanation:
Even try return the value, finally still executes before method returns.
So, Output is “In finally”.
Explanation:
Output is 2, because finally overrides the return of try.
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.
158
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
int x = instanceInit();
{
[Link]("Instance Block");
}
Test() {
[Link]("Constructor");
}
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:
159
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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.
This shows constructor chaining in inheritance.
So, output is:
A constructor
B constructor
161
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:
A obj = new B(); here reference is of type A, object is of type B.
We are trying to call [Link]();, but display() is not defined in class A.
Even though the object is of type B, the compiler checks in class A for available methods because
the reference type is A.
Since A has no display() method, this results in a compile-time error
How you fix this compile time error?
162
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:
C extends B, which extends A, so C is indirectly a subclass of A.
A a = new C(); is valid because we assigning a subclass (C) to a superclass reference (A) , that is
upcasting.
163
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
B b = (B) a; is downcasting, means are converting ‘a’ reference to class B. It is safe here because ‘a’ is
actually pointing to a C object and C is a subclass of B.
Since the cast is valid at runtime and the output is: Cast successful.
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.
164
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
165
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link]("D test");
}
}
public class Test {
public static void main(String[] args) {
new B().test();
}
}
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
166
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 method (the method in the parent class). Keep same visibility or increase it, but never reduce it
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
167
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Override
void connect() throws NullPointerException {
[Link]("Connecting to child server");
}
}
Explanation:
[Link]() throws Exception, a checked exception.
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.
168
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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().
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.
170
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
Explanation:
171
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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");
}
[Link]("hello");
}
}
Explanation:
There are two overloaded show() methods: one takes a single String, the other takes a varargs
(String...).
We call [Link]("hello") with a single String argument.
Java gives priority to the exact match over varargs.
So, show(String s) is chosen instead of show(String... s).
Output: String.
void show(long l) {
[Link]("long");
}
Explanation:
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");
173
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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");
}
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.
174
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
Explanation:
Class A has only a parameterized constructor A(String s) , it has no default constructor.
175
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
176
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[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, B Default.
Explanation:
new B().display();
177
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Inside display()
[Link](super.x); - super.x also refers to the same x variable in A (since it wasn’t shadowed in
B). The value is now 20 because we modified it earlier.
162 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
178
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
interface Parent {
void baseMethod();
}
@FunctionalInterface
interface Child extends Parent {
// No new abstract methods allowed except override
}
class Test {
public static void main(String[] args) {
Child c = () -> [Link]("Child");
[Link]();
}
}
Explanation:
164 Output-Based 59: Functional Interface: Will the code below compile?
@FunctionalInterface
interface MyFunc {
void test();
}
class Demo {
public static void main(String[] args) {
MyInterface m = (a) -> a * a;
[Link]([Link](5));
}
}
180
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
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]("Two");
} catch (InterruptedException e) {
[Link]();
}
});
[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.
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.
Unblocking t2: Because t1 is now terminated, [Link]() in t2 returns immediately. t2 resumes execution
and prints "Two", then terminates.
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]("B");
});
[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.
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.
183
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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:
184
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.
185
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
186
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
178 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.
187
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
179 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.
188
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
2. Create a ShareQueue class, In which we take a Queue or LinkedList. We need to how much
capacity this Queue should be.
3. SharedQueue class contains two synchronized methods produce() and consume(). These
methods are invoked by the two threads.
4. If Queue is full, make producer to wait, until consumer consumes the queue.
5. If Queue is empty, make consumer to wait, until producer pushes the values to the queue.
6. In this sample, we are producing 20 values and consuming till queue is empty. Once queue is
empty thread stops execution.
7. Here is the code link:
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:
189
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.
182 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.
Code links:
With Integer: JavaSamples/Scenario10_SharedCounter_Int.java at main · CodingLyf-
Fullstack/JavaSamples
190
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
// Async task 1
CompletableFuture<String> userFuture = [Link](() -> {
simulateDelay(1000);
return "User: CodingLyf";
});
// Async task 2
CompletableFuture<String> ordersFuture = [Link](() -> {
simulateDelay(1500);
return "Orders: 5";
});
191
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
});
//Existing implementations
class UpiPayment implements PaymentMethod {
//Implement the methods
}
192
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.
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.
195
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Example 2: DatabaseConnectionFailedException
The app can’t connect to the database at all. Without that, nothing works, so it should fail
immediately.
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
196
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
Explanation:
We should create them as static methods as they won’t depend on any object state.
public final class MathUtils {
return a / b;
}
}
Hint:
Use Static.
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
}
}
198
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
This avoids ConcurrentModificationException because remove() updates the iterator’s internal state
safely.
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);
199
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Solution: Use a LinkedHashSet, it removes duplicates while keeping the insertion order.
Add all emails from the first list, then from the second list.
Solution: Use a LinkedHashMap<Character, Integer>; it preserves insertion order and allows us to store
character counts.
After populating it, iterate over the entries and return the first key with a count of 1.
public class Test {
public static void main(String[] args) {
String str = "swiss";
// Count occurrences
for (char c : [Link]()) {
[Link](c, [Link](c, 0) + 1);
}
200
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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<>();
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);
201
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
// 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.
while (![Link]()) {
Job job = [Link]();
[Link]("Executing: " + job);
}
Solution:
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<>();
203
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[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("{[(])}"));
}
}
}
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.
205
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.
206
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.
3. Limit Large Collections: Clear or reuse large lists, maps, or arrays instead of letting them grow
endlessly.
207
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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.
209
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
5. Garbage Collection Tuning: Adjusted JVM garbage collection settings to reduce pause times and
improve memory management.
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:
210
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
Code Link: JavaSamples/Scenario47_StackWithArray.java at main · CodingLyf-Fullstack/JavaSamples
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.
211
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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:
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.
212
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
.collect([Link]());
[Link]("Unique Numbers: " + uniqueNumbers);
}
}
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.
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].
2. .max([Link]()) : finds the maximum element by comparing numbers in their
natural order (ascending).
3. .orElse(0) : in case the stream is empty, it safely returns 0 instead of throwing an exception.
Another Variant:
Given a list of strings, find the longest string using Java streams.
List<String> strings = [Link]("apple", "banana", "orange","grape", "kiwi");
Use: .max((o1, o2) -> [Link]() - [Link]())
Explanation:
215
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
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).
216
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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).
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
217
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
233 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:
218
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
Explanation:
sorted([Link]()) : arranges the numbers in descending order (largest to smallest).
limit(3) : takes only the first 3 elements from that sorted stream (the top three numbers).
235 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](""))
.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");
}
}
}
219
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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);
}
}
220
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"].
241 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]());
221
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](words);
}
}
}
}
Output:
Longest Strings [pineapple, blueberry]
222
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
245 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);
}
223
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.
.entrySet()
.stream()
.filter(entry -> [Link]() == 1)
.map([Link]::getKey)
.findFirst()
.orElse(null);
[Link]("First Non-Repeating Character: " + firstNonRepeating);
}
}
Explanation:
[Link]() : converts everything to lowercase so "Java" and "java" are treated the
same.
Result: "java is fun and java is powerful"
225
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
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.
227
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Expected output: Hyderabad(1200000) > Mumbai(800000) > Bangalore(450000) > Chennai(60000) >
Delhi(12000)
Code link: StreamsScenarios/[Link] at main · CodingLyf-Fullstack/StreamsScenarios
Spring
253 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, 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.
Rapid Development: Spring Boot’s opinionated approach and auto-configuration enable developers
to quickly develop apps without the need for time-consuming setup, cutting down on development
time.
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.
228
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
255 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).
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>
229
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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.
230
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
ModelAndView:
A container object that holds both the model data and the name of the view to be
rendered.
ViewResolver:
Resolves the logical view name returned by the controller into a
concrete View implementation (e.g., a JSP page, Thymeleaf template).
View:
Renders the user interface, displaying the data from the Model.
Responsible for generating the final output (e.g., HTML, JSON, XML) to be sent back to
the client.
@ComponentScan : This annotation scans the components (@Component, @Service, etc.) in the
package of annotated class and its sub-packages.
@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.
231
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Component
class Engine {}
@Component
class Car {
@Autowired
private Engine engine; // Spring will inject Engine object here
}
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?
232
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
But in Spring boot, we use Auto-configuration and component scanning to automatically discover and
register beans on the applicaiton's context and classpath. This means now we don’t have manually wire
up beans.
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext context =
[Link]([Link], args);
233
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Reference: Understanding IoC Container in Spring Boot with a Real-Time Project Example | by A cup of
JAVA coffee with NeeSri | Medium
Indirect Questions:
1. What are the types of IOC containers in Spring?
a. BeanFactory: BeanFactory is like a factory class that contains a collection of beans. It instantiates
the bean whenever asked for by clients.
b. ApplicationContext: The ApplicationContext interface is built on top of the BeanFactory
interface. It provides some extra functionality on top BeanFactory.
2. What is the default container?
ApplicationContext is the default and preferred container, adding enterprise features like events,
internationalization, AOP, and annotation support.
3. Difference between BeanFactory and ApplicationContext.
XmlBeanFactory ClassPathXmlApplicationContext,
Configuration (deprecated after Spring AnnotationConfigApplicationContext,
3.x) WebApplicationContext
No support for Full support for annotations, enterprise beans, and Boot
Support
@Autowired, autoconfiguration
234
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
261 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.
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.
235
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
Why? Because when we create a repository interface that extends JpaRepository, CrudRepository, or
PagingAndSortingRepository, Spring automatically finds it and creates an implementation at runtime.
That implementation is registered as a Spring bean, so we can use it with @Autowired even without
@Repository.
public interface UserRepository extends JpaRepository<User, Long> {
}
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
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?
236
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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 application-
[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() {
}
}
237
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
264 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 {
private Engine engine;
@Autowired
public void setEngine(Engine engine) {
[Link] = engine;
}
}
238
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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:
239
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;
}
240
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;
}
241
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Primary
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.
242
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
269 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
243
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
2. If you want to inject dynamic port from a different config file, how will you use value?
@Value("${[Link]}")
private int port;
270 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;
271 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
244
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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
}
}
245
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:
246
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() {
247
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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.
@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.
248
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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:
249
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
250
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When to use: For stateless beans or shared services/repositories where all components can use
the same instance.
2. Prototype:
Spring creates a new instance every time the bean is requested. Spring calls init methods but
does not call destroy methods.
When to use: For stateful beans or temporary objects where each client/request needs a fresh
copy, like form objects or calculations.
3. Request:
A new bean instance is created for each HTTP request. Only relevant in web applications. Each
request gets a fresh bean.
When to use: For request-specific beans, like handling data for a single web request or form
submission.
4. Session:
A new bean instance is created per HTTP session. All requests in the same session share the
same bean.
When to use: For user-specific session data, like shopping carts, logged-in user info.
5. Application:
A single bean instance per ServletContext. It is shared across the whole web application.
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.
251
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Component
@Scope("prototype")
class PrototypeBean {
public PrototypeBean() {
[Link]("New PrototypeBean created");
}
}
@Component
class SingletonBean {
@Autowired
private ObjectFactory<PrototypeBean> objectFactory;
@Autowired
private Provider<PrototypeBean> provider;
252
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
What is proxyMode in Spring, how it helps? (Refer Question No. 367, Spring 115)
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
253
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
}
}
254
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();
}
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();
}
255
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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();
}
}
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.
256
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Configuration
@Conditional([Link])
public class ProdConfig {
@Bean
public DataSource prodDataSource() {
return new HikariDataSource();
}
}
Here, the bean will only load if [Link]=prod.
@Override
public void run(String... args) throws Exception {
[Link]("App started with args: " + [Link](args));
257
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
@Order(2) // Runs second
public class SecondRunner implements ApplicationRunner { ... }
@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.
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
259
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
@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; }
}
282 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).
260
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
261
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?
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
We can just do
User u = new User(1, "CodingLyf");
[Link](u);
263
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The ORM framework will convert that into SQL internally and talk to the database.
Hibernate is the popular ORM Framework.
// getters, setters
}
Here we just call save(). Hibernate internally does: INSERT INTO users (id, name) VALUES (1, ‘CodingLyf’);
264
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
287 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);
[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:
If tomorrow we wanted to switch to another ORM framework (like EclipseLink or OpenJPA), we have to
rewrite a lot of code, because Hibernate APIs are not standard.
To solve this, JPA (Java Persistence API) was introduced by Sun/Oracle as a standard specification.
JPA defines a set of common annotations (@Entity, @Id, @Table, etc.) and methods (persist(),
remove(), find()).
Different frameworks like Hibernate, EclipseLink, OpenJPA can implement JPA.
So, if the code uses JPA annotations and APIs, you can easily switch providers.
Spring Data JPA:
Even with JPA, we still need to write repository/DAO classes, manage transactions, etc. That is
still boilerplate.
Spring Data JPA makes life easier:
We just create a repository interface, extend JpaRepository, and Spring generates all the CRUD
methods.
Under the hood, Spring uses JPA (and Hibernate as provider by default). It many manages all the
transactions.
Example with Spring Data JPA:
265
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Autowired
UserRepository repo;
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).
266
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[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.
267
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.
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
289 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].*;
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?
269
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
290 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.
Provide a No-Arg Constructor
Entities must have a default (public or protected) no-arg constructor for JPA to instantiate them.
Make Fields Private with Getters/Setters
Keep fields private and expose them via getters/setters to maintain encapsulation.
Don’t Use Static or Transient Fields for Persistent State
JPA ignores them, so use @Transient explicitly for non-persistent fields.
Prefer Wrapper Types for Nullable Columns
Example: use Integer instead of int if the column can be null.
Use Meaningful Table and Column Names
Override defaults using @Table(name="...") and @Column(name="...") for clarity.
Override Equals and HashCode carefully
Override equals and hashCode based on primary keys. Avoid including lazy-loaded relationships to
prevent performance issues.
Reference: Entity Class best practices and rules | by Sumit sharma | Medium
291 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.
270
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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
}
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."
271
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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");
Interview Tip: Always explain these relations with examples and dummy tables. So that it will be easy for
the explanation.
272
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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
}
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
273
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
274
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.
294 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.
275
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.
295 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).
276
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
@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?
277
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
278
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Indirect Questions:
279
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
297 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")
.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().
298 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)
280
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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.
281
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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
282
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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);
283
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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]());
}
}
284
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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) { ... }
}
Since OrderService has no interface, Spring uses CGLIB to generate something like
OrderService$$EnhancerBySpringCGLIB, which wraps the real logic.
285
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
That is what Propagation decides. It is basically the rule for how transactions should behave when one
transactional method calls another.
Let’s say we have two services:
@Service
public class OrderService {
@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])
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
286
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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() {
// deduct from account A
// add to account B
sendEmailNotification();
}
@Transactional
public void sendEmailNotification() {
// send email to user
}
}
287
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If this method is called from a transactional method, Spring suspends the existing transaction and runs
this code without transaction.
No error. It simply says "I don’t want a transaction here."
4. If transferMoney() method is in transaction but you don’t want sendEmailNotification() method in
transaction
If transferMoney() is transactional but we want sendEmailNotification() to run outside the transaction,
then:
With NOT_SUPPORTED, Spring will suspend A’s transaction, run B without any transaction, then
resume A’s transaction. Everything works fine.
With NEVER, Spring will throw an exception because A already has an active transaction. B
refuses to run at all.
So, in this case, NOT_SUPPORTED is the right choice, because we are saying: “I want this method to run,
but I don’t want it wrapped in a transaction.”
NEVER is useful only when we want to enforce a hard rule means “this method must never run if there’s
an active transaction, otherwise fail.”
288
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
289
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
303 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();
290
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
A SQL join combines data from two or more tables using a common column. In HQL or JPQL, a
JOIN adds the joined table’s data to the SQL query. But this doesn’t mean the related 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.
291
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Pessimistic Locking assumes that conflicts will occur and locks the data to prevent the other
transactions from accessing it concurrently.
How it works?
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
292
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
293
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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]();
294
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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();
295
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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;
296
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
The UserRepository we wrote extends JpaRepository or [Link] means Spring has already
created a proxy class for it at runtime.
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.
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:
297
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.
298
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Any changes we make to that entity are tracked automatically. When we call commit() or flush(),
JPA writes those changes back to the database.
EntityManager em = ...;
[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:
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.
299
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
[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
@[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.
301
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.
302
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
# Secondary DB (orders)
[Link]=jdbc:mysql://localhost:3306/ordersdb
[Link]=root
[Link]=secret
[Link]-class-name=[Link]
Purpose:
It instructs Spring to scan specified packages for interfaces extending Spring Data
JPA's JpaRepository (or related interfaces like CrudRepository, PagingAndSortingRepository).
For each such interface, Spring automatically generates a concrete implementation (proxy) at
runtime, allow to inject and use these repository interfaces directly in the application.
@EnableJpaRepositories(
basePackages = "[Link]",
entityManagerFactoryRef = "userEntityManagerFactory",
transactionManagerRef = "userTransactionManager"
)
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"
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?
304
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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?
@Repository marks an interface or class as a Spring bean.
@EnableJpaRepositories is what actually scans for those interfaces and generates
implementations.
Without @EnableJpaRepositories, our @Repository interfaces won’t be picked up automatically.
6. How does Spring Boot behave if you don’t even use @EnableJpaRepositories anywhere?
For a single database setup, Spring Boot auto-configures it.
That is why in single DB projects, we never see @EnableJpaRepositories
For multiple DBs, we must configure it explicitly, otherwise Spring won’t know how to separate
repositories by database.
7. Can a repository use multiple EntityManagerFactories at once?
No. A repository is tied to exactly one entity manager (hence one DB).
If we need data from multiple DBs, we
fetch them via different repositories in the service layer.
305
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
311 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();
}
}
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
use, connection pooling creates a pool of pre-defined and reusable connections. When an application
needs to interact with the database, it borrows a connection from this pool, uses it, and then returns it
to the pool for later reuse.
Since Spring Boot 2.x, HikariCP has been the default connection pool due to its speed, simplicity,
and reliability. HikariCP is designed to be a lightweight and high-performance connection pooling library
that performs well under various loads.
Setting up HikariCP in Spring Boot is straightforward since Spring Boot automatically configures
HikariCP as the default connection pool if it is available in the classpath. HikariCP settings can be
customized in the [Link] or [Link] file.
[Link]-idle=5
[Link]-pool-size=20
[Link]-timeout=30000
[Link]-timeout=600000
[Link]-lifetime=1800000
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.
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
307
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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.
Reference: Simplifying Database Access with @NoRepositoryBean | by Arsen Sargsyan | Octa Labs
Insights
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.
308
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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]();
}
}
309
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Spring boot does default configuration when we added starter-security to class path.
Spring Boot Defaults (with spring-boot-starter-security)
1. All endpoints are secured
By default, every HTTP endpoint requires authentication.
Even / or /home is protected unless explicitly allowed.
2. HTTP Basic authentication enabled
Spring Boot automatically provides a login mechanism using HTTP Basic.
Spring will give default login page.
3. Auto-generated user
Spring Boot creates a default user with username user.
Password is auto-generated at runtime and printed in logs.
This password changes every time the app restarts.
4. Password is encoded
The default password uses BCryptPasswordEncoder internally.
5. CSRF protection enabled
For web applications, POST, PUT, DELETE, PATCH requests are protected with CSRF by default.
But if we want override the default we need to a security configuration file with @EnableWebSecurity.
)
.formLogin(withDefaults())
.httpBasic(withDefaults())
.build();
}
317 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:
311
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).
312
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
313
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
When a user log into a Spring Security application, the system needs a place to store information about
who the user is e and what he can do. That is where the SecurityContext comes in.
Think of the SecurityContext as a little box that holds the authentication details:
Who the user is (username, roles, authorities).
Whether they are authenticated or anonymous.
Every request has its own SecurityContext, so Spring Security knows which user is making the request
and what they’re allowed to access.
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();
320 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.
314
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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.
315
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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)
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)
316
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
The server-side API endpoint receiving the request must validate the JWT token. If the token is found to
be expired during this validation, the server should respond with a 401 Unauthorized status code.
Refresh Token Endpoint:
A dedicated endpoint for refreshing access tokens is crucial. This endpoint accepts a valid refresh token
and, upon successful verification, issues a new, unexpired access token.
2. Client-Side Handling:
Intercepting Responses:
The client-side application (e.g., a web or mobile app) should have a mechanism to intercept API
responses, specifically looking for 401 Unauthorized errors.
Refresh Token Flow:
When a 401 Unauthorized response is received due to an expired access token, the client should:
Attempt to use the stored refresh token to request a new access token from the refresh
token endpoint.
If the refresh token is valid and a new access token is successfully obtained, the client
should update its stored access token and then retry the original failed request with the
new access token.
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.
318
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
324 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.
319
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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,
[Link]);
return [Link]();
}
320
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
httpBasic: This enables HTTP Basic Authentication. Spring Security will insert a BasicAuthenticationFilter
into the filter chain. This filter checks the Authorization: Basic ... header, extracts username/password,
and tries to authenticate the user.
addFilterBefore allows us to insert the custom filter into the SecurityFilterChain before another specific
filter.
addFilterBefore(myFilter, [Link])
Here myFilter runs before login/authentication happens. Commonly used for JWT validation so that
requests are authenticated without hitting the username-password login flow.
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
321
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Flow:
Request > DelegatingFilterProxy > FilterChainProxy > Security Filters > DispatcherServlet > Controller
@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.
327 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.
323
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Hashing means converting the password into a fixed-length string using an algorithm (like
BCrypt).
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");
324
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)
330 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
325
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
326
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
327
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
328
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
335 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
We can REST endpoint like /health or /actuator/health.
336 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
329
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
330
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 [Link]");
return data;
}
}
@ReadOperation
public Map<String, Object> activeUsers() {
Map<String, Object> metrics = new HashMap<>();
[Link]("activeUsers", activeUsers);
[Link]("pendingTransactions", pendingTransactions);
[Link]("currentLoad", currentLoad);
return metrics;
}
}
331
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
340 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]();
}
}
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...");
}
@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).
333
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
334
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
Pointcut: A rule that decides where our extra code (aspect) should run.
If we say execution(* PaymentService.*(..)), it means "apply this aspect to all methods in
PaymentService."
Weaving: The process of applying aspects to the target objects. Spring does this dynamically at runtime
using proxies.
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.
336
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Class B Proxy
A proxy is like a wrapper around Class B.
When Class A makes a call, it doesn’t go straight to Class B.
Instead, it goes to the proxy, which has the power to Decide whether to call the actual method
in Class B.
o Add extra behaviour before or after the call.
In this case, that extra behaviour is logging.
4. Class AOP (Aspect-Oriented Programming)
This defines the Aspect, it does the extra behaviour we want to apply.
In the diagram, the Aspect is logging (MethodAspect > logging).
The logging aspect will run before or after methodOfClassB() executes.
5. Flow of execution
1. Class A calls methodOfClassB() : but it hits the proxy instead of the real class.
2. The proxy checks if any aspect is attached (here: logging).
3. The logging aspect runs (e.g., "Method started" / "Method ended").
4. Then the proxy calls the real method in Class B to execute business logic.
5. Optionally, the aspect can also run after the method (e.g., log execution time, exceptions).
344 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
337
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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).
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...");
}
}
338
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
339
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
fixedDelay,
fixedRate
and using cron expressions.
@Scheduled(cron = "0 0 9 * * ?") // every day at 9 AM
public void morningTask() {
[Link]("Good Morning! It is 9 AM");
}
Indirect Question:
1. You have configured scheduled task only once but it is running twice. What might be the issue?
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.
347 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.
340
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
348 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
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.
341
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Override
public void handleError(Throwable t) {
// Custom logic for handling errors
[Link]("Error encountered in scheduled task: " + [Link]());
}
}
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;
}
}
350 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
342
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@EnableAsync
public class Config {
@Async
public void process(String userEmail) {
try {
[Link](5000); // simulate delay
[Link]("Delayed task");
} catch (InterruptedException e) {
[Link]().interrupt();
}
}
}
343
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
It provides a convenient way to mark a method for asynchronous execution and here we don’t need
manually manage the threads.
2. How Spring manages the thread pool in @Async task?
Spring manages @Async tasks using a TaskExecutor (default is SimpleAsyncTaskExecutor), which
handles a thread pool to run methods asynchronously. We can customize the pool size and behaviour by
defining a @Bean of type Executor. Spring submits each @Async method call to this executor, allowing it
to run in a separate thread without blocking the main thread.
@Bean(name = "taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
[Link](5); // Minimum threads
[Link](10); // Maximum threads
[Link](25); // Queue size
[Link]("AsyncThread-");
[Link]();
return executor;
}
Reference: How Spring Boot Configures Thread Pools | Medium
344
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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");
}
}
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";
}
352 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 {
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
355 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.
Whenever this method runs, the cache is updated with the latest product, ensuring consistency
between DB and cache.
347
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
361 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.
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();
}
}
}
When we call new PaymentService().processPayment(); Spring creates a proxy for PaymentService like
this,
//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)
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).
349
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Bean
public UserService userService() {
return new UserService(orderService()); // direct method call
}
@Bean
public OrderService orderService() {
return new OrderService();
}
}
363 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.
350
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Override
351
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
352
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Both Filters and Interceptors serving the same purpose. But what is the difference between them (Refer
Question No 368, Spring 116)
Key Points About Interceptors
1. Interceptors are tied to Spring MVC and work with HandlerMapping and
HandlerExecutionChain.
2. They can pre-process requests, post-process responses, and handle after-completion logic used
for cleanup tasks.
3. Unlike filters, interceptors have access to the controller’s handler method and can examine
method arguments, model data, and view.
353
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():
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
}
}
Works on all HTTP requests, even outside Works only on requests handled by Spring
Scope
Spring MVC (e.g., static resources, JSPs) MVC controllers
354
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Access to Does not know about controllers or Has access to handler (controller method)
Handler handler methods and ModelAndView
Dependency Independent of Spring; works at servlet Dependent on Spring MVC; integrated with
on Spring container level Spring lifecycle
JWT token validation before reaching any Measuring execution time of controller
Example
controller method
368 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.
355
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
Method -> Method
Constructor -> Constructor
@Target([Link] , @Target({[Link], [Link]})
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() {
356
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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
public class AppConfig {
@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.
370 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);
357
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
} 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]());
}
}
@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.
358
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatusCode status,
WebRequest request) {
[Link]("errors", errors);
[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
359
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
}
}
7. How can you restrict @ControllerAdvice only to controller or exceptions from specific packages
360
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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);
}
361
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.
372 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
362
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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]:
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:
363
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@CreatedBy
@Column(updatable = false)
private String createdBy;
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdDate;
@LastModifiedBy
private String lastModifiedBy;
@LastModifiedDate
private LocalDateTime lastModifiedDate;
}
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.
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
365
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
374 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
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.
366
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
367
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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:
368
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
In distributed systems, different instances can pre-allocate different ID ranges, leading to non-
continuous values.
AUTO doesn’t guarantee sequential IDs So the answer: IDs are not sequential because
[Link] relies on database-specific mechanisms (sequence, identity, table), and
Hibernate optimizes them by allocating IDs in batches, which causes gaps.
If we really want sequential IDs, we have to explicitly use [Link] (on MySQL) or a
@SequenceGenerator with allocationSize = 1 But it impacts the performance.
Singleton in Plain Java Before Spring, we create a singleton in Java using private constructors and static
methods.
class CoffeeMachine {
private static CoffeeMachine instance;
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
370
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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?
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 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:
372
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Override
public void addCorsMappings(CorsRegistry registry) {
[Link]("/api/**")
.allowedOrigins("[Link]
.allowedMethods("GET", "POST", "DELETE");
}
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>
373
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
<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);
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
379 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!
}
Reference: Bean Scopes in Java Springboot. Non-related intro | by Jayamal Jayamaha | Medium
Now, when the singleton calls [Link](), Spring fetches the correct request-specific
instance behind the scenes.
380 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>
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.
376
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@SpringBootApplication
public class MyAppApplication extends SpringBootServletInitializer {
@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).
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.
377
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
378
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> {
Below service decides which query to call depending on whether a cursor is provided.
379
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
if (cursor == null) {
return [Link](pageable);
} else {
return [Link](cursor, pageable);
}
}
}
REST APIs
382 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.
2. Platform-independent: Since it is based on HTTP, any system (Java, Python, React, Android, iOS)
can use it.
3. Scalability: Each request is stateless (server doesn’t store session info), making it easier to scale.
4. Integration: REST APIs allow connecting third-party services (payment gateways, maps, social
media).
380
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
5. Reusability: Once an API is built, multiple clients (web, mobile, desktop apps) can use the same
endpoints.
Point to Remember: You may be asked to write sample code for any API, so practice GET, POST, and PUT
Indirect Question:
1. What is stateless and stateful in REST?
In REST, stateless means every request from the client must contain all the info needed, and the
server doesn’t remember past interactions.
Stateful means the server stores session data about the client, so requests can rely on the server’s
memory of previous calls.
Stateless example:
A GET /users/123 request always includes authentication (like a token in headers).
The server doesn’t remember the user logged in; every request carries the needed info.
Stateful example:
we log in once, the server creates a session and stores it in memory.
On the next GET /users/123, we just send a session ID, and the server uses its stored state to
know the user who logged in.
2. How can you maintain a session in a stateless REST API
Use tokens instead
The common approach is JWT (JSON Web Tokens):
Client logs in then server generates a token with user info and expiry.
Client sends the token on every request (usually in the Authorization header).
Server validates the token, without needing to store session state.
3. Why should you handle response timeout while calling any API and how to handle in Spring?
If we don’t handle response timeouts when calling an API, our app can just wait there forever if
the other service is slow or dead. That means bad user experience, and even system crashes under load.
In Spring, we handle this by setting timeouts in the HTTP client. For example, with RestTemplate or
WebClient, we can configure connectTimeout and readTimeout. If the API doesn’t respond in that time,
the call fails fast, and we can retry, show an error, or switch to a fallback.
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout([Link](3000)) // Example: Set connection
timeout
.setReadTimeout([Link](3000)) // Example: Set read timeout
.build();
381
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;
}
});
return [Link]([Link](user));
})
382
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
.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.
384 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) {
383
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
ResponseEntity
.status([Link])
.body(savedUser);
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.
384
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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";
}
385
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;
}
386
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Tricky Questions:
1. What happens if you don’t pass a @RequestParam that is required?
By default, it throws an exception (MissingServletRequestParameterException). To avoid this, we
can make it optional:
@RequestParam(required = false) String city or
@RequestParam(defaultValue = "Hyderabad") String city
2. What happens if you don’t pass a @PathVaraible that is required?
If the value is required (default behavior) and it is missing from the request URL, we will get a 400
Bad Request error because Spring can’t bind it.
If we make it optional (required = false) and it is missing, Spring will pass null to the method
parameter.
// 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);
387
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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);
}
}
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.
388
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
390 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).
389
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@RestController
public class UserController {
@GetMapping("/user")
public User getUser() {
return new User("CodingLyf", 1);
}
}
class User {
private String name;
private int age;
Response JSON:
{
"name": "CodingLyf",
"age": 1
}
390
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
391
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");
}
}
393 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 {
392
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
393
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If the client retries the same POST with the same key, the server returns the stored response
instead of creating a new resource again.
Real-world use case:
Payment APIs (Stripe, PayPal, Razorpay, etc.)
o When we POST a payment request, client include an idempotency key.
o If the client retries due to timeout, the server won’t charge the customer twice.
So, POST can be made idempotent through server-side logic + idempotency keys.
397 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).
398 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
@Size(min=, max=) – validates the length of strings or collections
@Email – ensures the value is a valid email address
@Min / @Max – validates numeric ranges
These annotations are added directly to the request DTOs (Data Transfer Objects).
2. Enabling Validation in Controllers
To trigger validation automatically when a client sends a request, we need to use the @Valid
annotation in the controller method
394
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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.
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 {
@StrongPassword
private String password;
5. Trigger Validation.
Ensure that validation is triggered, typically by using @Valid or @Validated annotations on method
parameters in the controllers or services.
import [Link].*;
import [Link];
@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
397
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.
401 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 435 , Spring Scenario 23 for the implementation
403 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.
398
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Key Differences:
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.
406 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.
399
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
407 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.
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.
408 Rest 27: How do you document the APIs and their details?
When building RESTful APIs, proper documentation is crucial. It helps developers understand
how to use the API, what endpoints are available, what parameters are required, and what responses
to expect. One of the most popular tools for this purpose is Swagger, now known as OpenAPI.
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.
Features: Lightweight, stateless, supports CRUD operations via standard HTTP methods (GET,
POST, PUT, DELETE).
Transport: Only HTTP/HTTPS.
Use Case: Web and mobile applications requiring fast, scalable, and flexible APIs (like social
media apps, e-commerce platforms)
Additional Question:
Why do financial services prefer SOAP over rest?
Strong Contracts: SOAP uses WSDL (Web Services Description Language) which is like a strict contract
between client and server. In finance, this ensures no ambiguity in request/response formats.
Built-in Security: SOAP supports WS-Security (signing, encryption, authentication) out of the box. REST
relies on external mechanisms like OAuth, JWT, or HTTPS.
Transaction Support: SOAP has standards for things like ACID transactions (WS-AtomicTransaction),
which is critical for money transfers where operations must succeed or fail together.
410 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;
401
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
.retrieve()
.bodyToMono([Link]);
}
Mono<String> represents a single asynchronous value.
retrieve() handles the HTTP response.
Point to remember:
Spring has announced RestTemplate is in maintenance mode. That means:
It will still work in current and future Spring versions but No new major features are planned.
Spring recommends using WebClient (from Spring WebFlux) for new projects because it
supports non-blocking, reactive calls and is more flexible for modern applications.
402
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
return users;
}
403
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
404
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
3. Use Asynchronous Processing: Use asynchronous processing for long-running tasks to improve
responsiveness
4. Caching: Implement caching to reduce database load and improve response times
5. Pagination: For large datasets implement the pagination (Refer Question No. )
6. Optimize the Queries
-- Bad
SELECT * FROM users;
405
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Explanation:
For file upload, we need to use MultipartFile. It represents the file sent in a multipart/form-data
request.
Client sends file via HTTP POST request.
Server receives it as MultipartFile.
Server processes and stores the file (in DB, cloud, or local storage).
Return a success response.
@PostMapping("/upload")
ublic ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
try {
// Save to disk (demo purpose)
Path path = [Link]("uploads/" + [Link]());
[Link](path, [Link]());
@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();
}
}
406
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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].
@Configuration
@ConfigurationProperties(prefix = "[Link]")
public class DataSourceConfig {
private String url;
private String username;
private String password;
408
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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.
Create a Git repository (say config-repo). Inside it, place environment-specific property files:
[Link]
[Link]
[Link]
409
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
@GetMapping("/feature-status")
public String featureStatus() {
return "Feature X is " + (featureEnabled ? "ENABLED" : "DISABLED");
410
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
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?
411
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@RestController
@RequestMapping("/files")
public class FileController {
@GetMapping("/presigned-url")
public String getPresignedUrl(@RequestParam String fileName) {
BlobInfo blobInfo = [Link]("my-bucket-name", fileName).build();
@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.
413
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.
@GetMapping("/user")
public String getUser() {
return [Link]();
}
}
415
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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.
416
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Example:
public interface PaymentService {
void pay(double amount);
}
@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]");
return [Link]("linux") && "kafka".equalsIgnoreCase(brokerType);
}
}
And we will have to use @Conditional to trigger the custom Condition class.
@Bean
@Conditional([Link])
public MessageProducer kafkaProducer() {
return new KafkaProducer();
}
428 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.
At runtime, the client request parameter (say paymentMode=paypal) should decide which bean
(payment processor) to use.
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:
418
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
@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:
@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.
420
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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:
421
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
return [Link];
}
public void log(String msg) {
[Link](msg);
}
}
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>
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:
422
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
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);
return false;
}
}
return true;
}
}
423
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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.
If the method does not have the annotation, we block the request and return a 403 Forbidden.
424
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
When we write a filter in Spring Boot, we usually extend OncePerRequestFilter or implement Filter. That
filter can intercept every HTTP request and response.
425
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:
426
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Entity
public class User {
@Id
private Long id;
private String name;
private int age;
}
@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> {
If there are 100 users, for each user one order will be made, which creates 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:
[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.
429
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Modifying
@Query("UPDATE User u SET [Link] = :status WHERE [Link] = :id")
int updateUserStatus(@Param("id") String status, @Param("id") Long id);
}
@Modifying: tells Spring this is an update/delete, not a select.
JPQL UPDATE query updates only the status field.
int return value: number of rows updated.
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.
430
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. 361 Spring 109).
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;
}
Now when we call [Link](order); createdDate and updatedDate will be saved automatically.
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
432
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@Service
public class BookService {
@Autowired
private BookRepository repository;
@ExceptionHandler([Link])
public ResponseEntity<String> handleBookNotFound(BookNotFoundException ex) {
return [Link](HttpStatus.NOT_FOUND).body([Link]());
}
}
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.
Solution:
434
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
446 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.
Initiating the beans.
Connecting to DB
Setting up security, filters etc
Steps to improve.
Use actuator/startup endpoint to analyse which beans are taking time.
Enable lazy initialization using @Lazy:
In Spring Boot, all beans get initialized at startup by default.
If we have complex beans (like DataSources, caches, external API clients), startup time will increase. So
se @Lazy to load non-critical beans only when needed.
Tune the auto-configuration:
Spring Boot auto-configures does many things we may not use (JDBC, JPA, Security, Actuator, etc.). This
adds to startup.
Use @SpringBootApplication(exclude = {[Link]}) for things that are not
needed.
Use Spring AOT + Native image.
Instead of compiling bytecode into native code at runtime (like the JVM with JIT does), AOT compiles
the code ahead of time into a native executable. In traditional Java applications, the Just-in-Time (JIT)
435
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
compiler compiles code during runtime, which can introduce some delays. With AOT, Spring 6 aims to
overcome these delays by performing the compilation ahead of time, which improves startup
performance and resource usage.
We use Spring Security (SecurityFilterChain) to configure which URL endpoints are public and which
require authentication.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests()
// Public pages
.requestMatchers("/", "/home", "/products", "/contact").permitAll()
// Admin-only pages
.requestMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin() // default login page
.and()
.logout();
return [Link]();
}
}
436
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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.
2. If later we add another controller, a scheduled task, or an internal service call deleteEmployee(),
the security rule should still apply.
437
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
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
438
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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:
452 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:
439
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
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
440
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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<>();
441
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Avoid unnecessary String duplication , use intern() where safe, or use StringBuilder instead of +
in loops.
Prefer primitives instead of Wrapper classes when possible . Use int[], long[], etc. instead of
List<Integer>, List<Long> when ever applicable .
EnumMap<Category, List<Product>> productsByCategory = new EnumMap<>([Link]);
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
private Integer version; // Hibernate manages this
442
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;
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])
)
.collectList()
.block(); // waits for all results
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
444
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);
445
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
[Link](1, username);
[Link](2, password);
ResultSet rs = [Link]();
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.
446
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Input Validation
Always validate and escape all user input to ensure it is treated as text, not executable code.
Sanitize Output
Encode HTML entities when displaying user input.
String safeComment = StringEscapeUtils.escapeHtml4(userComment)
Content Security Policy (CSP):
Implement a CSP header to instruct the browser on which sources are allowed to execute
scripts, effectively blocking injected, untrusted scripts
Enable XSS Protection and prevent clickjacking.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@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.
459 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.
447
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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.
Think about security. 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
Student: Represents an individual student. Each student belongs to exactly one department.
[Link]
@Entity
public class Department {
@Id
448
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@GeneratedValue(strategy = [Link])
private Long id;
[Link]
@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
449
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
student Table
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.
450
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
451
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
452
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;
}
}
453
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
So, we write plain business logic in the service methods, while the transactional concerns (begin,
commit, rollback) are handled transparently by the AOP proxy.
454
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
465 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
@Around("@annotation([Link])")
public Object logExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
long start = [Link]();
return result;
}
}
467 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
Cache heavy results (in Redis or application cache).
456
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
If the data changes slowly, you don’t need to hit the DB every time.
Compression & serialization
Compress large JSON responses (gzip).
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);
457
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.
458
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() {
459
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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?
460
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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>
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.
@SpringBootTest // Loads the full application context
@AutoConfigureMockMvc // Configures and injects MockMvc
class UserControllerIT {
@Autowired
private MockMvc mockMvc;
@Test
void shouldReturnUserById() throws Exception {
[Link](get("/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"));
}
}
461
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@ContextConfiguration comes from the older Spring testing framework. It is used to specify
which configuration classes or XML files should be loaded to create the application context for a test. It
is used for configuring the ApplicationContext for integration tests, For instance, before Spring Boot, we
would write something like this:
@ContextConfiguration(classes = [Link])
class LegacySpringTest {
}
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.
@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;
462
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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]());
}
}
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
463
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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 are 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"))
.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.
464
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
@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.
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
465
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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;
@Test
void shouldReturnSunnyWeather() {
when([Link]("Hyderabad"))
.thenReturn("Sunny");
assertThat(result).isEqualTo("Sunny");
466
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
}
}
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);
}
}
467
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.
468
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
class OrderService {
private final PaymentService paymentService;
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
469
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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.
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.
Given int[] arr = {2, 5, 6, 4, 1, 3, 10, 8, 7}; Second largest is 8 and second smallest is 2
Code link: [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]
470
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
471
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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]
472
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Given an integer array, find the contiguous subarray (containing at least one number) which has
the largest product.
Input: int[] arr = { 2, 3, -2, 4 } , Expected output is 6 which maximum product of a sub array.
Code Link:
Similar question: Find Maximum Subarray Sum (Kadane’s algorithm)
Code link: Arrays/[Link] at main · CodingLyf-Fullstack/Arrays
Example:
Input int arr = [1, 2, 3, 4, 5, 6, 7] and k = 3
Ouput [5, 6, 7, 1, 2, 3, 4]
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)
Approach:
Here we use Two pointer technique. Reference to know more about two pointer: Two Pointers in 7
minutes | LeetCode Pattern
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));
}
475
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Example: for [1,2] and subsets are: [], [1], [2], [1,2].
Code Link Arrays/[Link] at main · CodingLyf-Fullstack/Arrays
Additional problems for practice
[Link] of natural numbers using recursion
27. Factorial of a number using recursion
28. Find out the Sum of Digits of a Number.
29. Find Common elements between two arrays int[] arr1 = {1, 2, 4, 5, 6}; int[] arr2 = {2, 3, 5, 7};
30. Add and substract two matrices
476
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
477
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
None of them repeat > isogram.
Example 2:
Word: programming
Letters: p, r, o, g, r, a, m, m, i, n, g
Here r, m, and g repeat > Not an isogram.
Code Link: Strings/[Link] at main · CodingLyf-Fullstack/Strings
478
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
Example 2:
s1 = "xyz"; s2 = "xyabcz"; Output: 0
Explanation:
" xyz" is not there “xyabcz”.
479
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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
480
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
481
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
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
482
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
16. What are the design patterns you have used in your project?
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?
483
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
OOP Concepts
Strings
Collections
484
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Exception Handling
Spring Core
Spring Boot
REST
486
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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?
31. Explain volatile vs synchronized.
32. Difference between Callable and Runnable.
33. How does ExecutorService work?
34. Explain producer-consumer problem.
35. What are deadlocks and how to prevent them?
36. What is a thread pool?
37. How do you stop a thread safely?
38. Difference between Future and CompletableFuture.
39. How do you achieve inter-thread communication in Java?
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?
69. Explain @Entity, @Id, @GeneratedValue.
70. Explain lazy vs eager loading with an example.
71. How do you handle relationships like OneToMany in JPA?
72. What’s the difference between save() and saveAndFlush() in Spring Data JPA?
Testing
73. What is JUnit, and what are its key annotations?
74. What is Mockito? When would you use @Mock vs @Spy?
75. What is @SpringBootTest vs @WebMvcTest?
76. How do you test REST controllers with MockMvc?
Security
77. Authentication vs Authorization, explain with examples.
78. What is Spring Security, and how does it integrate with REST APIs?
488
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
64. How do you implement distributed logging & tracing (Zipkin, ELK)?
65. What happens when one service becomes slow? How would you isolate failures?
66. One of your microservice is down then how do you handle?
System Design & Scalability
67. How would you design an e-commerce system (catalog, orders, payments)?
68. SOLID Principles and Design patterns
69. How would you design scalable notification system?
70. How do you handle millions of users without crashing the DB?
71. What is CQRS pattern? When to use it?
72. What is database sharding? When is it required?
73. How do you ensure high availability and fault tolerance?
74. How do you design a notification system (email/SMS/push)?
75. What are the different caching strategies in distributed systems? (Redis, Hazelcast)?
Production Debugging Scenarios
76. Your Spring Boot app takes 45s to start in prod, but 5s locally. How do you debug?
77. After deployment, REST APIs are responding in >5s. What’s your debugging approach?
78. Your service crashes with OutOfMemoryError when traffic spikes. How do you fix it?
79. A microservice returns 503 during peak load. What’s happening?
80. Users are logged out every 30 min despite JWT being valid for 24h. Root cause?
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.
Collections Utility: Helper methods like sort, binarySearch, max, unmodifiableList.
492
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Stream API: Declarative functional style with map, filter, reduce, collect. Parallel streams enable
concurrency.
5. Java Streams & Functional Programming
Functional Interfaces: Predicate, Function, Consumer, Supplier.
Lambda expressions
Method references (Class::method)
Stream API: intermediate operators (map, filter, sorted) and terminal operators (collect, reduce,
forEach).
Parallel streams.
Optional: of, empty, ofNullable, orElse, ifPresent.
6. Input/Output (I/O)
Console I/O: Read with Scanner, BufferedReader; output with [Link]().
File I/O: Classes: FileReader, FileWriter, BufferedReader, BufferedWriter. Support line-by-line
processing.
Serialization: Persist object state to a file/network via Serializable. Mark sensitive fields
transient.
NIO (New I/O): Channels, Buffers, Selectors for non-blocking, scalable I/O operations.
7. Exception Handling
Checked vs Unchecked: Checked must be declared or handled (IOException); Unchecked are
runtime (NullPointerException).
try-catch-finally: Catch exceptions gracefully; finally always executes (commonly for resource
cleanup).
throw & throws: throw creates an exception; throws declares that method may pass exceptions
up.
Custom Exceptions: Extend Exception or RuntimeException for business-specific errors.
8. Multithreading & Concurrency
Thread Creation: Extend Thread or implement Runnable/Callable.
Synchronization: synchronized methods/blocks ensure only one thread accesses resource.
Locks/ReentrantLocks give more control.
Volatile: Guarantees visibility of changes to variables across threads (not atomicity).
Executor Framework: High-level API to manage pools of threads (ExecutorService,
ScheduledExecutorService).
Future & CompletableFuture: Handle async tasks and callbacks (CompletableFuture = non-
blocking, chainable).
Atomic Classes: Thread-safe operations (AtomicInteger, AtomicBoolean).
493
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Key Features
o Auto-configuration (based on classpath & beans)
o Starter dependencies (spring-boot-starter-*)
o Embedded servers (Tomcat, Jetty, Undertow)
o JAR packaging (spring-boot-maven-plugin)
Configuration
o [Link] / [Link]
o Profiles: [Link]=dev
o Externalized config: Environment variable, command line arguments, system properties
Dev Tools
o spring-boot-devtools: auto-restart, live reload
Run Options
o [Link]() customization
o CommandLineRunner / ApplicationRunner for startup logic
Actuator (Basics)
o /actuator/health, /actuator/info
o For monitoring & health checks
496
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
497
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
498
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)
o Use Spring’s [Link]() for manual escaping
o Set response headers (X-XSS-Protection, Content-Security-Policy)
SQL Injection Prevention
o Always use prepared statements / parameterized queries
o With Spring Data JPA : repository methods prevent injection
o Avoid string concatenation in queries ("WHERE name='" + input + "'")
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)
499
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
500
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
Listening:
@EventListener([Link]).
Built-in Events:
ContextRefreshedEvent, ContextClosedEvent, ApplicationReadyEvent.
15. Legacy (XML & Old Features)
XML-based config ([Link]).
context:component-scan, bean definitions.
16. Deployment & Observability
Zero Downtime:
o Graceful shutdown ([Link]=graceful).
o Readiness + liveness probes.
Monitoring:
o Spring Boot Actuator + Micrometer.
o Logs: SLF4J, Logback.
Packaging:
o Executable JAR/WAR.
o Deploy on Docker, Kubernetes, or Cloud.
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
501
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
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)
477 November
478 December
502
Java & Spring Knowledge Boost by Coding Lyf Insta ID: coding__lyf
503