Lesson Completion
Back to course

Performance Best Practices: Writing Efficient Java Code

Beginner
12 minutesβ˜…4.8Java

1. The Hook (The "Byte-Sized" Intro)

  • In a Nutshell: Performance optimization = measure first, optimize second. Premature optimization = root of evil (optimize without data).
  • Collections: ArrayList (fast access) vs LinkedList (fast insert), HashMap vs TreeMap.
  • Strings: Use StringBuilder in loops (not +).
  • Objects: Reuse expensive objects (ConnectionPool, DateFormat).
  • Profiling tools: JProfiler, VisualVM, JMH.
  • Golden rule: Profile β†’ identify hotspot β†’ optimize β†’ measure improvement. Readable code > clever code!

Think of driving. Profiling = GPS speed analysis (find slow sections). Premature optimization = buying race car for city streets (unnecessary). String concatenation = stopping car repeatedly vs cruise control. Object pooling = reuse rental car vs buy new each trip!


2. Conceptual Clarity (The "Simple" Tier)

πŸ’‘ The Analogy

  • Profiling: Health checkup (find actual problems)
  • Premature Optimization: Worry about wrinkles at age 10
  • StringBuilder: Shopping list (add items efficiently)
  • Object Pooling: Library books (borrow, return, reuse)

3. Technical Mastery (The "Deep Dive")

java
// =========================================== // 1. PREMATURE OPTIMIZATION (DON'T DO THIS!) // =========================================== // ❌ BAD: Optimizing without measuring class DataProcessor { // Complex object pool, caching, bit manipulation... // But is this even a bottleneck? } // βœ… GOOD: Simple first, profile, then optimize class DataProcessor { void process(List<Data> data) { for (Data d : data) { transform(d); } } } // If slow, profile β†’ identify bottleneck β†’ optimize THAT part // =========================================== // 2. COLLECTION PERFORMANCE // =========================================== // ArrayList vs LinkedList // βœ… ArrayList: Random access O(1), insert O(n) List<String> arrayList = new ArrayList<>(); arrayList.get(1000); // Fast: O(1) arrayList.add(5, "x"); // Slow: O(n) - shift elements // βœ… LinkedList: Random access O(n), insert O(1) List<String> linkedList = new LinkedList<>(); linkedList.get(1000); // Slow: O(n) - traverse linkedList.add(5, "x"); // Fast: O(1) - adjust pointers // Rule: Use ArrayList unless you need frequent inserts/deletes // Initial capacity (avoid resizing) // ❌ BAD: Grows multiple times List<String> list = new ArrayList<>(); // Capacity 10 for (int i = 0; i < 10000; i++) { list.add("item"); // Resizes many times! } // βœ… GOOD: Pre-allocate List<String> list = new ArrayList<>(10000); // Capacity 10000 for (int i = 0; i < 10000; i++) { list.add("item"); // No resizing! } // HashMap vs TreeMap // βœ… HashMap: O(1) operations, no order Map<String, Integer> hashMap = new HashMap<>(); hashMap.put("key", 1); // O(1) // βœ… TreeMap: O(log n) operations, sorted Map<String, Integer> treeMap = new TreeMap<>(); treeMap.put("key", 1); // O(log n) // Rule: Use HashMap unless you need sorted keys // =========================================== // 3. STRING HANDLING // =========================================== // ❌ BAD: String concatenation in loop String result = ""; for (int i = 0; i < 10000; i++) { result += "item"; // Creates 10000 String objects! } // O(nΒ²) - each + creates new String // βœ… GOOD: StringBuilder StringBuilder sb = new StringBuilder(); for (int i = 0; i < 10000; i++) { sb.append("item"); // Efficient: O(n) } String result = sb.toString(); // String.format vs concatenation // ❌ Slower (but more readable) String msg = String.format("Hello, %s! You have %d messages", name, count); // βœ… Faster (but less readable) String msg = "Hello, " + name + "! You have " + count + " messages"; // Rule: Use StringBuilder for loops, + for simple concat // =========================================== // 4. OBJECT CREATION // =========================================== // Reuse expensive objects // ❌ BAD: Create every time public String formatDate(Date date) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // Expensive! return sdf.format(date); } // βœ… GOOD: Reuse (but careful - SimpleDateFormat not thread-safe!) private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // Thread-safe! public String formatDate(LocalDate date) { return FORMATTER.format(date); } // Static factory methods (can cache) // βœ… Integer caching (-128 to 127) Integer a = Integer.valueOf(127); Integer b = Integer.valueOf(127); System.out.println(a == b); // true (cached!) Integer c = Integer.valueOf(128); Integer d = Integer.valueOf(128); System.out.println(c == d); // false (not cached) // =========================================== // 5. LOOP OPTIMIZATION // =========================================== // ❌ BAD: Recalculate in every iteration for (int i = 0; i < list.size(); i++) { // size() called every iteration! process(list.get(i)); } // βœ… GOOD: Hoist invariant code int size = list.size(); // Calculate once for (int i = 0; i < size; i++) { process(list.get(i)); } // βœ… BETTER: Enhanced for-loop (simplest) for (Item item : list) { process(item); } // Stream API (may be slower for small collections) // Sometimes slower due to overhead list.stream().forEach(this::process); // Benchmark before using streams for performance-critical code! // =========================================== // 6. PROFILING // =========================================== // Use JMH for microbenchmarks @Benchmark public void stringConcatenation() { String result = ""; for (int i = 0; i < 100; i++) { result += "item"; } } @Benchmark public void stringBuilder() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < 100; i++) { sb.append("item"); } } // Run: mvn clean install && java -jar target/benchmarks.jar

5. The Comparison & Decision Layer

ScenarioChoiceReason
Random accessArrayListO(1) vs LinkedList O(n)
Frequent insertsLinkedListO(1) vs ArrayList O(n)
String in loopStringBuilderAvoid O(nΒ²)
Need sorted keysTreeMapHashMap unordered
Small collectionFor-loopStream overhead

6. The "Interview Corner" (The Edge)

The "Killer" Interview Question: "Why is String concatenation in a loop slow?" Answer: Strings are immutable! Each + creates a NEW String object!

java
String s = ""; for (int i = 0; i < 3; i++) { s += "x"; // Creates: "", "x", "xx", "xxx" } // 3 iterations = 3 String objects created! // For n iterations = n String objects = O(n) space, O(nΒ²) time! // StringBuilder: mutates internal character array StringBuilder sb = new StringBuilder(); for (int i = 0; i < 3; i++) { sb.append("x"); // Modifies same object } // 1 StringBuilder object = O(n) space, O(n) time

Pro-Tips:

  1. Profile before optimizing:
bash
# VisualVM (JDK tool) jvisualvm # Java Flight Recorder java -XX:+FlightRecorder -XX:StartFlightRecording=duration=60s MyApp # Find hotspots β†’ optimize those first!
  1. JVM optimizations (JIT compiler):
java
// Small methods get inlined automatically int add(int a, int b) { return a + b; // JVM inlines this! } // Trust the JVMβ€”it's smart!

Topics Covered

Java Fundamentals

Tags

#java#programming#beginner-friendly

Last Updated

2025-02-01