When implementing equals(), hashCode(), or handling potentially null values, manual null checks are error-prone and verbose. The Objects utility class provides null-safe methods for these common operations, making defensive programming cleaner and more reliable.

Null-Safe Equality

Compare objects without risking NullPointerException.

Equals.java
// Objects.equals examples

import java.util.Objects;

public class Equals {
    public static void main(String[] args) {
        System.out.println("Basic equals:");

        String s1 = "hello";
        String s2 = "hello";
        String s3 = "world";
        String s4 = null;

        System.out.println("s1.equals(s2): " + s1.equals(s2));
        System.out.println("Objects.equals(s1, s2): " + Objects.equals(s1, s2));
        System.out.println("Objects.equals(s1, s3): " + Objects.equals(s1, s3));
        System.out.println("\nNull-safe equals:");

        System.out.println("Objects.equals(s1, null): " + Objects.equals(s1, null));
        System.out.println("Objects.equals(null, s1): " + Objects.equals(null, s1));
        System.out.println("Objects.equals(null, null): " + Objects.equals(null, null));

        // This would throw NullPointerException:
        // System.out.println(s4.equals(s1));
        System.out.println("\nDeep equals:");

        int[] arr1 = {1, 2, 3};
        int[] arr2 = {1, 2, 3};
        int[] arr3 = arr1;

        System.out.println("arr1 == arr2: " + (arr1 == arr2));
        System.out.println("arr1.equals(arr2): " + arr1.equals(arr2));
        System.out.println("Objects.equals(arr1, arr2): " + Objects.equals(arr1, arr2));
        System.out.println("Objects.deepEquals(arr1, arr2): " + Objects.deepEquals(arr1, arr2));
        System.out.println("Objects.deepEquals(arr1, arr3): " + Objects.deepEquals(arr1, arr3));
        System.out.println("\nCustom class equals:");

        Person p1 = new Person("Alice", 30);
        Person p2 = new Person("Alice", 30);
        Person p3 = new Person("Bob", 25);
        Person p4 = null;

        System.out.println("p1.equals(p2): " + p1.equals(p2));
        System.out.println("Objects.equals(p1, p2): " + Objects.equals(p1, p2));
        System.out.println("Objects.equals(p1, p3): " + Objects.equals(p1, p3));
        System.out.println("Objects.equals(p1, null): " + Objects.equals(p1, null));
        System.out.println("Objects.equals(null, null): " + Objects.equals(null, null));
        System.out.println("\nComparing arrays:");

        String[] names1 = {"Alice", "Bob"};
        String[] names2 = {"Alice", "Bob"};

        System.out.println("Arrays equal (==): " + (names1 == names2));
        System.out.println("Arrays equal (equals): " + names1.equals(names2));
        System.out.println("Arrays equal (Objects.equals): " + Objects.equals(names1, names2));
        System.out.println("Arrays equal (Objects.deepEquals): " + Objects.deepEquals(names1, names2));
        System.out.println("\n2D arrays:");

        int[][] matrix1 = {{1, 2}, {3, 4}};
        int[][] matrix2 = {{1, 2}, {3, 4}};

        System.out.println("Matrix equal (Objects.equals): " + Objects.equals(matrix1, matrix2));
        System.out.println("Matrix equal (Objects.deepEquals): " + Objects.deepEquals(matrix1, matrix2));
        System.out.println("\nIn collections:");

        java.util.List<String> list1 = java.util.Arrays.asList("a", "b", "c");
        java.util.List<String> list2 = java.util.Arrays.asList("a", "b", "c");
        java.util.List<String> list3 = null;

        System.out.println("Lists equal: " + Objects.equals(list1, list2));
        System.out.println("List vs null: " + Objects.equals(list1, null));
        System.out.println("Null lists: " + Objects.equals(list3, null));
    }

    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            Person other = (Person) obj;
            return age == other.age && Objects.equals(name, other.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    }
}
Objects class A utility class in java.util providing null-safe static methods for common object operations.
Null-safe comparison Objects.equals(a, b) handles null values gracefully, returning true if both are null and false if only one is null.

Hash Code Generation

