Skillversitas

Tips & Tricks

A collection of tips and best practices for writing clean, efficient, and easy-to-maintain Java code. These tips cover performance, readability, security, and everyday productivity.

String formatting with String.format() or text blocks is neater than concatenation. Effectively final (Java 8+) allows non-final local variables to be used in a lambda. Method references (::) are shorthand for simple lambdas. Optional (Java 8+) avoids NullPointerException in an elegant way.

Var (Java 10+) enables type inference for local variables. Switch expressions are safer and more compact than switch statements. Records replace boilerplate POJOs. The Streams API enables functional, parallel data processing pipelines.

Productivity Tips:

Tip Example
Use var to cut excessive verbosity var list = new ArrayList<String>()
Method reference instead of a lambda list.forEach(System.out::println)
Optional for null safety Optional.ofNullable(obj).orElse(default)
Text blocks for multi-line strings """Hello\nWorld"""
Switch expression without fall-through case "a" -> result = 1;
Records for data classes record Point(int x, int y) {}

Code Example

import java.util.*;
import java.util.stream.*;

public class TipsDanTrik {
    public static void main(String[] args) {
        // 1. var (type inference)
        var name = "Java";           // String
        var numbers = List.of(1, 2, 3); // List<Integer>
        var mapa = Map.of("a", 1);   // Map<String, Integer>

        // 2. Method references
        List.of("b", "a", "c").stream()
            .sorted()
            .forEach(System.out::println);

        // 3. Optional for null safety
        String input = null;
        String result = Optional.ofNullable(input)
            .filter(s -> !s.isBlank())
            .orElse("Default Value");
        System.out.println("Result: " + result);

        // 4. Stream pipeline
        List<Integer> numbersList = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        int evenCount = numbersList.stream()
            .filter(a -> a % 2 == 0)
            .mapToInt(Integer::intValue)
            .sum();
        System.out.println("Even count: " + evenCount);

        // 5. Collect to Map
        Map<String, Integer> wordLengths = List.of("hello", "world", "java")
            .stream()
            .collect(Collectors.toMap(
                s -> s,
                String::length
            ));
        System.out.println("Length: " + wordLengths);

        // 6. Pattern matching instanceof
        Object obj = 42;
        if (obj instanceof Integer i && i > 0) {
            System.out.println("Integer positif: " + i);
        }

        // 7. Effectively final for lambda
        String prefix = "DEBUG: "; // effectively final
        List.of("a", "b").forEach(s ->
            System.out.println(prefix + s));
    }
}

Code Explanation

  1. var: reduces verbosity without sacrificing type safety — the compiler determines the type from the expression on the right-hand side.
  2. Method reference: System.out::println is equivalent to x -> System.out.println(x) — more compact for lambdas that only call a single method.
  3. Optional: avoids repetitive if (x != null) checks. ofNullable() for input that may be null, filter() for validation, orElse() for a default value.
  4. Stream: the filter → map → collect pipeline processes data functionally. It can be parallelized with .parallel().
  5. Effectively final: the prefix variable does not need to be declared final — as long as its value is not changed after declaration, it can be used in a lambda.

Everyday Example

A collection of frequently used utility methods:

import java.util.*;
import java.util.stream.*;

public class JavaUtils {

    // Check whether a string is empty/null
    static boolean isBlank(String s) {
        return s == null || s.isBlank();
    }

    // Format a name: "john smith" → "John Smith"
    static String titleCase(String name) {
        return Arrays.stream(name.split("\\s+"))
            .map(w -> Character.toUpperCase(w.charAt(0)) + w.substring(1).toLowerCase())
            .collect(Collectors.joining(" "));
    }

    // Group a list by a classifier
    static <T, K> Map<K, List<T>> groupBy(List<T> list, java.util.function.Function<T, K> fn) {
        return list.stream().collect(Collectors.groupingBy(fn));
    }

    // Retry mechanism
    static <T> T retry(int maxAttempt, java.util.concurrent.Callable<T> action) throws Exception {
        for (int i = 0; i < maxAttempt; i++) {
            try {
                return action.call();
            } catch (Exception e) {
                if (i == maxAttempt - 1) throw e;
                Thread.sleep(1000L * (i + 1));
            }
        }
        throw new RuntimeException("Unreachable");
    }

    public static void main(String[] args) {
        System.out.println(titleCase("john smith")); // John Smith

        var fruits = List.of("apel", "mangga", "jeruk", "pisang", "mangga");
        var grouped = groupBy(fruits, String::length);
        System.out.println("By length: " + grouped);
    }
}

Summary

Modern Java is far more concise and expressive than older Java versions. Take advantage of var, method references, Optional, Records, and Streams for cleaner code. Always use the latest LTS (Java 21) to get all the latest features. Practice makes perfect — keep refactoring your old code with the new features!