• ✨ Explicit Declaration of Record Class Members

    with French Actor Flair

    Java record classes provide a compact syntax for declaring immutable data carriers. But you’re not just limited to the default behavior: you can explicitly define many of the derived members.

    Let’s illustrate with a theme: French actors. 🎬

    🎭 Custom Accessor Method

    You can explicitly define accessor methods that Java otherwise generates automatically. Here's a record for an actor with a custom name() method:

    record FrenchActor(String name, int birthYear) {
    
        // Custom accessor method for 'name'
        public String name() {
            System.out.println("Accessing name: " + name);
            return name;
        }
    }

    💡 Reminder: If you redefine accessors, they must match the auto-generated versions: same name, return type, and be public.

    Similarly, if you implement your own versions of the equals, hashCode, and toString methods, then ensure that they have the same characteristics and behavior as those in the java.lang.Record class, which is the common superclass of all record classes.

    🧮 Static Members in Record Classes

    Record classes can include static fields, methods, and static initializers. For example, let’s track the average French actor's debut age:

    record FrenchActor(String name, int birthYear) {
    
        // Static field
        static int averageDebutAge;
    
        // Static initializer
        static {
            averageDebutAge = 22;
        }
    
        // Static method
        public static FrenchActor createYoungDebut(String name) {
            int estimatedYear = java.time.Year.now().getValue() - averageDebutAge;
            return new FrenchActor(name, estimatedYear);
        }
    }

    ❌ What’s Not Allowed in Records

    Unlike normal classes, record classes cannot:

    🟣 Declare instance (non-static) fields outside of the header.

    🟣 Use instance initializers.

    🚫 The following is invalid and won’t compile:

    record FrenchActor(String name, int birthYear) {
    
        // ❌ This is illegal in a record
        BiFunction<Integer, Integer, Integer> ageCalculator;
    
        {
            ageCalculator = (now, year) -> now - year;
        }
    }

    📦 Instance Methods and Nested Types

    Even though records are mostly about data, you can still add behavior via instance methods. You can also nest types, including other record classes!

    Here's an example where we calculate how old an actor will be in a specific year, and use a nested record for movie awards:

    record FrenchActor(String name, int birthYear) {
    
        // Nested record class
        record Award(String title, int year) {}
    
        // Instance method
        public int ageInYear(int year) {
            return year - birthYear;
        }
    
        // Example usage
        public Award winAward(String title, int awardYear) {
            return new Award(title, awardYear);
        }
    }

    🧬 Final Notes

    ✅ You can declare instance methods and static members.

    ✅ You can nest classes, including other records.

    ❌ You cannot declare native methods in record classes.

    🎬 Summary with a French Twist

    var marion = new FrenchActor("Marion Cotillard", 1975);
    System.out.println(marion.name()); // Custom accessor
    System.out.println("Age in 2025: " + marion.ageInYear(2025));
    
    var award = marion.winAward("César", 2005);
    System.out.println(award); // Nested record usage
    

    Record classes are great for modeling simple data structures—like information about your favorite French actors—while still letting you define useful logic and structure where needed.