Generate consistent hash codes for multiple fields.

Hash.java
// Objects.hash examples

import java.util.Objects;
import java.util.Arrays;

public class Hash {
    public static void main(String[] args) {
        System.out.println("Basic hash:");

        String s1 = "hello";
        String s2 = "world";

        System.out.println("s1.hashCode(): " + s1.hashCode());
        System.out.println("Objects.hashCode(s1): " + Objects.hashCode(s1));
        System.out.println("Objects.hashCode(null): " + Objects.hashCode(null));
        System.out.println("\nMultiple values:");

        int hash1 = Objects.hash("Alice", 30);
        int hash2 = Objects.hash("Alice", 30);
        int hash3 = Objects.hash("Bob", 30);
        int hash4 = Objects.hash("Alice", 25);

        System.out.println("hash('Alice', 30): " + hash1);
        System.out.println("hash('Alice', 30): " + hash2);
        System.out.println("Same? " + (hash1 == hash2));
        System.out.println("hash('Bob', 30): " + hash3);
        System.out.println("hash('Alice', 25): " + hash4);
        System.out.println("\nCustom class:");

        Person p1 = new Person("Alice", 30);
        Person p2 = new Person("Alice", 30);
        Person p3 = new Person("Bob", 25);

        System.out.println("p1.hashCode(): " + p1.hashCode());
        System.out.println("p2.hashCode(): " + p2.hashCode());
        System.out.println("p3.hashCode(): " + p3.hashCode());
        System.out.println("p1 == p2 hashCode? " + (p1.hashCode() == p2.hashCode()));
        System.out.println("\nIn HashMap:");

        java.util.Map<Person, String> map = new java.util.HashMap<>();

        map.put(new Person("Alice", 30), "Engineer");
        map.put(new Person("Bob", 25), "Designer");

        System.out.println("Get Alice: " + map.get(new Person("Alice", 30)));
        System.out.println("Get Bob: " + map.get(new Person("Bob", 25)));
        System.out.println("\nHash with nulls:");

        int h1 = Objects.hash("Alice", null, 30);
        int h2 = Objects.hash("Alice", null, 30);
        int h3 = Objects.hash(null, null, null);

        System.out.println("hash('Alice', null, 30): " + h1);
        System.out.println("hash('Alice', null, 30): " + h2);
        System.out.println("Same? " + (h1 == h2));
        System.out.println("hash(null, null, null): " + h3);
        System.out.println("\nPoint class:");

        Point pt1 = new Point(10, 20);
        Point pt2 = new Point(10, 20);
        Point pt3 = new Point(20, 10);

        System.out.println("pt1: " + pt1 + " hash=" + pt1.hashCode());
        System.out.println("pt2: " + pt2 + " hash=" + pt2.hashCode());
        System.out.println("pt3: " + pt3 + " hash=" + pt3.hashCode());
        System.out.println("\nHashSet usage:");

        java.util.Set<Point> points = new java.util.HashSet<>();
        points.add(new Point(1, 2));
        points.add(new Point(3, 4));
        points.add(new Point(1, 2));  // Duplicate

        System.out.println("Set size: " + points.size());
        System.out.println("Contains (1,2)? " + points.contains(new Point(1, 2)));
        System.out.println("\nRecord class:");

        Rectangle r1 = new Rectangle(10, 20);
        Rectangle r2 = new Rectangle(10, 20);
        Rectangle r3 = new Rectangle(20, 10);

        System.out.println("r1 hash: " + r1.hashCode());
        System.out.println("r2 hash: " + r2.hashCode());
        System.out.println("r3 hash: " + r3.hashCode());
        System.out.println("r1.equals(r2)? " + r1.equals(r2));
    }

    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            Person other = (Person) obj;
            return age == other.age && Objects.equals(name, other.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    }

