Every Java language construct imports a set of change drivers into the code that uses it. A non-static inner class imports the enclosing instance's entire driver set. A lambda imports only what it explicitly closes over. A `record` bounds the driver set to its declared components. A sealed interface with pattern matching bounds it to the contract. The choice between constructs is therefore a structural question, not a style one: which construct bounds the driver set to what the situation actually requires? I wrote an article applying this lens to Java 25. It walks through non-static inner classes, static nested classes, lambdas, method references, anonymous classes, records, sealed interfaces with pattern matching, `Optional`, `Result`, and `enum` — and identifies, for each, the structural situation where the construct is the right choice and the situations where a lighter alternative exists. The underlying principle is the Independent Variation Principle (IVP): a module's driver set should contain exactly the drivers its elements genuinely vary with — no more, no fewer. Java's evolution since Java 8 has been a series of additions that narrow the gap between what constructs force you to couple to and what the situation requires. Reading the language history through this lens makes the direction visible. https://lnkd.in/exxXMez4
Yannick L.’s Post
More Relevant Posts
-
Java- Automatic Type Promotion of Primitives I am trying to explore and explain the concept of automatic type promotion of primitives using a simple code in java using two byte values: class TestAutomatictypepromotion{ public static void main(String[] ar){ byte a=10; byte b=20; int sum=a+b; System.out.println(sum); }} Perfect! Let me prove the byte → int promotion step by step through actual bytecode analysis.We have the real bytecode. Now let me build the full visual explanation. javac your souce code javap -c TestAutomatictypepromotion.class (we will get the vyte code) The 3 smoking-gun proofs from the actual bytecode Here is the raw javap -c output from your exact code, with the proof highlighted: 0: bipush 10 ← pushes 10 as INT (not byte) 2: istore_1 ← "i" = integer store (no bstore exists!) 3: bipush 20 ← pushes 20 as INT 5: istore_2 ← integer store 6: iload_1 ← "i" = integer load (no bload exists!) 7: iload_2 ← integer load 8: iadd ← "i" = INTEGER add ← THE KEY PROOF 9: istore_3 Proof 1 — iload, not bload: When a and b are loaded from local variable slots, the opcode is iload_1 and iload_2. The i prefix means integer. There is literally no bload instruction in the entire JVM specification. Proof 2 — iadd, not badd: The addition uses iadd. There is no badd opcode. The JVM arithmetic instruction set only has iadd, ladd, fadd, dadd (int, long, float, double). Bytes have no dedicated add — they must become ints first. Proof 3 — println:(I)V: The method descriptor in constant pool entry #13 is println:(I)V. The I is the JVM type descriptor for int. So even println receives an int, not a byte. Why does Java do this? The JVM's operand stack and local variable slots work natively in 32-bit units. Byte, short, char, and boolean values are all widened to int the moment they enter the stack — this is called numeric promotion. It's defined in the JLS §5.6.1 (Unary Numeric Promotion) and §5.6.2 (Binary Numeric Promotion). The JVM spec simply has no byte-level arithmetic opcodes — they were intentionally omitted to keep the instruction set small and the stack 32-bit aligned. Want me to show what happens when the result overflows a byte, or demonstrate why byte c = a + b causes a compile-time error without an explicit cast: Let me cover both — byte overflow AND the compile-time error proof through actual bytecode! byte data type has a range: -128 to 127 Assume we declare the variables llike : byte b=100.byte b=100; then try to add both (byte values) like byte c=a+b; The result :200 is not in byte range. So overflow happens. Compiler will not allow. The compiled and interpreted way in Java is the base for such standard code. Most developers fear the JVM. Java developers understand it. Codeest Software Factory Anirudh Mangore Sandip Magdum Mehvish Fansopkar Mitali Dere Sakshi Randive Shruti Chavan NILESH GHAVATE Shaikh Abdulkhadir Java Recruiting Group,OpenJDK
To view or add a comment, sign in
-
Small concept. Big impact. In Java: byte + byte = int That’s automatic type promotion — and it’s one of those things that silently causes bugs if you don’t fully understand it. Back to basics = better code.
Java- Automatic Type Promotion of Primitives I am trying to explore and explain the concept of automatic type promotion of primitives using a simple code in java using two byte values: class TestAutomatictypepromotion{ public static void main(String[] ar){ byte a=10; byte b=20; int sum=a+b; System.out.println(sum); }} Perfect! Let me prove the byte → int promotion step by step through actual bytecode analysis.We have the real bytecode. Now let me build the full visual explanation. javac your souce code javap -c TestAutomatictypepromotion.class (we will get the vyte code) The 3 smoking-gun proofs from the actual bytecode Here is the raw javap -c output from your exact code, with the proof highlighted: 0: bipush 10 ← pushes 10 as INT (not byte) 2: istore_1 ← "i" = integer store (no bstore exists!) 3: bipush 20 ← pushes 20 as INT 5: istore_2 ← integer store 6: iload_1 ← "i" = integer load (no bload exists!) 7: iload_2 ← integer load 8: iadd ← "i" = INTEGER add ← THE KEY PROOF 9: istore_3 Proof 1 — iload, not bload: When a and b are loaded from local variable slots, the opcode is iload_1 and iload_2. The i prefix means integer. There is literally no bload instruction in the entire JVM specification. Proof 2 — iadd, not badd: The addition uses iadd. There is no badd opcode. The JVM arithmetic instruction set only has iadd, ladd, fadd, dadd (int, long, float, double). Bytes have no dedicated add — they must become ints first. Proof 3 — println:(I)V: The method descriptor in constant pool entry #13 is println:(I)V. The I is the JVM type descriptor for int. So even println receives an int, not a byte. Why does Java do this? The JVM's operand stack and local variable slots work natively in 32-bit units. Byte, short, char, and boolean values are all widened to int the moment they enter the stack — this is called numeric promotion. It's defined in the JLS §5.6.1 (Unary Numeric Promotion) and §5.6.2 (Binary Numeric Promotion). The JVM spec simply has no byte-level arithmetic opcodes — they were intentionally omitted to keep the instruction set small and the stack 32-bit aligned. Want me to show what happens when the result overflows a byte, or demonstrate why byte c = a + b causes a compile-time error without an explicit cast: Let me cover both — byte overflow AND the compile-time error proof through actual bytecode! byte data type has a range: -128 to 127 Assume we declare the variables llike : byte b=100.byte b=100; then try to add both (byte values) like byte c=a+b; The result :200 is not in byte range. So overflow happens. Compiler will not allow. The compiled and interpreted way in Java is the base for such standard code. Most developers fear the JVM. Java developers understand it. Codeest Software Factory Anirudh Mangore Sandip Magdum Mehvish Fansopkar Mitali Dere Sakshi Randive Shruti Chavan NILESH GHAVATE Shaikh Abdulkhadir Java Recruiting Group,OpenJDK
To view or add a comment, sign in
-
[Post #37] | JVM | Garbage Collection in Java — What It Actually Is Hey folks! 👋 Most developers think Garbage Collection just “frees memory automatically.” That shallow understanding is exactly why memory leaks and performance issues go unnoticed. Here’s the real truth: Garbage Collection (GC) is not just cleanup. It’s a JVM mechanism to manage memory efficiently, predictably, and without stopping your application unnecessarily. Break it down clearly: 1. JVM memory is divided into generations • Young Generation (Eden + Survivor) → short-lived objects • Old Generation → long-lived objects GC behavior depends heavily on this structure. 2. Minor GC vs Major GC • Minor GC → fast, frequent, cleans Young Gen • Major (Full) GC → slow, expensive, cleans Old Gen Frequent Full GC = serious problem. 3. GC is based on reachability, not null checks Objects are collected only if they are not reachable from GC Roots (stack, static references, etc.) Setting obj = null doesn’t guarantee immediate cleanup. 4. Stop-The-World (STW) pauses exist During GC, application threads may pause. Bad GC tuning → noticeable latency spikes. 5. Different collectors exist for different needs • G1 (default) → balanced, predictable • ZGC / Shenandoah → ultra-low latency • CMS (deprecated) → older concurrent model Choosing the wrong GC can kill performance. Why this actually matters: • Prevent memory leaks • Avoid latency spikes • Improve throughput • Handle high-load systems efficiently • Critical for microservices & large-scale systems One-sentence summary: => Garbage Collection is not about freeing memory. It’s about managing application performance under memory pressure.
To view or add a comment, sign in
-
Java Is Not As Simple As We Think. We’re taught that Java is predictable and straightforward. But does it always behave the way we expect? Here are 3 subtle behaviors that might surprise you. Q1: Which method gets called? You have a method overloaded with int and long. What happens when you pass a literal? public void print(int i) { System.out.println("int"); } public void print(long l) { System.out.println("long"); } print(10); It prints "int". But what if you comment out the int version? You might expect an error, but Java automatically "widens" the int to a long. However, if you change them to Integer and Long (objects), Java will not automatically widen them. The rules for primitives vs. objects are completely different. Q2: Is 0.1 + 0.2 really 0.3? In a financial application, you might try this: double a = 0.1; double b = 0.2; System.out.println(a + b == 0.3); // true or false? It prints false. In fact, it prints 0.30000000000000004. The Reason: Java (and most languages) uses IEEE 754 floating-point math, which cannot represent certain decimals precisely in binary. This is why for any precise calculation, BigDecimal is the only safe choice. Q3: Can a static variable "see" the future? Look at the order of initialization here: public class Mystery { public static int X = Y + 1; public static int Y = 10; public static void main(String[] args) { System.out.println(X); // 11 or 1? } } It prints 1. The Reason: Java initializes static variables in the order they appear. When X is calculated, Y hasn't been assigned 10 yet, so it uses its default value of 0. A simple reordering of lines changes your entire business logic. The takeaway: Java is not a simple language. Even professionals with years of experience get tripped up by its subtle behaviors and exceptions to the rules. The language rewards curiosity and continuous learning — no matter how senior you are. Keep revisiting the fundamentals. They have more depth than you remember. #Java #SoftwareEngineering #Coding #JVM #ProgrammingTips
To view or add a comment, sign in
-
Java Method Overloading I was revising notes on method overloading, and it reminded me how easy it is to memorize definitions… but miss the real mechanics behind it. Let’s break it down in a way that actually sticks What the Compiler Actually Uses When Java resolves an overloaded method, it ONLY looks at: ✔️ Method name ✔️ Number of parameters ✔️ Data types of parameters ✔️ Order (sequence) of parameters This combination is called the method signature ❌ Return type is completely ignored What is “Overload Resolution”? It’s the process where the compiler decides which method to call from multiple overloaded methods. Important: This decision happens at compile time, not runtime That’s why method overloading is also called: Compile-time polymorphism Static polymorphism Early binding Static binding Real Understanding (From Notes → Reality) “Compiler binds method call with method body during compilation” Let’s make that practical: void add(int x, int y) { } void add(int x, float y) { } void add(float x, float y) { } add(10.5f, 20.5f); 👉 Compiler instantly picks: add(float, float) ✔️ Decision made at compile time ✔️ Execution happens later at runtime ⚡ Where Most People Go Wrong Many think: “Return type helps differentiate methods” ❌ Wrong. int add(int a, int b) { return 0; } double add(int a, int b) { return 0; } // ❌ Error 👉 Same signature → Compilation Error The Hidden Rule When multiple methods match, Java follows priority: 1️⃣ Exact match 2️⃣ Widening 3️⃣ Autoboxing 4️⃣ Varargs If two methods fall at same level → ❌ Compilation Error The Illusion “It creates an illusion that one method performs multiple activities” In reality: Methods are different Only the name is same Each method handles a specific case Overloading improves readability, not magic Reference For deeper understanding of invalid cases: 🔗 https://lnkd.in/gD3W_efG Thanks to PW Institute of Innovation and my mentor Syed Zabi Ulla sir for helping me truly understand how Java thinks under the hood. Your guidance made these concepts much clearer and interview-ready. 🚨 One-Line Truth Method overloading is not about flexibility at runtime — it’s about clarity and compile-time precision #Java #Programming #SoftwareEngineering #CodingInterview #FAANG #JavaDeveloper #TechLearning
To view or add a comment, sign in
-
-
One of the most valuable lessons from “The New Java Best Practices” by Stephen Colebourne was about Java Records and it goes far beyond reducing boilerplate. Many developers think Records are simply a shorter way to write DTOs. But the real message is this: A Record should model immutable, trustworthy data. Modern Java gives us record to clearly express intent: this object is a transparent carrier of values. Key best practices for Records: 1.All fields should be immutable Not just primitives and Strings even Lists, Maps, and nested objects should be immutable. final List<String> is not enough if the list itself can still change. 2. Prefer basic types and other Records Compose records using primitives, enums, Strings, and other immutable records for safer design. 3.Use the constructor for validation Ensure invalid objects can never be created. Examples: blank username negative amount invalid age 4.Trust generated methods Records automatically provide equals(), hashCode(), and toString(). Avoid overriding them unless there is a strong reason. 5. Be careful with toString() Generated toString() may expose sensitive values like passwords, tokens, or PII in logs. 6. Avoid arrays and mutable fields Arrays, mutable collections, and mutable references go against the core principle of records. Biggest takeaway: A Record with mutable internals is only syntactically modern not architecturally modern. Modern Java is not just about using new features. It is about using them with the right design mindset. Where Records shine: ✔ API request/response models ✔ Event payloads (Kafka, messaging) ✔ Value objects ✔ Read-only projections ✔ Configuration snapshots Where to think twice: ✖ JPA entities ✖ Stateful domain objects ✖ Objects requiring mutation-heavy lifecycle Java has evolved. The question is: Have our design habits evolved with it? #Java #SoftwareEngineering #CleanCode #BackendDevelopment #JavaDeveloper #Architecture #Programming #ModernJava #TechLeadership
To view or add a comment, sign in
-
Think var in Java is just about saving keystrokes? Think again. When Java introduced var, it wasn’t just syntactic sugar — it was a shift toward cleaner, more readable code. So what is var? var allows the compiler to automatically infer the type of a local variable based on the assigned value. Instead of writing: String message = "Hello, Java!"; You can write: var message = "Hello, Java!"; The type is still strongly typed — it’s just inferred by the compiler. Why developers love var: Cleaner Code – Reduces redundancy and boilerplate Better Readability – Focus on what the variable represents, not its type Modern Java Practice – Aligns with newer coding standards But here’s the catch: Cannot be used without initialization Only for local variables (not fields, method params, etc.) Overuse can reduce readability if the type isn’t obvious Not “dynamic typing” — Java is still statically typed Pro Insight: Use var when the type is obvious from the right-hand side — avoid it when it makes the code ambiguous. Final Thought: Great developers don’t just write code — they write code that communicates clearly. var is a tool — use it wisely, and your code becomes not just shorter, but smarter. Special thanks to Syed Zabi Ulla and PW Institute of Innovation for continuous guidance and learning support. #Java #Programming
To view or add a comment, sign in
-
-
I use both Python and Java, and when working with LLMs I have noticed a meaningful difference. Java, especially together with Spring, often requires more code, configuration, and infrastructure scaffolding. In traditional enterprise development, this can be fully justified: strong structure, a mature ecosystem, well-established patterns, and production-grade reliability. But when working with LLMs, a new factor emerges: language noise starts to cost tokens. When a model works with code, every additional class, DTO, annotation, generic, mapper, or abstraction layer takes up space in the context window. As a result, part of the LLM’s attention is spent not on the actual intent of the task, but on the technical packaging around it. In these scenarios, Python often feels more compact. It is easier to fit more substance into the context: business logic, prompts, model calls, result processing, and test examples. This makes experimentation faster and makes it easier to reason about code together with an LLM. This does not mean that Java is worse, or that Python is always cheaper. Java remains very strong in enterprise, high-load, and large-scale production systems. But in LLM-driven development, a new criterion is emerging for technology choices: how easily the code can be understood by the model, and how much context it consumes. Developers are reading code line by line less often. Increasingly, they look at intent, diffs, tests, and the output of agents. That is why programming languages and frameworks will likely adapt faster to this new reality.
To view or add a comment, sign in
-
Records in Java — Say Goodbye to Boilerplate Code Writing simple data classes in Java used to mean creating: fields constructors getters equals() hashCode() toString() A lot of code… just to store data. With Records (introduced in Java), Java made this much simpler. Instead of writing this: class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } You can simply write: record Person(String name, int age) {} And Java automatically generates: 1. Constructor 2. Getter methods (name(), age()) 3. equals() 4. hashCode() 5. toString() Why Records matter? 1. Less boilerplate code 2. Immutable by default 3. Cleaner and more readable code 4. Perfect for DTOs, API requests/responses, and model classes Example: record Employee(String name, String department, double salary) {} Usage: Employee emp = new Employee("John", "Engineering", 90000); System.out.println(emp.name()); Records become even more powerful with modern Java features like Sealed Classes: sealed interface Shape permits Circle, Rectangle {} record Circle(double radius) implements Shape {} record Rectangle(double length, double width) implements Shape {} Modern Java is getting cleaner, safer, and more expressive. In one line: Records = Less code, more clarity. #Java #Java17 #JavaDeveloper #BackendDevelopment #Programming #SoftwareEngineering #Coding
To view or add a comment, sign in
-
What’s ‘Static’ in Java? Why to use it? Static, as in fixed. Applying it to Object-Oriented tech - something that doesn’t change for every object, it’s fixed for all objects. Generally fields are created separately in memory for each instance of a class, i.e. Object variables. But, anything declared using static keyword belongs to the class instead of individual instances (objects). What does it mean? That every object of this class share this same copy of the variable, method, etc. We can apply static keyword with variables, methods, blocks and nested class. The benefit – memory management of course. public class Student{ private String Name; //Object variable private int Age; //Object variable private String StudentId; //Object variable public static int NumberOfStudents = 0; //Class variable public Student(String name, int age, String studentId) { this.Name = name; this.Age = age; this.StudentId = studentId; NumberOfStudents++; //Increase the no of students whenever an object is created. } } The most common example is << public static void main(String args[]) >> declared static because it must be called before any object exists. Making a method static in Java is an important decision. Does it make sense to call a method/variable, even if no object has been constructed yet? If so, it should be static. Static entity, • Will be initialized first, before any class objects are created. • Is accessed directly by the class name and doesn’t need any object. • Can access only static data. It cannot access non-static data (instance variables). • Can call only other static methods and cannot call a non-static method. Caution: Generally, it is bad practice to set the WebDriver instance as static. Instead create a base class that each test classes extend so that each test class has its own instance of WebDriver to be used (this is especially important with parallel execution), then just declare/define your WebDriver variable within the base class.
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