Java >> Java tutorial >  >> Tag >> return

Java valgfri som returtype

1. Introduktion

Valgfri type blev introduceret i Java 8.  Det giver en klar og eksplicit måde at formidle budskabet om, at der muligvis ikke er en værdi, uden at bruge null .

Når du får en Valgfri returtype, vil vi sandsynligvis kontrollere, om værdien mangler, hvilket fører til færre NullPointerException s i applikationerne. Men Valgfri type er ikke egnet alle steder.

Selvom vi kan bruge det, hvor som helst vi finder det passende, vil vi i dette selvstudie fokusere på nogle bedste fremgangsmåder ved brug af Valgfri som returtype.

2. Valgfrit som returtype

En Valgfri type kan være en returtype for de fleste metoder undtagen nogle scenarier, der diskuteres senere i selvstudiet.

Det meste af tiden returnerer en Valgfri er helt fint:

public static Optional<User> findUserByName(String name) {
    User user = usersByName.get(name);
    Optional<User> opt = Optional.ofNullable(user);
    return opt;
}

Dette er praktisk, da vi kan bruge Valgfri API i kaldemetoden:

public static void changeUserName(String oldFirstName, String newFirstName) {
    findUserByFirstName(oldFirstName).ifPresent(user -> user.setFirstName(newFirstName));
}

Det er også passende for en statisk metode eller hjælpemetode at returnere en Valgfri værdi. Der er dog mange situationer, hvor vi ikke bør returnere en Valgfri type.

3. Hvornår skal du ikke returnere Valgfrit

Fordi Valgfrit er en indpaknings- og værdibaseret klasse, er der nogle handlinger, der ikke kan udføres mod Valgfri objekt. Mange gange er det simpelthen bedre at returnere den faktiske type frem for en Valgfri type.

Generelt set er det mere velegnet for getters i POJO'er at returnere den faktiske type, ikke en Valgfri type. Det er især vigtigt for Entity Beans, Data Models og DTO'er at have traditionelle getters.

Vi vil undersøge nogle af de vigtige use cases nedenfor.

3.1. Serialisering

Lad os forestille os, at vi har en simpel enhed:

public class Sock implements Serializable {
    Integer size;
    Optional<Sock> pair;

    // ... getters and setters
}

Dette virker faktisk slet ikke. Hvis vi skulle prøve at serialisere dette, ville vi få en NotSerializableException :

new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(new Sock());

Og virkelig, mens du serialiserer Valgfrit kan fungere sammen med andre biblioteker, det tilføjer helt sikkert, hvad der kan være unødvendig kompleksitet.

Lad os tage et kig på en anden applikation af samme serialiseringsmismatch, denne gang med JSON.

3.2. JSON

Moderne applikationer konverterer Java-objekter til JSON hele tiden. Hvis en getter returnerer en Valgfri type, vil vi højst sandsynligt se en eller anden uventet datastruktur i den endelige JSON.

Lad os sige, at vi har en bønne med en valgfri egenskab:

private String firstName;

public Optional<String> getFirstName() {
    return Optional.ofNullable(firstName);
}

public void setFirstName(String firstName) {
    this.firstName = firstName;
}

Så hvis vi bruger Jackson til at serialisere en forekomst af Valgfri , får vi:

{"firstName":{"present":true}}

Men hvad vi virkelig ønsker er:

{"firstName":"Baeldung"}

Så Valgfrit  er en smerte for serialiseringsbrug. Lad os derefter se på fætteren til serialisering:skrivning af data til en database.

3.3. JPA

I JPA skal getter, setter og felt have navn samt type aftale. For eksempel et fornavn  felt af typen String  skal parres med en getter kaldet getFirstName der også returnerer en streng.

At følge denne konvention gør adskillige ting enklere, herunder brugen af ​​refleksion fra biblioteker som Hibernate, for at give os fantastisk Objekt-Relationel kortlægningsstøtte.

Lad os tage et kig på vores samme brugstilfælde af et valgfrit fornavn i en POJO.

Denne gang vil det dog være en JPA-entitet:

@Entity
public class UserOptionalField implements Serializable {
    @Id
    private long userId;

    private Optional<String> firstName;

    // ... getters and setters
}

Og lad os gå videre og prøve at fortsætte det:

UserOptionalField user = new UserOptionalField();
user.setUserId(1l);
user.setFirstName(Optional.of("Baeldung"));
entityManager.persist(user);

Desværre løber vi ind i en fejl:

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: com.baeldung.optionalReturnType] Unable to build Hibernate SessionFactory
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1015)
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:941)
	at org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory(HibernatePersistenceProvider.java:56)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:79)
	at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
	at com.baeldung.optionalReturnType.PersistOptionalTypeExample.<clinit>(PersistOptionalTypeExample.java:11)
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Optional, at table: UserOptionalField, for columns: [org.hibernate.mapping.Column(firstName)]

Vi kunne prøve at afvige fra denne standard. For eksempel kunne vi beholde ejendommen som en streng , men skift getteren:

@Column(nullable = true) 
private String firstName; 

public Optional<String> getFirstName() { 
    return Optional.ofNullable(firstName); 
}

Det ser ud til, at vi kunne have begge måder:have en Valgfri returtype for getteren og et vedvarende felt fornavn .

Men nu hvor vi er inkonsistente med vores getter, setter og felt, bliver det sværere at udnytte JPA-standarder og IDE-kildekodeværktøjer.

Indtil JPA har elegant understøttelse af Valgfri type, bør vi holde os til den traditionelle kode. Det er enklere og bedre:

private String firstName;

// ... traditional getter and setter

Lad os endelig tage et kig på, hvordan dette påvirker frontenden – tjek om problemet, vi støder på, lyder bekendt.

3.4. Udtrykssprog

At forberede en DTO til front-end giver lignende vanskeligheder.

Lad os f.eks. forestille os, at vi bruger JSP-skabeloner til at læse vores UserOptional DTO's fornavn fra anmodningen:

<c:out value="${requestScope.user.firstName}" />

Da det er en Valgfri , vil vi ikke se "Baeldung ". I stedet vil vi se strengen repræsentation af Valgfri type:

Optional[Baeldung]

Og dette er ikke et problem kun med JSP. Ethvert skabelonsprog, det være sig Velocity, Freemarker eller noget andet, skal tilføje understøttelse til dette. Indtil da, lad os fortsætte med at holde vores DTO'er enkle.

4. Konklusion

I dette selvstudie har vi lært, hvordan vi kan returnere en Valgfri objekt, og hvordan man håndterer denne form for returværdi.

På den anden side har vi også erfaret, at der er mange scenarier, som vi ville være bedre stillet til ikke at bruge Valgfri returtype for en getter. Mens vi kan bruge Valgfri skriv som et hint om, at der muligvis ikke er nogen værdi, der ikke er nul, skal vi passe på ikke at overbruge Valgfri returtype, især i en getter af en entity bean eller en DTO.

Kildekoden til eksemplerne i denne tutorial kan findes på GitHub.


Java tag