    static class Point {
        int x, y;

        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (!(obj instanceof Point)) return false;
            Point other = (Point) obj;
            return x == other.x && y == other.y;
        }

        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }

        @Override
        public String toString() {
            return "(" + x + "," + y + ")";
        }
    }

    static class Rectangle {
        int width, height;

        Rectangle(int width, int height) {
            this.width = width;
            this.height = height;
        }

        @Override
        public boolean equals(Object obj) {
            if (!(obj instanceof Rectangle)) return false;
            Rectangle r = (Rectangle) obj;
            return width == r.width && height == r.height;
        }

        @Override
        public int hashCode() {
            return Objects.hash(width, height);
        }
    }
}
Combined hash Objects.hash() combines multiple fields into a single hash code, ideal for implementing hashCode() in classes with multiple fields.

Null Validation

Enforce non-null requirements with clear error messages.

Require.java
// Objects.requireNonNull examples

import java.util.Objects;

public class Require {
    public static void main(String[] args) {
        System.out.println("Basic requireNonNull:");

        String valid = "hello";
        String invalid = null;

        String result = Objects.requireNonNull(valid);
        System.out.println("Valid: " + result);

        try {
            Objects.requireNonNull(invalid);
        } catch (NullPointerException e) {
            System.out.println("Caught NPE: " + e.getMessage());
        }
        System.out.println("\nWith message:");

        try {
            Objects.requireNonNull(null, "Value must not be null");
        } catch (NullPointerException e) {
            System.out.println("Message: " + e.getMessage());
        }
        System.out.println("\nConstructor validation:");

        try {
            Person p1 = new Person("Alice", 30);
            System.out.println("Created: " + p1);

            Person p2 = new Person(null, 25);
        } catch (NullPointerException e) {
            System.out.println("Constructor failed: " + e.getMessage());
        }
        System.out.println("\nMethod parameters:");

        EmailSender sender = new EmailSender();

        try {
            sender.send("user@example.com", "Hello", "Welcome!");
            System.out.println("Email sent successfully");
        } catch (NullPointerException e) {
            System.out.println("Failed: " + e.getMessage());
        }

        try {
            sender.send(null, "Hello", "Welcome!");
        } catch (NullPointerException e) {
            System.out.println("Failed: " + e.getMessage());
        }
        System.out.println("\nSupplier message:");

        String userId = ;

        try {
            Objects.requireNonNull(userId, () ->
                "User ID is required but was null in this request");
            System.out.println("User ID: " + userId);
        } catch (NullPointerException e) {
            System.out.println("Lazy message: " + e.getMessage());
        }
        System.out.println("\nChain validation:");

        Config config = new Config("localhost", 8080, "/api");
        System.out.println("Config: " + config);

        try {
            new Config(null, 8080, "/api");
        } catch (NullPointerException e) {
            System.out.println("Host required: " + e.getMessage());
        }
        System.out.println("\nReturn value validation:");

        UserService service = new UserService();

        User user = service.findUser("alice");
        System.out.println("Found: " + user);

        try {
            service.findUser("unknown");
        } catch (NullPointerException e) {
            System.out.println("Not found: " + e.getMessage());
        }
        System.out.println("\nDefensive copy:");

        String[] items = {"a", "b", "c"};
        Container c1 = new Container(items);
        System.out.println("Container: " + c1);

        try {
            new Container(null);
        } catch (NullPointerException e) {
            System.out.println("Null array: " + e.getMessage());
        }
    }

    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = Objects.requireNonNull(name, "Name must not be null");
            this.age = age;
        }

        @Override
        public String toString() {
            return name + " (" + age + ")";
        }
    }

    static class EmailSender {
        void send(String to, String subject, String body) {
            Objects.requireNonNull(to, "Recipient must not be null");
            Objects.requireNonNull(subject, "Subject must not be null");
            Objects.requireNonNull(body, "Body must not be null");
            // Send email...
        }
    }

    static class Config {
        String host;
        int port;
        String path;

        Config(String host, int port, String path) {
            this.host = Objects.requireNonNull(host, "Host required");
            this.port = port;
            this.path = Objects.requireNonNull(path, "Path required");
        }

        @Override
        public String toString() {
            return host + ":" + port + path;
        }
    }

    static class UserService {
        User findUser(String id) {
            Objects.requireNonNull(id, "User ID required");

            if ("alice".equals(id)) {
                return new User("alice", "Alice");
            }

            throw new NullPointerException("User not found: " + id);
        }
    }

    static class User {
        String id;
        String name;

        User(String id, String name) {
            this.id = id;
            this.name = name;
        }

        @Override
        public String toString() {
            return name + " (id=" + id + ")";
        }
    }

    static class Container {
        String[] items;

        Container(String[] items) {
            this.items = Objects.requireNonNull(items, "Items array required")
                               .clone();  // Defensive copy
        }

        @Override
        public String toString() {
            return java.util.Arrays.toString(items);
        }
    }
}
// Objects.requireNonNull examples

