❗ Java Bug: Why final List or final Map Is Not Immutable in Java Recently, I ran into immunity issue in Java, which I've never paid attention before. It’s a common misconception that marking a field final automatically makes it “safe” or “immutable.” Unfortunately, this is not true when the field holds a mutable object such as a List or Map. Let’s look at this Java class: @Getter @Builder public class Plan { private final List<String> toDoList; } At first glance, this looks immutable: the field is final, and there is no setter. But watch what happens: List<String> initialToDoList = new ArrayList<>(Arrays.asList("Buy groceries", "Read a book", "Exercise")); var plan = Plan.builder().toDoList(initialToDoList).build(); List<String> firstList = plan.getToDoList(); firstList.size()==3; firstList .add("Learn Java"); //No Exception Obtain list again AFTER adding the item: List<String> secondList = plan.getToDoList(); Now firstList.size()==4 and secondList.size()==4 firstList contains the newly added item 'Learn Java' secondList contains the newly added item 'Learn Java' ❇️ Conclusion: Summary object looks immutable from the outside, but its internal state can be changed at any time. That’s not immutability—that’s an illusion of immutability. I feel it's a Java Bug. If it's final, why not just make it immutable no matter if it's a collection or not 😂. #Java
Java Bug: Final List or Map Not Truly Immutable
More Relevant Posts
-
Building Native Image for a Java application requires configuration of reflection, proxies, and other dynamic Java mechanisms. But why is this necessary if the JVM handles all of this automatically? To answer that, we need to look at the differences between static and dynamic compilation in Java. https://lnkd.in/eVyGYHZk
To view or add a comment, sign in
-
☕ Java 8 Features Every Developer Should Know Java 8 was a turning point in Java’s evolution. It introduced functional programming concepts that made code more expressive, concise, and powerful. 🔹 1. Lambda Expressions Write cleaner and shorter code by treating functions as values. Example: "(a, b) -> a + b" 🔹 2. Functional Interfaces Interfaces with a single abstract method (SAM). Common ones: "Runnable", "Callable", "Comparator" 🔹 3. Stream API Process collections in a declarative way. Example: "list.stream().filter(x -> x > 10).forEach(System.out::println);" 🔹 4. Default & Static Methods in Interfaces Interfaces can now have method implementations without breaking existing code. 🔹 5. Optional Class Avoid "NullPointerException" by handling null values safely. Example: "Optional.ofNullable(value).orElse("default");" 🔹 6. Method References Simplifies lambda expressions. Example: "System.out::println" 🔹 7. Date & Time API (java.time) A modern replacement for old Date/Calendar APIs. Classes: "LocalDate", "LocalTime", "LocalDateTime" 🔹 8. Nashorn JavaScript Engine Run JavaScript code inside Java (now deprecated in later versions). 🔹 9. Parallel Streams Easily leverage multi-core processors: "list.parallelStream().forEach(...);" 💡 Takeaway: Java 8 is not just an upgrade—it changes how you think about writing Java code, especially with functional programming and streams. #Java #Java8 #Programming #SoftwareDevelopment #BackendDeveloper #Coding #Developers
To view or add a comment, sign in
-
⚡ Java 8 Lambda Expressions — Write Less, Do More Java 8 completely changed how we write code. What once required verbose boilerplate can now be expressed in a single, clean line 👇 🔹 Before Java 8 Runnable r = new Runnable() { public void run() { System.out.println("Hello World"); } }; 🔹 With Lambda Expression Runnable r = () -> System.out.println("Hello World"); 💡 What are Lambda Expressions? A concise way to represent a function without a name — enabling you to pass behavior as data. 🚀 Where Lambdas Really Shine ✔️ Functional Interfaces (Runnable, Comparator, Predicate) ✔️ Streams & Collections ✔️ Parallel Processing ✔️ Event Handling ✔️ Writing clean, readable code 📌 Real-World Example List<String> names = Arrays.asList("Java", "Spring", "Lambda"); // Using Lambda names.forEach(name -> System.out.println(name)); // Using Method Reference (cleaner) names.forEach(System.out::println); 🔥 Pro Tip Lambdas are most powerful when used with functional interfaces — that’s where Java becomes truly expressive. 💬 Java didn’t just become shorter with Lambdas — it became smarter and more functional. 👉 What’s your favorite Java 8+ feature? Drop a 🔥 or share below! #Java #Java8 #LambdaExpressions #Programming #BackendDevelopment #SoftwareEngineering
To view or add a comment, sign in
-
-
What is a Java Class? Think of a class like a blueprint for a house. The blueprint itself is not a house—it is just a set of instructions that tells you how to build a house. Similarly, a class in Java is a blueprint that defines the structure and behavior of objects. It specifies what attributes an object should have and what actions it can perform. When you write a class, you are essentially saying, “Here is a template. Anyone who wants to create an object of this type should follow these rules.” The class does not exist in memory until you create an object from it. The object is the actual house built from the blueprint. The class is just the plan.
To view or add a comment, sign in
-
💡 Java Tip: Why You Should Be Careful with "Optional" "Optional" in Java was introduced to avoid "NullPointerException"… but many developers still misuse it. Here are a few things to keep in mind: 👉 1. Don’t use "Optional" as a field in entities It was designed for return types, not for class fields. 👉 2. Avoid "isPresent()" + "get()" This defeats the purpose of "Optional". Instead, use: - "orElse()" - "orElseGet()" - "ifPresent()" 👉 3. Don’t overuse it Sometimes a simple null check is more readable than wrapping everything in "Optional". 👉 4. Prefer functional style Example: "userOptional.map(User::getName).orElse("Unknown")" --- 🔍 Quick thought: "Optional" is not a replacement for null — it's a tool to write cleaner, safer code when used correctly. --- What’s one mistake you’ve seen (or made 😄) while using "Optional"? #Java #CleanCode #BackendDevelopment #JavaTips #Developers
To view or add a comment, sign in
-
☄️🎊Day 67 of 90 – Java Backend Development 🎆 🧨 In Java, immutability means that once a String object is created, its value cannot be changed. If you try to "modify" a string—for example, by appending text—Java actually creates a brand-new string object in memory rather than altering the original one. This design choice wasn't accidental; it’s a foundational pillar of how Java handles memory, security, and performance. 👉 Core Reasons for Immutability 👉 1. The String Constant Pool Java uses a special memory area called the String Pool. When you create a string literal, the JVM checks if that value already exists in the pool. If it does, it returns a reference to the existing object instead of creating a new one. If strings were mutable, changing the value of one variable would secretly change the value for every other variable pointing to that same literal, leading to unpredictable bugs. 👉 2. Security Strings are used heavily in sensitive areas of Java programming, such as: Database URLs and credentials. Network connections. File paths. Class loading. If a string were mutable, an untrusted piece of code could receive a reference to a file path, verify it has permission, and then sneakily change the path before the file is actually opened. Immutability ensures that once a value is validated, it stays that way. 👉 3. Thread Safety Because a String cannot change, it is inherently thread-safe. You can share a single string across multiple threads without worrying about synchronization or data corruption. This significantly simplifies concurrent programming in Java. 👉 4. Caching HashCodes In Java, strings are frequently used as keys in HashMap or elements in HashSet. The hashCode() of a string is calculated and cached the first time it's called. Since the string is immutable, the hash code will never change. This makes lookups in collections incredibly fast, as the JVM doesn't have to re-calculate the hash every time the string is accessed. #String #Immutability #HashCodes
To view or add a comment, sign in
-
-
Top 5 Causes of Memory Leaks in Java 🚀 Memory leaks in Java may not cause immediate crashes, but they can significantly degrade performance over time. These leaks occur when objects are no longer needed but are still referenced, preventing Garbage Collection from cleaning them up. The top causes of memory leaks in Java include: 1. Unused objects still referenced – Objects remain in memory due to active references. 2. Static collections – Data continues to grow because static variables persist for the entire application lifecycle. 3. Incorrect equals() and hashCode() – This can lead to duplicate entries in collections like HashMap. 4. Unclosed resources – Resources such as database connections, streams, or sessions are not properly closed. 5. Non-static inner classes – These classes hold implicit references to outer class objects. Understanding these causes can help developers write more efficient Java applications.
To view or add a comment, sign in
-
-
Core Java (Deep Concepts): 1️⃣ What happens internally in HashMap when two keys generate the same hash? Collision occurs. HashMap stores entries in buckets indexed by hash(key). Before Java 8: linked list. Java 8+: red-black tree if list grows beyond 8. equals() is checked for key match. 2️⃣ How does ConcurrentHashMap achieve thread safety? Fine-grained locking or CAS for writes. Reads mostly lock-free. Allows concurrent read/write without locking the entire map. 3️⃣ Difference between Synchronized Collections and Concurrent Collections: Synchronized: coarse-grained, single-thread access, e.g., Collections.synchronizedList. Concurrent: fine-grained, multiple threads can access, e.g., ConcurrentHashMap. 4️⃣ Volatile vs Synchronization: Volatile: ensures visibility only, no mutual exclusion. Synchronization: ensures visibility + mutual exclusion. 5️⃣ Explain Java Memory Model (JMM): Defines thread interactions via memory. Key concepts: main memory vs CPU cache, happens-before relationship, visibility with volatile, atomicity with synchronized. 6️⃣ Difference between Future and CompletableFuture: Future: waits for the result, limited. CompletableFuture: async, chaining, handles exceptions, supports multiple futures. 7️⃣ Parallel Streams: Executes operations in parallel via ForkJoinPool. Avoid when shared mutable state exists, small datasets, or ordering matters. 8️⃣ ClassLoader in Java: Loads class bytecode into JVM. Types: Bootstrap, Extension, System/Application, Custom. 9️⃣ Sealed Classes Allows developers to restrict which classes can extend or implement a class or interface, improving domain modeling and security. 🔟 What is a record in Java? A record is a special type of class used to model immutable data objects with very little boilerplate code. It automatically generates: constructor getters equals() hashCode() toString()
To view or add a comment, sign in
-
❗ Even Java record Don’t Make Maps Immutable It’s a common misconception that Java record automatically provides immutability for the fields. Actually, Java record doesn't make mutable objects (like Map, List, Set) immutable. 💡 Example: A Record with a Map @Builder public record Summary(Map<String, Address> addressMap) { } Then try this: var summary = Summary.builder() .addressMap(existingMap) .build(); var map = summary.addressMap(); map.put("newAddress", Address.builder().street("main").build()); // ❗ This works! ✔ No exception is thrown addressMap() simply returns the internal Map reference. Since Map is mutable, external code can still change the record’s internal state. This means: Records prevent reassignment, but they do not prevent mutation of contained objects. 🔒 How to Make the Map Truly Immutable To ensure callers can’t mutate your internal Map, you must explicitly defensively copy it. You can do this using the compact constructor as shown in the example, which runs after the canonical constructor is generated: @Builder public record Summary(Map<String, Address> addressMap) { public Summary { // Defensive copy to ensure immutability addressMap = (addressMap == null) ? Map.of() : Map.copyOf(addressMap); } } ✔ Why this works Map.copyOf(...) creates a new, unmodifiable map. Any attempt to modify the returned map will throw UnsupportedOperationException. Your record no longer exposes internal mutable state. var summary = Summary.builder() .addressMap(existingMap) .build(); summary.addressMap().put("x", someAddress); // → UnsupportedOperationException 📝 Summary Records do not make mutable fields immutable. final only protects references, not the objects they reference. If a record contains a Map, List, or Set, callers can mutate it unless you: Wrap it with Map.copyOf / List.copyOf / Set.copyOf The compact constructor is the cleanest way to enforce immutability in records. #Java #MyWorkExperience
To view or add a comment, sign in
More from this author
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