Java Valgfritt som returtype

1. Introduksjon

De Valgfri type ble introdusert i Java 8. Det gir en klar og eksplisitt måte å formidle budskapet om at det ikke kan være en verdi uten å bruke null.

Når du får en Valgfri returtype, vil vi sannsynligvis sjekke om verdien mangler, noe som fører til færre NullPointerExceptions i applikasjonene. Imidlertid, den Valgfri typen passer ikke alle steder.

Selv om vi kan bruke den uansett hvor vi ser det, vil vi i denne opplæringen fokusere på noen gode fremgangsmåter for bruk Valgfri som returtype.

2. Valgfri som Returtype

An Valgfri type kan være en returtype for de fleste metoder, bortsett fra noen scenarier som er diskutert senere i opplæringen.

Mesteparten av tiden, returnerer en Valgfri er helt greit:

offentlig statisk Valgfri findUserByName (strengnavn) {User user = usersByName.get (name); Valgfri opt = Optional.ofNullable (bruker); returvalg; }

Dette er praktisk siden vi kan bruke Valgfri API i anropsmetoden:

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

Det er også hensiktsmessig for en statisk metode eller verktøymetode å returnere en Valgfri verdi. Imidlertid er det mange situasjoner der vi ikke skal komme tilbake et valgfritt type.

3. Når skal jeg ikke returnere Valgfri

Fordi Valgfri er en wrapper og verdibasert klasse, er det noen operasjoner som ikke kan gjøres mot Valgfri gjenstand. Mange ganger er det bare bedre å returnere den faktiske typen i stedet for en Valgfri type.

Generelt sett er det mer passende for getters i POJOs å returnere den faktiske typen, ikke en Valgfri type. Spesielt er det viktig for Entity Beans, Data Models og DTOs å ha tradisjonelle getters.

Vi vil undersøke noen av de viktige brukssakene nedenfor.

3.1. Serialisering

La oss forestille oss at vi har en enkel enhet:

public class Sock implementer Serializable {Heltalstørrelse; Valgfritt par; // ... getters og setters}

Dette fungerer faktisk ikke i det hele tatt. Hvis vi skulle prøve å serialisere dette, ville vi få en NotSerializableException:

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

Og egentlig, mens du serierer Valgfri kan samarbeide med andre biblioteker, det legger absolutt til det som kan være unødvendig kompleksitet.

La oss ta en titt på en annen applikasjon av samme serialiseringsfeil, denne gangen med JSON.

3.2. JSON

Moderne applikasjoner konverterer Java-objekter til JSON hele tiden. Hvis en getter returnerer en Valgfri type, vil vi mest sannsynlig se noen uventede datastrukturer i den endelige JSON.

La oss si at vi har en bønne med en valgfri eiendom:

privat streng fornavn; public Optional getFirstName () {return Optional.ofNullable (fornavn); } public void setFirstName (String firstName) {this.firstName = firstName; }

Så hvis vi bruker Jackson til å serieisere en forekomst av Valgfri, vi får:

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

Men det vi virkelig vil ha er:

{"firstName": "Baeldung"}

Så, Valgfri er en smerte for bruk av serialisering. Deretter, la oss se på fetteren til serialisering: skrive data til en database.

3.3. JPA

I JPA skal getter, setter og felt ha navn så vel som typeavtale. For eksempel, a fornavn felt av typen String skal parres med en getter som heter getFirstName som også returnerer a String.

Å følge denne konvensjonen gjør flere ting enklere, inkludert bruk av refleksjon av biblioteker som Hibernate, for å gi oss god støtte for objektrelasjonell kartlegging.

La oss ta en titt på vår samme brukstilfelle av et valgfritt fornavn i en POJO.

Denne gangen vil det imidlertid være en JPA-enhet:

@Entity offentlig klasse UserOptionalField implementerer Serializable {@Id privat lang brukerId; privat Valgfritt fornavn; // ... getters og setters}

Og la oss fortsette og prøve å vedvare det:

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

Dessverre støter vi på en feil:

Forårsaket av: javax.persistence.PersistenceException: [PersistenceUnit: com.baeldung.optionalReturnType] Kunne ikke bygge Hibernate SessionFactory ved org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException (EntityManagerFiber) .boot.internal.EntityManagerFactoryBuilderImpl.build (EntityManagerFactoryBuilderImpl.java:941) på org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory (HibernatePersistenceProvider.java:56) at javax.persent. persistence.Persistence.createEntityManagerFactory (Persistence.java:54) at com.baeldung.optionalReturnType.PersistOptionalTypeExample. (PersistOptionalTypeExample.java:11) Forårsaket av: org.hibernate.MappingException: Kunne ikke bestemme type for: javation. tabell: UserOptionalField, for kolonner: [org.hibernate.mapping.Column (firstName)]

Vi kunne prøve avviker fra denne standarden. For eksempel kan vi beholde eiendommen som en String, men endre getter:

@Column (nullable = true) privat streng fornavn; public Optional getFirstName () {return Optional.ofNullable (fornavn); }

Det ser ut til at vi kunne ha begge veier: ha en Valgfri returtype for getter og et vedvarende felt fornavn.

Nå som vi ikke er i samsvar med getter, setter og felt, vil det imidlertid være vanskeligere å utnytte JPA-standarder og IDE-kildekodeverktøy.

Inntil JPA har elegant støtte fra Valgfri type, bør vi holde oss til den tradisjonelle koden. Det er enklere og bedre:

privat streng fornavn; // ... tradisjonell getter og setter

La oss endelig ta en titt på hvordan dette påvirker frontend - sjekk for å se om problemet vi støter på høres kjent ut.

3.4. Uttrykk språk

Å forberede en DTO for front-end byr på lignende vanskeligheter.

La oss for eksempel forestille oss at vi bruker JSP-mal for å lese vår Bruker Valgfritt DTO-er fornavn fra forespørselen:

Siden det er en Valgfri, vi ser ikke “Baeldung“. I stedet får vi se String representasjon av Valgfri type:

Valgfritt [Baeldung] 

Og dette er ikke et problem bare med JSP. Ethvert malespråk, det være seg Velocity, Freemarker eller noe annet, må legge til støtte for dette. Inntil da, la oss fortsette å holde DTO-ene enkle.

4. Konklusjon

I denne opplæringen har vi lært hvordan vi kan returnere en Valgfri objekt, og hvordan man skal håndtere denne typen returverdi.

På den annen side har vi også lært at det er mange scenarier som det er bedre å ikke bruke Valgfri returtype for en getter. Mens vi kan bruke Valgfri skriv som et hint om at det ikke kan være noen verdi som ikke er null, bør vi være forsiktige med å ikke bruke for mye Valgfri returtype, spesielt i en getter av en enhetsbønne eller en DTO.

Kildekoden til eksemplene i denne opplæringen finner du på GitHub.