import java.util.Objects;

public class Require {
    public static void main(String[] args) {
        System.out.println("Basic requireNonNull:");

        String valid = "hello";
        String invalid = null;

        String result = Objects.requireNonNull(valid);
        System.out.println("Valid: " + result);

        try {
            Objects.requireNonNull(invalid);
        } catch (NullPointerException e) {
            System.out.println("Caught NPE: " + e.getMessage());
        }
        System.out.println("\nWith message:");

        try {
            Objects.requireNonNull(null, "Value must not be null");
        } catch (NullPointerException e) {
            System.out.println("Message: " + e.getMessage());
        }
        System.out.println("\nConstructor validation:");

        try {
            Person p1 = new Person("Alice", 30);
            System.out.println("Created: " + p1);

            Person p2 = new Person(null, 25);
        } catch (NullPointerException e) {
            System.out.println("Constructor failed: " + e.getMessage());
        }
        System.out.println("\nMethod parameters:");

        EmailSender sender = new EmailSender();

        try {
            sender.send("user@example.com", "Hello", "Welcome!");
            System.out.println("Email sent successfully");
        } catch (NullPointerException e) {
            System.out.println("Failed: " + e.getMessage());
        }

        try {
            sender.send(null, "Hello", "Welcome!");
        } catch (NullPointerException e) {
            System.out.println("Failed: " + e.getMessage());
        }
        System.out.println("\nSupplier message:");

        String userId = ;

        try {
            Objects.requireNonNull(userId, () ->
                "User ID is required but was null in this request");
            System.out.println("User ID: " + userId);
        } catch (NullPointerException e) {
            System.out.println("Lazy message: " + e.getMessage());
        }
        System.out.println("\nChain validation:");

        Config config = new Config("localhost", 8080, "/api");
        System.out.println("Config: " + config);

        try {
            new Config(null, 8080, "/api");
        } catch (NullPointerException e) {
            System.out.println("Host required: " + e.getMessage());
        }
        System.out.println("\nReturn value validation:");

        UserService service = new UserService();

        User user = service.findUser("alice");
        System.out.println("Found: " + user);

        try {
            service.findUser("unknown");
        } catch (NullPointerException e) {
            System.out.println("Not found: " + e.getMessage());
        }
        System.out.println("\nDefensive copy:");

        String[] items = {"a", "b", "c"};
        Container c1 = new Container(items);
        System.out.println("Container: " + c1);

        try {
            new Container(null);
        } catch (NullPointerException e) {
            System.out.println("Null array: " + e.getMessage());
        }
    }

    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = Objects.requireNonNull(name, "Name must not be null");
            this.age = age;
        }

        @Override
        public String toString() {
            return name + " (" + age + ")";
        }
    }

    static class EmailSender {
        void send(String to, String subject, String body) {
            Objects.requireNonNull(to, "Recipient must not be null");
            Objects.requireNonNull(subject, "Subject must not be null");
            Objects.requireNonNull(body, "Body must not be null");
            // Send email...
        }
    }

    static class Config {
        String host;
        int port;
        String path;

        Config(String host, int port, String path) {
            this.host = Objects.requireNonNull(host, "Host required");
            this.port = port;
            this.path = Objects.requireNonNull(path, "Path required");
        }

        @Override
        public String toString() {
            return host + ":" + port + path;
        }
    }

    static class UserService {
        User findUser(String id) {
            Objects.requireNonNull(id, "User ID required");

            if ("alice".equals(id)) {
                return new User("alice", "Alice");
            }

            throw new NullPointerException("User not found: " + id);
        }
    }

    static class User {
        String id;
        String name;

        User(String id, String name) {
            this.id = id;
            this.name = name;
        }

        @Override
        public String toString() {
            return name + " (id=" + id + ")";
        }
    }

    static class Container {
        String[] items;

        Container(String[] items) {
            this.items = Objects.requireNonNull(items, "Items array required")
                               .clone();  // Defensive copy
        }

        @Override
        public String toString() {
            return java.util.Arrays.toString(items);
        }
    }
}
// Objects.requireNonNull examples

