🚀 Day 2/15: Eliminating the "Billion Dollar Mistake" with Optional 🛡️ As an Architect, I see codebases cluttered with 'if (obj != null)' checks. This "defensive" coding hides the actual business logic. Today is about Java 8 Optional—the tool for cleaner, safer API design. 🧠 📝 THE "WHY": Before Java 8, returning 'null' was a silent trap. Optional<T> is a container that forces the caller to acknowledge that a value might be absent. It’s not just a wrapper; it’s an API contract. ✅ API HONESTY: Method signatures now tell the truth about potential missing data. ✅ FUNCTIONAL FLUENCY: Chain operations (.map, .filter) without nesting 'if' statements. ✅ LAZY EVALUATION: Use .orElseGet() to avoid unnecessary object creation. 🎯 MASTERING THE METHODS: 1. 🛠️ Optional.ofNullable(val): The safe way to wrap potential nulls. 2. 🔄 .flatMap(): Use this when your mapping function also returns an Optional. 3. ⚡ .orElseGet(Supplier): The "Senior" way to provide a fallback (lazy execution). 💻 IMPLEMENTATION: import java.util.Optional; public class Day2 { public static void main(String[] args) { String dbValue = null; // Potential null from a DB call // The Functional, Null-Safe Approach String result = Optional.ofNullable(dbValue) .filter(val -> val.length() > 3) .map(String::toUpperCase) .orElseGet(() -> "Default Value"); System.out.println("Result: " + result); } } 💡 INTERVIEW TIP: "Should you use Optional as a class field or method parameter?" 🚫 NO. It’s intended as a return type to help callers handle missing data. Using it as a field adds unnecessary overhead and isn't Serializable! 13 days to go! Moving from "defensive" to "expressive" code. 📈 #Java #CleanCode #Java8 #SoftwareArchitecture #Programming #Backend
Java 8 Optional: Cleaner API Design with Null Safety
More Relevant Posts
-
If your domain is mostly String, int, and BigDecimal, you will likely ship more avoidable bugs. For Java and Spring teams, this is a common trap: primitive obsession (a domain model built from raw primitives). It feels productive because JSON serialization and JPA (Java Persistence API) mapping often just work. The cost shows up later as duplicated validation, unclear intent, and easy-to-swap parameters. Rule of thumb: promote a field to a type when it carries meaning beyond its raw representation. Example: In a checkout flow, you have BigDecimal amount and a String discount. One endpoint treats discount as 10 (10%), another treats it as 0.10. Then a third place rounds differently. Introduce a PercentDiscount value object that accepts one representation, normalizes it, and enforces invariants (range, scale, rounding). Now "10 vs 0.10" is not a recurring debate. It is a constructor rule. When a field should become a type: - You validate the same rule in more than one place (invariants). - You keep normalizing or formatting it (behavior). - It has multiple representations (cents vs dollars, case-insensitive codes). - It is easy to mix up with other fields of the same primitive. - It is part of the ubiquitous language (Money, OrderId, EmailAddress). Trade-off: more types means more boundary plumbing. In Spring, you may need Jackson configuration (for example, @JsonCreator and @JsonValue) and JPA mapping (AttributeConverter or @Embeddable). What is one field in your codebase that is still a String, but should be a type? Inspiration: https://lnkd.in/dEarQAaW #java #ddd #architecture #programming #cleancode #clean #code
To view or add a comment, sign in
-
-
🚀 𝗪𝗵𝘆 𝗖𝗼𝗹𝗹𝗲𝗰𝘁𝗶𝗼𝗻 𝗙𝗿𝗮𝗺𝗲𝘄𝗼𝗿𝗸 𝗜𝗻𝘀𝘁𝗲𝗮𝗱 𝗼𝗳 𝗔𝗿𝗿𝗮𝘆𝘀? Today I revised an important core Java concept. I reflected on an important question: 👉 Why do we prefer the Collection Framework over Arrays in real-world applications? 🔎 𝗔𝗿𝗿𝗮𝘆𝘀 — 𝗦𝗶𝗺𝗽𝗹𝗲 𝗯𝘂𝘁 𝗟𝗶𝗺𝗶𝘁𝗲𝗱 • Fixed size (defined at creation time) • No built-in utility methods • Manual resizing required • Limited flexibility for dynamic data • Homogeneous data Example: int[] arr = new int[3]; Once the size is fixed, it cannot grow. 🚀 𝗖𝗼𝗹𝗹𝗲𝗰𝘁𝗶𝗼𝗻 𝗙𝗿𝗮𝗺𝗲𝘄𝗼𝗿𝗸 – 𝗙𝗹𝗲𝘅𝗶𝗯𝗹𝗲 & 𝗦𝗰𝗮𝗹𝗮𝗯𝗹𝗲 Java provides powerful data structures through the Collection Framework. Example: ArrayList<Integer> list = new ArrayList<>(); list.add(10); list.add(20); list.add(30); list.add(40); // Automatically resizes ✅ 𝗪𝗵𝘆 𝗖𝗼𝗹𝗹𝗲𝗰𝘁𝗶𝗼𝗻𝘀 𝗔𝗿𝗲 𝗣𝗿𝗲𝗳𝗲𝗿𝗿𝗲𝗱 • Dynamic resizing • Built-in methods (add(), remove(), contains()) • Multiple data structures: • List → Ordered data • Set → Unique elements • Map → Key-value pairs • Queue → FIFO processing • Better scalability for real-world systems 💡 𝗞𝗲𝘆 𝗜𝗻𝘀𝗶𝗴𝗵𝘁 *Arrays are good for fixed-size data. *Collections are designed for real-world, evolving applications. Understanding why we use something makes us stronger developers — not just coders. #Java #CollectionFramework #Programming #DSA #LearningJourney
To view or add a comment, sign in
-
-
🧩⚡ COLLECTORS.TEEING(): TWO AGGREGATIONS, ONE STREAM PASS 🔸 TLDR ▪️ Need two aggregations? teeing() does it in one collect with a clean immutable merge. 🔸 THE PROBLEM Ever needed two aggregations (ex: count + sum) on the same stream? The “classic” approach often streams the data twice — simple, but not always ideal. 🔸 CODE: OLD VS MODERN // ✕ Java 8: two passes long count = items.stream().count(); double sum = items.stream() .mapToDouble(Item::price) .sum(); var result = new Stats(count, sum); // ✓ Java 12+: one pass with teeing() var result = items.stream().collect( Collectors.teeing( Collectors.counting(), Collectors.summingDouble(Item::price), Stats::new ) ); 🔸 SEE A PROBLEM WITH THIS CODE? LET US KNOW 👀 Hint: there’s a subtle one depending on what items is… 😉 🔸 WHY THE MODERN WAY WINS ▪️ ⚡ Single pass: stream once, aggregate twice ▪️ 🧩 Composable: mix any 2 collectors (min/max, summary stats, grouping, etc.) ▪️ 🔒 Immutable result: merge straight into a record / value object 🔸 HOW IT WORKS (IN 1 SENTENCE) Collectors.teeing() routes each element to two downstream collectors, then merges both results using your merger function (Stats::new here). 🔸 TAKEAWAYS ▪️ Prefer teeing() when you want two results from one stream without mutable accumulators ▪️ Great fit for Stats/DTO/record building ▪️ Still keep readability in mind: for tiny lists, two passes can be totally fine ✅ #Java #Java12 #Streams #Collectors #FunctionalProgramming #CleanCode #Performance #BackendDevelopment #JVM src: https://lnkd.in/ezn22fFC Go further with Java certification: Java👇 https://lnkd.in/eZKYX5hP Spring👇 https://lnkd.in/eADWYpfx SpringBook👇 https://bit.ly/springtify JavaBook👇 https://bit.ly/jroadmap
To view or add a comment, sign in
-
-
Loops work. But they don’t always express intent clearly. That’s where 𝗦𝘁𝗿𝗲𝗮𝗺𝘀 𝗔𝗣𝗜 changed Java. Instead of telling the system how to iterate, you describe what you want. Example: List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.stream() .filter(name -> name.startsWith("A")) .map(String::toUpperCase) .forEach(System.out::println); This reads like a pipeline: • Take a collection • Filter it • Transform it • Consume it No explicit loop. No temporary variables. No manual indexing. Streams encourage: • Functional-style thinking • Declarative code • Cleaner data transformation They also introduce: • Lambda expressions • Method references • Lazy evaluation Today was about: • Understanding 𝘀𝘁𝗿𝗲𝗮𝗺() • Difference between intermediate and terminal operations • Writing expressive and readable data pipelines Modern Java isn’t about writing more code. It’s about writing clearer code. #Java #Streams #FunctionalProgramming #CleanCode #SoftwareEngineering #LearningInPublic
To view or add a comment, sign in
-
-
What happens when an exception is thrown inside a finally block? • We all learn early that finally always executes • But there’s a dangerous edge case many developers miss Consider this: • An exception occurs in the try block • Control moves to finally • Another exception is thrown inside finally What Java actually does: • The exception from finally overrides the original exception • The original exception is silently lost • Debugging becomes painful because the real cause disappears Why this is risky: • You think cleanup is handled safely • But the real failure gets masked Real-world scenario: • DB query fails → exception thrown • finally tries to close the connection • close() throws another exception • You only see the cleanup failure, not the DB issue Best practices: • Never throw new exceptions from finally • Keep finally simple and safe • Use try-with-resources whenever possible • Log inside finally, don’t propagate Key takeaway: • finally is for cleanup — not logic, not errors, not control flow If this surprised you, you’re not alone. #Java #ExceptionHandling #BackendDevelopment #CleanCode #LearningInPublic
To view or add a comment, sign in
-
Day 39: The Decision Makers – Mastering Java Conditional Statements 🛣️🧠 Today was all about "Branching." I moved from linear code to dynamic logic. I learned that Conditional Statements are the heart of every "Smart" feature in a professional application—from checking login credentials to calculating dynamic discounts. Here is the "Logic Ladder" I climbed today: 1. Simple if (The One-Way Gate) 🚪 The most basic decision. If the condition is true, the code runs. If not, it skips it entirely. ▫️ Use Case: Sending a notification only if a user has unread messages. ▫️ Syntax: if (balance < 0) { System.out.println("Low Balance!"); } 2. if-else (The Two-Way Fork) 🍴 The "Plan B" statement. It ensures that something always happens, whether the condition is met or not. ▫️ Use Case: If passwordMatch is true, log in; else, show an error. ▫️ Logic: It’s an "Either/Or" scenario. 3. if-else-if Ladder (The Multi-Choice) 📶 This is for complex, multi-layered decisions. Java checks each condition one by one until it finds a "True" match. ▫️ Use Case: Grading systems (A, B, C, D) or calculating tax brackets based on income. ▫️ Efficiency: As soon as one condition is met, Java skips the rest of the ladder! I realized that every condition inside the parentheses () must result in a boolean (true or false). This is where the Relational and Logical operators I learned earlier (like &&, ||, ==) finally come to life! Code isn't just about calculation; it's about Navigation. Today, I learned how to give my program a "Brain" to choose the right path. Task: https://lnkd.in/dQmCm3sr #JavaFullStack #ConditionalStatements #ControlFlow #LogicBuilding #Day39 #LearningInPublic #BackendDeveloper #Java2026 #CodingJourney #SoftwareEngineering 10000 Coders Meghana M
To view or add a comment, sign in
-
Day 21-What I Learned In a Day(JAVA) 1️⃣ Method Call Without Passing Data Definition: A method call without passing data is a statement that invokes a method which does not require any input parameters. When executed, control temporarily moves from the calling statement to the method, the method performs its task, and then control returns to the calling statement. Flow: Caller → Method → Execution → Return to Caller Syntax: methodName(); // if method is in same class ClassName.methodName(); // if method is static or called from another class objectName.methodName(); // if method is non-static 2️⃣ Method Call With Parsing Data (With Parameters) Definition: A method call with parsing data is a statement that invokes a method while passing input values (arguments) to its parameters. The values provided in the call are assigned to the method’s parameters, the method executes using these values, and control returns to the caller (optionally returning a value). Flow: Caller → Pass Arguments → Method → Execution → Return Value (if any) → Return to Caller Syntax: methodName(argument1, argument2, ...); // same class ClassName.methodName(argument1, argument2, ...); // from another class (static method) objectName.methodName(argument1, argument2, ...);// non-static method returnTypevariable=methodName(arguments); // if method returns a value Practiced 👇 #Java #JavaMethods #Programming #CodeReusability #LearnJava #SoftwareDevelopment #CodingPractice #TechLearning #MethodCalling #CareerGrowth
To view or add a comment, sign in
-
Arrays are fixed. Real applications aren’t. That’s why Java introduced the 𝗖𝗼𝗹𝗹𝗲𝗰𝘁𝗶𝗼𝗻𝘀 𝗙𝗿𝗮𝗺𝗲𝘄𝗼𝗿𝗸. Instead of managing size manually, you use dynamic data structures like: • 𝐀𝐫𝐫𝐚𝐲𝐋𝐢𝐬𝐭 • 𝐋𝐢𝐧𝐤𝐞𝐝𝐋𝐢𝐬𝐭 • 𝐇𝐚𝐬𝐡𝐒𝐞𝐭 • 𝐇𝐚𝐬𝐡𝐌𝐚𝐩 Example: List<String> names = new ArrayList<>(); names.add("Alice"); names.add("Bob"); Unlike arrays: • Collections grow dynamically • Provide built-in methods • Reduce manual memory handling But collections are not interchangeable. Choosing the wrong one affects: • Performance • Memory usage • Readability For example: • ArrayList → fast random access • LinkedList → efficient insert/delete • HashSet → unique elements • HashMap → key-value storage Today was about: Understanding why collections exist When to use List vs Set vs Map Writing scalable data logic Good developers don’t just store data. They choose the right structure for it. #Java #Collections #DataStructures #SoftwareEngineering #Programming #LearningInPublic
To view or add a comment, sign in
-
-
Almost mass is a production deployment because of one missing annotation. Had a REST endpoint that worked perfectly in dev. In production, it returned empty responses randomly. Spent hours checking the code logic. Everything looked fine. The problem: @Transactional public List<Order> getOrders(Long userId) { return orderRepository.findByUserId(userId); } Hibernate session was closing before lazy-loaded collections could be accessed. The fix: @Transactional(readOnly = true) public List<Order> getOrders(Long userId) { return orderRepository.findByUserId(userId); } One annotation. readOnly = true keeps the session open long enough to load the data properly. Lazy loading issues are the worst because they work sometimes and fail randomly. What annotation has saved you from a production disaster? #Java #SpringBoot #Hibernate #Production #BackendDevelopment
To view or add a comment, sign in
-
Solving LeetCode 876: Middle of the Linked List Finding the middle node of a linked list might sound simple, but it’s a great exercise in pointer manipulation and efficiency. Problem Statement Given the head of a singly linked list, return the middle node. If there are two middle nodes, return the second one. Example: Input: 1 → 2 → 3 → 4 → 5 → Output: 3 → 4 → 5 Input: 1 → 2 → 3 → 4 → 5 → 6 → Output: 4 → 5 → 6 My Java Solution class Solution { public ListNode middleNode(ListNode head) { ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; // move one step fast = fast.next.next; // move two steps } return slow; // slow ends at middle } } Key Insights Using two pointers (slow & fast) ensures we find the middle in a single pass. Time complexity: O(n) Space complexity: O(1) This technique is widely applicable in problems like cycle detection and linked list partitioning.
To view or add a comment, sign in
-
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