Strategy Pattern: Keep Your Code Flexible Sometimes your code needs to support multiple ways to solve the same problem. For example: different payment methods, sorting algorithms, or pricing strategies. A common mistake is to handle this with large if–else blocks. This quickly becomes hard to maintain and extend. This is where the Strategy pattern helps. The idea is simple: you extract each algorithm into a separate class and define a common interface. At runtime, you just choose which strategy to use. This allows you to: • easily add new behavior • avoid complex condition logic • keep your code clean and flexible In Java, this usually means: → interface + multiple implementations → inject the needed strategy into your service Small pattern — but very powerful in real systems. #designpatterns #java #backend #softwarearchitecture #cleancode
Andrei Lupanov’s Post
More Relevant Posts
-
How the JVM Works We compile, run, and debug Java code all the time. But what exactly does the JVM do between compile and run? Here's the flow: Build: javac compiles your source code into platform-independent bytecode, stored as .class files, JARs, or modules. Load: The class loader subsystem brings in classes as needed using parent delegation. Bootstrap handles core JDK classes, Platform covers extensions, and System loads your application code. Link: The Verify step checks bytecode safety. Prepare allocates static fields with default values, and Resolve turns symbolic references into direct memory addresses. Initialize: Static variables are assigned their actual values, and static initializer blocks execute. This happens only the first time the class is used. Memory: Heap and Method Area are shared across threads. The JVM stack, PC register, and native method stack are created per thread. The garbage collector reclaims unused heap memory. Execute: The interpreter runs bytecode directly. When a method gets called multiple times, the JIT compiler converts it to native machine code and stores it in the code cache. Native calls go through JNI to reach C/C++ libraries. Run: Your program runs on a mix of interpreted and JIT-compiled code. Fast startup, peak performance over time. Thanks to ByteByteGo #JVM #JavaVirtualMachine
To view or add a comment, sign in
-
-
#Post11 In the previous post(https://lnkd.in/dynAvNrN), we saw how to create threads in Java. Now let’s talk about a problem. If creating threads is so simple… why don’t we just create a new thread every time we need one? Let’s say we are building a backend system. For every incoming request/task, we create a new thread: new Thread(() -> { // process request }).start(); This looks simple. But this approach breaks very quickly in real systems because of below mentioned problems. Problem 1: Thread creation is expensive Creating a thread is not just creating an object. It involves: • Allocating memory (stack) • Registering with OS • Scheduling overhead Creating thousands of threads = performance degradation Problem 2: Too many threads → too much context switching We already saw this earlier(https://lnkd.in/dYG3v-vb). More threads does NOT mean more performance. Instead: • CPU spends more time switching • Less time doing actual work Problem 3: No control over thread lifecycle When you create threads manually: • No limit on number of threads • No reuse • Hard to manage failures This quickly becomes difficult to manage as the system grows. So what’s the solution? Instead of creating threads manually: we use something called the Executor Framework. In simple words consider the framework to be like: Earlier, we were manually hiring a worker (thread) for every task. With Executor, we have a team of workers (thread pool), and we just assign tasks to them. Key idea Instead of: Creating a new thread for every task We do: Submit tasks to a pool of reusable threads This is exactly what Java provides using: Executor Framework Key takeaway Manual thread creation works for learning, but does not scale in real-world systems. Thread pools help: • Control number of threads • Reduce overhead • Improve performance We no longer manage threads directly — we delegate that responsibility to the Executor Framework. In the next post, we’ll see how Executor Framework works and how to use it in Java. #Java #Multithreading #Concurrency #BackendDevelopment #SoftwareEngineering
To view or add a comment, sign in
-
Let’s break the code step by step: int x = 4; int y = 11; x += y >> 1; System.out.println(x); 🔹 Step 1 — Understand the operator precedence In Java, the right-shift operator >> has higher precedence than the compound assignment +=. So this line: x += y >> 1; is evaluated as: x = x + (y >> 1); 🔹 Step 2 — Evaluate the shift operation y >> 1 Right shift means: divide by 2 (for positive integers). 11 in binary = 00001011 Right shift 1 = 00000101 That equals 5. 🔹 Step 3 — Add to x Copy code x = 4 + 5 x = 9 🔹 Step 4 — Print System.out.println(x); // 9 🧠 ✅ Correct Answer: B) 9 #Java #SpringBoot #FullStackDeveloper
To view or add a comment, sign in
-
-
dmx-fun 0.0.14 Released! Version 0.0.14 is the ecosystem release. Where previous milestones built out the core type system, this one connects dmx-fun to the frameworks and infrastructure that production Java applications actually run on: Spring, Spring Boot, Micrometer, and Resilience4J. Five new production modules ship alongside new core types, collector façades, and a full Spring Boot reference application. Here is everything that changed: https://lnkd.in/ecRis2JM
To view or add a comment, sign in
-
How the JVM Works (Simple Breakdown) We compile and run Java code every day, but what actually happens inside the JVM? Here’s the flow: 1. Build (Compilation) javac converts your .java code into bytecode (.class). This bytecode is platform-independent. 2. Load The JVM loads classes only when needed using class loaders: Bootstrap → core Java classes Platform → extensions System → your application 3. Link Before execution: Verify → checks bytecode safety Prepare → allocates memory for static variables Resolve → converts references into memory addresses 4. Initialize Static variables get their values and static blocks run (only once). 5. Memory Heap & Method Area → shared Stack & PC Register → per thread Garbage Collector manages memory automatically. 6. Execute Interpreter runs bytecode JIT compiler converts frequently used code into native code 7. Run Your program runs using a mix of interpreted and compiled code, improving performance over time. Follow Ankit Sharma for more such insights.
To view or add a comment, sign in
-
-
Traditional Loops vs Streams in Java When working with collections, developers often face this choice 👇 Traditional Loops - Imperative approach (how to do it) - Step-by-step control - More verbose and manual Streams - Declarative approach (what to do) - Functional style (filter, map, collect) - Cleaner and more expressive code Key Insight Streams shift the focus from iteration to transformation, making code easier to read and maintain. * When to use what? - Use loops when you need fine-grained control - Use streams for cleaner, pipeline-based data processing There’s no one-size-fits-all — choose based on readability, performance, and use case. #Java #CleanCode #Streams #SoftwareEngineering #BackendDevelopment
To view or add a comment, sign in
-
-
🚀 Day 7 – Exception Handling: More Than Just try-catch Today I focused on how exception handling should be used in real applications—not just syntax. try { int result = 10 / 0; } catch (Exception e) { System.out.println("Error occurred"); } This works… but is it the right approach? 🤔 👉 Catching generic "Exception" is usually a bad practice 💡 Better approach: ✔ Catch specific exceptions (like "ArithmeticException") ✔ Helps in debugging and handling issues more precisely ⚠️ Another insight: Avoid using exceptions for normal flow control Example: if (value != null) { value.process(); } 👉 is better than relying on exceptions 💡 Key takeaway: - Exceptions are for unexpected scenarios, not regular logic - Proper handling improves readability, debugging, and reliability Small changes here can make a big difference in production code. #Java #BackendDevelopment #ExceptionHandling #CleanCode #LearningInPublic
To view or add a comment, sign in
-
“No implementation. Still powerful.” Sounds weird? A thing that does nothing… yet controls everything. 👉 That’s a Java Interface. Think of it like this: An interface is a contract. It doesn’t tell how to do something. It tells what must be done. And once you agree to that contract… 'You must follow it.' What makes Interface special? You cannot create objects of an interface It contains: Variables → public static final Methods → public abstract (by default) A class uses implements → to accept the contract What happens when a class implements an interface? No shortcuts. If a class signs the contract: 👉 It MUST implement all methods 👉 Otherwise → it becomes abstract 🧠 The real power (most people miss this) One class → can implement multiple interfaces That means: ✔ Multiple behaviors ✔ Flexible design ✔ Loose coupling This is something classes alone can’t achieve. 🔥 Real-world thinking Interface = Rules Class = Player Rules don’t play the game… but without rules, the game collapses. Final Insight- Abstract class gives partial abstraction Interface gives pure abstraction 👉 If abstraction is hiding complexity then interface is designing clarity #Java #OOP #Interface #Abstraction #JavaProgramming #SoftwareDesign #CodingJourney #DeveloperMindset #LearnJava #TechSkills
To view or add a comment, sign in
-
-
🚨 Can a Thread call start() twice in Java? Short answer — No. And we learned this the hard way in production. 😬 😓 The real story We had a payment retry system. When a payment failed, our code called thread.start() again on the same thread to retry. Seemed logical... until we saw IllegalThreadStateException crashing the entire service at midnight. 💀 🔍 Why does this happen? Once a thread finishes, it moves to a TERMINATED state. Java does not allow restarting a dead thread — ever. ❌ Wrong: t.start(); t.start(); → 💥 CRASH ✅ Right: Create a new Thread each time, or use ExecutorService 💡 How we fixed it Replaced raw threads with ExecutorService. Every retry = a new task submitted to the pool. No crashes. No headaches. 🧠 Remember: 🔁 Thread lifecycle → New → Runnable → Running → Terminated 🚫 Once terminated — cannot restart ✅ Always use a new Thread or ExecutorService One line of mistake. One midnight crash. One lesson for life. 🙂 Have you ever hit this bug? Drop a comment 👇 #Java #Multithreading #Threading #JavaDeveloper #BackendDevelopment #CodingTips #SoftwareEngineering
To view or add a comment, sign in
-
InterruptedException is not an error. It’s how threads are asked to stop. And ignoring it can make your application impossible to shut down. --- In Java’s threading model, interruption was never designed as a failure mechanism. It’s a signal. A coordination event between threads. --- Calling interrupt() is the intended way to ask a thread to stop. But it doesn’t stop it. It sets a flag. And if the thread is blocked, it may react by throwing InterruptedException. Here is the trap: when that exception is thrown, the flag is cleared. If you ignore it, you erase the signal. If you care about it, you must restore it: Thread.currentThread().interrupt(); --- This is the model. And most code ignores it. Consider this: try { queue.take(); } catch (InterruptedException e) { // ignore } Looks harmless. It’s not. From that point on, your thread behaves as if no interruption ever happened. The JVM asked it to stop. Your code said: no. This is how systems become impossible to shut down cleanly. Threads keep running. Executors don’t terminate. Shutdown hooks hang. And eventually: kill -9 This is not a rare edge case. It’s the direct consequence of coding against the model. --- There is a contract: If you catch InterruptedException, you must either: - propagate it - or restore the flag Interruption is not about failure. It’s about control. It’s how the JVM coordinates lifecycle across threads. When you ignore it, you’re not just hiding a problem. You’re breaking the control plane of your application. Final thought Most systems don’t fail because something crashed. They fail because something refused to stop. A thread that ignores interruption is not resilient. It’s uncontrollable. And in production, uncontrollable systems don’t degrade. They hang. Then they get killed. 💬 How do you handle interruption in your production code? #Java #JVM #Multithreading #Backend #SoftwareEngineering
To view or add a comment, sign in
Explore related topics
- Code Design Strategies for Software Engineers
- Evaluating Code Flexibility in Software Design
- Patterns for Solving Coding Problems
- How to Align Code With System Architecture
- Interface Prototyping Techniques
- How Pattern Programming Builds Foundational Coding Skills
- Maintaining Consistent Code Patterns in Projects
- Strategies to Refactor Code for Changing Project Needs
- Emergent Design Strategies Using Refactoring
- Button Design and Placement Strategies
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development