import java.util.Objects;

public class Require {
    public static void main(String[] args) {
        System.out.println("Basic requireNonNull:");

        String valid = "hello";
        String invalid = null;

        String result = Objects.requireNonNull(valid);
        System.out.println("Valid: " + result);

        try {
            Objects.requireNonNull(invalid);
        } catch (NullPointerException e) {
            System.out.println("Caught NPE: " + e.getMessage());
        }
        System.out.println("\nWith message:");

        try {
            Objects.requireNonNull(null, "Value must not be null");
        } catch (NullPointerException e) {
            System.out.println("Message: " + e.getMessage());
        }
        System.out.println("\nConstructor validation:");

        try {
            Person p1 = new Person("Alice", 30);
            System.out.println("Created: " + p1);

            Person p2 = new Person(null, 25);
        } catch (NullPointerException e) {
            System.out.println("Constructor failed: " + e.getMessage());
        }
        System.out.println("\nMethod parameters:");

        EmailSender sender = new EmailSender();

        try {
            sender.send("user@example.com", "Hello", "Welcome!");
            System.out.println("Email sent successfully");
        } catch (NullPointerException e) {
            System.out.println("Failed: " + e.getMessage());
        }

        try {
            sender.send(null, "Hello", "Welcome!");
        } catch (NullPointerException e) {
            System.out.println("Failed: " + e.getMessage());
        }
        System.out.println("\nSupplier message:");

        String userId = ;

        try {
            Objects.requireNonNull(userId, () ->
                "User ID is required but was null in this request");
            System.out.println("User ID: " + userId);
        } catch (NullPointerException e) {
            System.out.println("Lazy message: " + e.getMessage());
        }
        System.out.println("\nChain validation:");

        Config config = new Config("localhost", 8080, "/api");
        System.out.println("Config: " + config);

        try {
            new Config(null, 8080, "/api");
        } catch (NullPointerException e) {
            System.out.println("Host required: " + e.getMessage());
        }
        System.out.println("\nReturn value validation:");

        UserService service = new UserService();

        User user = service.findUser("alice");
        System.out.println("Found: " + user);

        try {
            service.findUser("unknown");
        } catch (NullPointerException e) {
            System.out.println("Not found: " + e.getMessage());
        }
        System.out.println("\nDefensive copy:");

        String[] items = {"a", "b", "c"};
        Container c1 = new Container(items);
        System.out.println("Container: " + c1);

        try {
            new Container(null);
        } catch (NullPointerException e) {
            System.out.println("Null array: " + e.getMessage());
        }
    }

    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = Objects.requireNonNull(name, "Name must not be null");
            this.age = age;
        }

        @Override
        public String toString() {
            return name + " (" + age + ")";
        }
    }

    static class EmailSender {
        void send(String to, String subject, String body) {
            Objects.requireNonNull(to, "Recipient must not be null");
            Objects.requireNonNull(subject, "Subject must not be null");
            Objects.requireNonNull(body, "Body must not be null");
            // Send email...
        }
    }

    static class Config {
        String host;
        int port;
        String path;

        Config(String host, int port, String path) {
            this.host = Objects.requireNonNull(host, "Host required");
            this.port = port;
            this.path = Objects.requireNonNull(path, "Path required");
        }

        @Override
        public String toString() {
            return host + ":" + port + path;
        }
    }

    static class UserService {
        User findUser(String id) {
            Objects.requireNonNull(id, "User ID required");

            if ("alice".equals(id)) {
                return new User("alice", "Alice");
            }

            throw new NullPointerException("User not found: " + id);
        }
    }

    static class User {
        String id;
        String name;

        User(String id, String name) {
            this.id = id;
            this.name = name;
        }

        @Override
        public String toString() {
            return name + " (id=" + id + ")";
        }
    }

    static class Container {
        String[] items;

        Container(String[] items) {
            this.items = Objects.requireNonNull(items, "Items array required")
                               .clone();  // Defensive copy
        }

        @Override
        public String toString() {
            return java.util.Arrays.toString(items);
        }
    }
}
Fail-fast validation Objects.requireNonNull() throws NullPointerException immediately with a descriptive message, catching bugs early.

