Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
22: The var Keyword for Local Type Inference
For years, Java had a reputation for being "verbose." If you've been following along with the course, you've probably felt this. We've spent a lot of time writing things like List<UserAccount> users = new ArrayList<>();. It's clear, sure, but it's repetitive. You're essentially saying "this is a list of users" twice in one line.
That's why Java introduced the var keyword. It allows for local variable type inference. Basically, you're telling the compiler, "You're smart enough to look at the right side of the equals sign and figure out the type for me."
Cleaning up the noise in a Loyalty Tracker
Let's build a quick little utility that tracks loyalty points for customers. I want to store a map where the key is the customer's name and the value is a list of their individual transaction amounts. Traditionally, that declaration is a nightmare to look at.
public void processLoyaltyPoints() {
// The old, verbose way
Map<String, List<Integer>> customerTransactions = new HashMap<>();
customerTransactions.put("Alice", new ArrayList<>());
customerTransactions.get("Alice").add(100);
customerTransactions.get("Alice").add(50);
}
Now, let's use var. Since the compiler sees new HashMap<>(), it knows exactly what customerTransactions is. I don't need to repeat the generics.
public void processLoyaltyPoints() {
// Much cleaner
var customerTransactions = new HashMap<String, List<Integer>>();
customerTransactions.put("Alice", new ArrayList<>());
customerTransactions.get("Alice").add(100);
}
Notice that I still put the generics on the right side. If I just wrote var map = new HashMap();, Java would infer it as a raw HashMap, and I'd be back to dealing with Object types and compiler warnings. The goal is to remove redundancy, not type safety.
Wait, why isn't this compiling?
As I was sketching this out, I tried to move the customerTransactions map outside the method so it could be shared across the whole class. I did something like this:
public class LoyaltyService {
var customerTransactions = new HashMap<String, List<Integer>>(); // Error here!
public void process() {
// ...
}
}
And immediately, the IDE started screaming at me. Here is the most important rule about var: it only works for local variables.
You cannot use var for class fields, method parameters, or return types. Why? Because Java wants the "public contract" of your class to be explicit. If another developer uses your LoyaltyService, they shouldn't have to guess what the type of a field is by tracing the initialization logic. I had to move it back inside the method or give it an explicit type if I wanted it as a field.
Knowing when to keep the explicit type
Just because you can use var everywhere doesn't mean you should. I've seen some developers treat it like JavaScript, where every single variable is var. That makes the code a riddle.
Take a look at this:
var result = database.fetchRecords();
If I'm reading this code for the first time, I have no idea what result is. Is it a List? A ResultSet? A custom QueryResponse object? In this case, the "verbosity" of an explicit type is actually a feature—it's documentation. I generally use var when the type is obvious from the constructor (like new ArrayList<>()) or when the variable name makes the type crystal clear (like var userList = ...).
📋 Practical Task
Refactoring the Inventory Report Generator
You are reviewing a piece of code for a warehouse system. The current implementation is cluttered with redundant type declarations, and one developer mistakenly tried to use var where it isn't allowed.
Your task:
- Fix the compilation error by providing an explicit type for the class field.
- Refactor the local variables inside the
generateReportmethod to usevarwhere it improves readability without sacrificing clarity.
import java.util.*;
public class InventoryReport {
// TASK 1: Fix this line. var cannot be used for fields.
var inventoryMap = new HashMap<String, Integer>();
public void generateReport() {
// TASK 2: Refactor these local variables to use var
List<String> itemNames = new ArrayList<>();
itemNames.add("Widget");
itemNames.add("Gadget");
Map<String, Integer> stockLevels = new HashMap<>();
stockLevels.put("Widget", 10);
stockLevels.put("Gadget", 20);
System.out.println("Report generated for " + itemNames.size() + " items.");
}
}There are no comments for now.