Java Academy · leksjon

Egendefinerte metoder i records

Legg til instansmetoder og statiske fabrikkmetoder for å utvide funksjonaliteten til records.

Leksjon 3 av 413 trinn

Egendefinerte metoder i records er en gratis leksjon i Java Academy på CoddyKit. Dette er leksjon 3 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Java Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Java Academy inneholder totalt 4 leksjoner.

Egendefinerte metoder i records

Records kan inneholde instansmetoder, statiske metoder og statiske felt – all atferd som er avledet fra eller knyttet til recordens komponenter.

Instansmetoder i records

Legg til metoder i records for å beregne avledede verdier eller tilby nyttige operasjoner basert på komponentene.

record Money(long cents, String currency) {
    public double amount() { return cents / 100.0; }
    public String display() { return String.format("%s %.2f", currency, amount()); }
    public Money add(Money other) {
        if (!currency.equals(other.currency))
            throw new IllegalArgumentException("Currency mismatch");
        return new Money(cents + other.cents, currency);
    }
    public Money multiply(int factor) { return new Money(cents * factor, currency); }
}

Money price = new Money(1999, "USD");
Money tax = new Money(160, "USD");
System.out.println(price.add(tax).display()); // USD 21.59

Statiske fabrikkmetoder

Statiske fabrikkmetoder tilbyr navngitte og lesbare måter å opprette records på – og skjuler den rå konstruktøren når den er mindre tydelig.

import java.time.*;

record DateRange(LocalDate start, LocalDate end) {
    DateRange { if (start.isAfter(end)) throw new IllegalArgumentException(); }

    public static DateRange of(LocalDate start, LocalDate end) {
        return new DateRange(start, end);
    }

    public static DateRange thisMonth() {
        LocalDate now = LocalDate.now();
        return new DateRange(now.withDayOfMonth(1),
            now.withDayOfMonth(now.lengthOfMonth()));
    }

    public long durationDays() {
        return ChronoUnit.DAYS.between(start, end) + 1;
    }
}

System.out.println(DateRange.thisMonth().durationDays());

Predikatmetoder

Records tilbyr ofte boolske predikatmetoder for å kontrollere betingelser for dataene de inneholder.

record User(String email, String plan, boolean emailVerified) {
    public boolean isPro()      { return "PRO".equals(plan); }
    public boolean canPublish() { return isPro() && emailVerified; }
    public boolean isFree()     { return "FREE".equals(plan); }

    public User withPlan(String newPlan) {
        return new User(email, newPlan, emailVerified); // "update"
    }
}

User u = new User("alice@example.com", "FREE", true);
System.out.println(u.canPublish()); // false
User upgraded = u.withPlan("PRO");
System.out.println(upgraded.canPublish()); // true

Wither-metoder (Copy-With)

Ettersom records er uforanderlige, betyr «oppdatering» at du oppretter en ny record. Wither-metoder følger mønsteret withX(newValue).

record ServerConfig(String host, int port, boolean ssl, int timeout) {
    public ServerConfig withHost(String h)    { return new ServerConfig(h, port, ssl, timeout); }
    public ServerConfig withPort(int p)       { return new ServerConfig(host, p, ssl, timeout); }
    public ServerConfig withSsl(boolean s)    { return new ServerConfig(host, port, s, timeout); }
    public ServerConfig withTimeout(int t)    { return new ServerConfig(host, port, ssl, t); }
}

ServerConfig dev = new ServerConfig("localhost", 8080, false, 30);
ServerConfig prod = dev
    .withHost("api.example.com")
    .withPort(443)
    .withSsl(true)
    .withTimeout(60);
System.out.println(prod);

Records som implementerer funksjonelle grensesnitt

En record som også implementerer et funksjonelt grensesnitt, kan sendes direkte inn som en erstatning for en lambda.

import java.util.function.*;

record Validator<T>(Predicate<T> rule, String message)
    implements Predicate<T> {

    public boolean test(T value) { return rule.test(value); }

    public String validate(T value) {
        return test(value) ? null : message;
    }
}

Validator<String> notEmpty = new Validator<>(
    s -> !s.isBlank(), "Must not be blank");
Validator<String> validEmail = new Validator<>(
    s -> s.contains("@"), "Invalid email");

System.out.println(notEmpty.validate(""));        // Must not be blank
System.out.println(validEmail.validate("a@b.c")); // null (valid)

Aggregeringsmetoder

Records som inneholder samlinger, kan tilby stream-baserte aggregeringsmetoder.

import java.util.*;

record SalesReport(String region, List<Double> dailySales) {
    SalesReport { dailySales = List.copyOf(dailySales); }

    public double total()   { return dailySales.stream().mapToDouble(Double::doubleValue).sum(); }
    public double average() { return dailySales.stream().mapToDouble(Double::doubleValue).average().orElse(0); }
    public double max()     { return dailySales.stream().mapToDouble(Double::doubleValue).max().orElse(0); }
    public int    days()    { return dailySales.size(); }
}