String Conversion

Convert objects to strings safely.

Tostring.java
// Objects.toString examples

import java.util.Objects;

public class Tostring {
    public static void main(String[] args) {
        System.out.println("Basic toString:");

        String s1 = "hello";
        String s2 = null;

        System.out.println("s1.toString(): " + s1.toString());
        System.out.println("Objects.toString(s1): " + Objects.toString(s1));
        System.out.println("Objects.toString(null): " + Objects.toString(s2));

        // This would throw NPE:
        // System.out.println(s2.toString());
        System.out.println("\nWith default:");

        String name = null;
        String result = Objects.toString(name, "Unknown");
        System.out.println("Name: " + result);

        Integer age = null;
        String ageStr = Objects.toString(age, "N/A");
        System.out.println("Age: " + ageStr);
        System.out.println("\nArray toString:");

        int[] numbers = {1, 2, 3, 4, 5};
        int[] empty = null;

        System.out.println("Array: " + Objects.toString(numbers));
        System.out.println("Null array: " + Objects.toString(empty, "[]"));

        // Better for arrays:
        System.out.println("Arrays.toString: " + java.util.Arrays.toString(numbers));
        System.out.println("\nCustom objects:");

        Person p1 = new Person("Alice", 30);
        Person p2 = null;

        System.out.println("Person: " + Objects.toString(p1));
        System.out.println("Null person: " + Objects.toString(p2, "No person"));
        System.out.println("\nCollections:");

        java.util.List<String> list = java.util.Arrays.asList("a", "b", "c");
        java.util.List<String> nullList = null;

        System.out.println("List: " + Objects.toString(list));
        System.out.println("Null list: " + Objects.toString(nullList, "[]"));
        System.out.println("\nFormatting output:");

        String username = "alice";
        String email = null;
        String phone = "555-1234";

        System.out.println("Username: " + Objects.toString(username, "N/A"));
        System.out.println("Email: " + Objects.toString(email, "N/A"));
        System.out.println("Phone: " + Objects.toString(phone, "N/A"));
        System.out.println("\nIn logging:");

        Config config = new Config();
        config.host = "localhost";
        config.port = 8080;
        config.database = null;

        System.out.println("Config:");
        System.out.println("  Host: " + Objects.toString(config.host, "default"));
        System.out.println("  Port: " + config.port);
        System.out.println("  DB: " + Objects.toString(config.database, "not configured"));
        System.out.println("\nOptional values:");

        Integer count = getCount();
        String status = getStatus();

        System.out.println("Count: " + Objects.toString(count, "0"));
        System.out.println("Status: " + Objects.toString(status, "unknown"));
        System.out.println("\nDebug output:");

        Object obj1 = "hello";
        Object obj2 = 123;
        Object obj3 = null;
        Object obj4 = new Person("Bob", 25);

        printDebug("obj1", obj1);
        printDebug("obj2", obj2);
        printDebug("obj3", obj3);
        printDebug("obj4", obj4);
    }

    static Integer getCount() {
        return null;  // Simulate optional value
    }

    static String getStatus() {
        return null;  // Simulate optional value
    }

    static void printDebug(String name, Object value) {
        System.out.println(name + " = " + Objects.toString(value, "<null>"));
    }

    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return "Person{name='" + name + "', age=" + age + "}";
        }
    }

    static class Config {
        String host;
        int port;
        String database;
    }
}

Comparison Operations

Compare objects with null handling.

Compare.java
// Objects.compare examples

import java.util.Objects;
import java.util.Comparator;