SalesReport r = new SalesReport("North", List.of(1200.0, 1450.0, 980.0, 1600.0));
System.out.printf("Total: %.0f, Avg: %.0f, Max: %.0f%n", r.total(), r.average(), r.max());
// Total: 5230, Avg: 1307, Max: 1600

Egendefinert toString-overstyring

Selv om den automatisk genererte toString er nyttig ved feilsøking, kan det hende du vil overstyre den for visning til brukeren.

record Temperature(double celsius) {
    @Override
    public String toString() {
        return String.format("%.1f\u00b0C / %.1f\u00b0F",
            celsius, toFahrenheit());
    }

    public double toFahrenheit() { return celsius * 9.0/5.0 + 32; }
    public double toKelvin()     { return celsius + 273.15; }

    public static Temperature fromFahrenheit(double f) {
        return new Temperature((f - 32) * 5.0/9.0);
    }
}

Temperature boiling = new Temperature(100.0);
System.out.println(boiling); // 100.0°C / 212.0°F

Records som verdiobjekter i DDD

I Domain-Driven Design tilsvarer records naturlig verdiobjekter – uforanderlige typer som defineres av attributtene sine, ikke av identiteten.

// Value objects in a banking domain
record AccountId(String value) {
    AccountId { if (!value.matches("ACC-[0-9]{8}")) throw new IllegalArgumentException(); }
}
record Amount(long cents, String currency) {
    public static Amount usd(long cents) { return new Amount(cents, "USD"); }
    public boolean isPositive() { return cents > 0; }
}
record TransactionId(java.util.UUID value) {
    public static TransactionId generate() {
        return new TransactionId(java.util.UUID.randomUUID());
    }
}

AccountId id = new AccountId("ACC-12345678");
Amount amount = Amount.usd(5000);
TransactionId txId = TransactionId.generate();
System.out.println(id + " " + amount + " " + txId);

Sammenligne records med Comparator

Records kan sorteres ved hjelp av Comparator.comparing med metodereferanser som peker på tilgangsmetoder.

import java.util.*;

record Employee(String name, String dept, double salary) {}

List<Employee> employees = List.of(
    new Employee("Alice",   "Engineering", 95000),
    new Employee("Bob",     "Marketing",   72000),
    new Employee("Charlie", "Engineering", 105000),
    new Employee("Diana",   "Marketing",   81000)
);

// Sort by dept, then salary descending
employees.stream()
    .sorted(Comparator.comparing(Employee::dept)
        .thenComparing(Comparator.comparingDouble(Employee::salary).reversed()))
    .forEach(e -> System.out.printf("%-10s %-15s %.0f%n",
        e.name(), e.dept(), e.salary()));

Statiske hjelpemetoder i records

Records kan ha statiske metoder som fungerer med flere record-instanser – nyttig for transformasjoner og sammenligninger.

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

record Product(String id, String category, double price) {
    public static Map<String, DoubleSummaryStatistics> statsByCategory(
            List<Product> products) {
        return products.stream().collect(
            Collectors.groupingBy(Product::category,
                Collectors.summarizingDouble(Product::price)));
    }

    public static Optional<Product> cheapest(List<Product> products) {
        return products.stream()
            .min(Comparator.comparingDouble(Product::price));
    }
}

Hurtigsjekk

Du vil «oppdatere» et record-felt. Hva er den riktige fremgangsmåten?

Oppsummering: Egendefinerte metoder i records

Viktige punkter:

  • Records kan ha instansmetoder, statiske metoder og statiske felt
  • Legg til beregnede egenskaper som metoder (area(), total(), display())
  • Bruk statiske fabrikkmetoder for lesbare, navngitte konstruktører
  • Implementer wither-metoder (withX) for uforanderlige oppdateringer
  • Overstyr toString() for visning til brukeren i stedet for feilsøkingsutdata
  • Records tilsvarer naturlig verdiobjekter i Domain-Driven Design
Gratis å komme i gang

Lær deg Java med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
104
Leksjoner
374

Ofte stilte spørsmål

Er leksjonen «Egendefinerte metoder i records» gratis?

Ja – hele teksten i «Egendefinerte metoder i records» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Java Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Java Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Egendefinerte metoder i records»?

Legg til instansmetoder og statiske fabrikkmetoder for å utvide funksjonaliteten til records. Du øver på Java Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Java Academy?

Ingen tidligere erfaring er nødvendig. Java Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Egendefinerte metoder i records»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Java Academy-leksjonen?

Ja. Alle Java Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Introduksjon til records
  2. Kompakte konstruktører og validering
  3. Egendefinerte metoder i records
  4. Records kontra klasser kontra Lombok
← Tilbake til Java Academy