public class Compare {
    public static void main(String[] args) {
        System.out.println("Basic compare:");

        String s1 = "apple";
        String s2 = "banana";
        String s3 = "apple";

        int result = Objects.compare(s1, s2, String::compareTo);
        System.out.println("compare('apple', 'banana'): " + result);

        result = Objects.compare(s1, s3, String::compareTo);
        System.out.println("compare('apple', 'apple'): " + result);
        System.out.println("\nWith nulls:");

        String n1 = null;
        String n2 = "hello";

        // Nulls-first comparator
        Comparator<String> nullsFirst = Comparator.nullsFirst(String::compareTo);

        result = Objects.compare(n1, n2, nullsFirst);
        System.out.println("compare(null, 'hello', nullsFirst): " + result);

        result = Objects.compare(n2, n1, nullsFirst);
        System.out.println("compare('hello', null, nullsFirst): " + result);

        result = Objects.compare(n1, n1, nullsFirst);
        System.out.println("compare(null, null, nullsFirst): " + result);
        System.out.println("\nNulls-last:");

        Comparator<String> nullsLast = Comparator.nullsLast(String::compareTo);

        result = Objects.compare(null, "hello", nullsLast);
        System.out.println("compare(null, 'hello', nullsLast): " + result);

        result = Objects.compare("hello", null, nullsLast);
        System.out.println("compare('hello', null, nullsLast): " + result);
        System.out.println("\nNumbers:");

        Integer i1 = 10;
        Integer i2 = 20;
        Integer i3 = null;

        result = Objects.compare(i1, i2, Integer::compareTo);
        System.out.println("compare(10, 20): " + result);

        result = Objects.compare(i1, i3, Comparator.nullsLast(Integer::compareTo));
        System.out.println("compare(10, null): " + result);
        System.out.println("\nCustom objects:");

        Person p1 = new Person("Alice", 30);
        Person p2 = new Person("Bob", 25);
        Person p3 = new Person("Charlie", 30);

        // Compare by age
        result = Objects.compare(p1, p2, Comparator.comparing(p -> p.age));
        System.out.println("Alice vs Bob (by age): " + result);

        result = Objects.compare(p1, p3, Comparator.comparing(p -> p.age));
        System.out.println("Alice vs Charlie (by age): " + result);

        // Compare by name
        result = Objects.compare(p1, p2, Comparator.comparing(p -> p.name));
        System.out.println("Alice vs Bob (by name): " + result);
        System.out.println("\nSorting:");

        java.util.List<Person> people = new java.util.ArrayList<>();
        people.add(new Person("Charlie", 30));
        people.add(new Person("Alice", 25));
        people.add(new Person("Bob", 35));

        System.out.println("Before sort:");
        people.forEach(System.out::println);

        people.sort((a, b) -> Objects.compare(a, b, Comparator.comparing(p -> p.name)));

        System.out.println("\nAfter sort by name:");
        people.forEach(System.out::println);
        System.out.println("\nMultiple criteria:");

        java.util.List<Person> students = new java.util.ArrayList<>();
        students.add(new Person("Alice", 30));
        students.add(new Person("Bob", 25));
        students.add(new Person("Charlie", 30));
        students.add(new Person("Alice", 25));

        Comparator<Person> byAgeThenName =
            Comparator.comparing((Person p) -> p.age)
                      .thenComparing(p -> p.name);

        students.sort((a, b) -> Objects.compare(a, b, byAgeThenName));

        System.out.println("Sorted by age then name:");
        students.forEach(System.out::println);
        System.out.println("\nMin/Max:");

        Person youngest = people.stream()
            .min((a, b) -> Objects.compare(a, b, Comparator.comparing(p -> p.age)))
            .orElse(null);

        Person oldest = people.stream()
            .max((a, b) -> Objects.compare(a, b, Comparator.comparing(p -> p.age)))
            .orElse(null);

        System.out.println("Youngest: " + youngest);
        System.out.println("Oldest: " + oldest);
    }

    static class Person {
        String name;
        int age;

        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return name + " (" + age + ")";
        }
    }
}

@seealso collections_util

Exercise: Practical.java

Implement equals and hashCode for a Product class using Objects methods