Java nije obavezna kao povratna vrsta

1. Uvod

The Neobvezno type uveden je u Javi 8. Pruža jasan i eksplicitan način prenošenja poruke da možda ne postoji vrijednost bez upotrebe null.

Prilikom dobivanja Neobvezno return type, vjerojatno ćemo provjeriti nedostaje li vrijednost, što dovodi do manje NullPointerExceptions u aplikacijama. Međutim Neobvezno tip nije prikladan za sva mjesta.

Iako ga možemo koristiti gdje god smatramo prikladnim, u ovom ćemo se vodiču usredotočiti na neke najbolje prakse korištenja Neobvezno kao povratni tip.

2. Neobvezno kao Povratni tip

An Neobvezno type može biti povratni tip za većinu metoda, osim nekih scenarija o kojima ćemo kasnije raspravljati u vodiču.

Većinu vremena, vraćanje Neobvezno je sasvim u redu:

javna statička Neobavezna findUserByName (ime niza) {User user = usersByName.get (name); Neobvezno opt = Neobvezno.ofNullable (korisnik); return opt; }

Ovo je zgodno jer možemo koristiti Neobvezno API u načinu pozivanja:

javna statička praznina changeUserName (String oldFirstName, String newFirstName) {findUserByFirstName (oldFirstName) .ifPresent (user -> user.setFirstName (newFirstName)); }

Također je prikladno za statičku metodu ili uslužnu metodu za vraćanje Neobvezno vrijednost. Međutim, postoji mnogo situacija u kojima se ne bismo trebali vratiti neobavezna tip.

3. Kada se ne vratiti Neobvezno

Jer Neobvezno je omot i klasa koja se temelji na vrijednosti, postoje neke operacije protiv kojih se ne može učiniti Neobvezno objekt. Mnogo je puta jednostavno jednostavno vratiti stvarni tip, a ne Neobvezno tip.

Općenito govoreći, za getere u POJO-ima prikladnije je vratiti stvarni tip, a ne Neobvezno tip. Osobito je važno da grah entiteta, modeli podataka i DTO imaju tradicionalne getere.

U nastavku ćemo ispitati neke od važnih slučajeva korištenja.

3.1. Serijalizacija

Zamislimo da imamo jednostavan entitet:

javna klasa Sock implementira Serializable {Integer size; Neobvezni par; // ... geteri i postavljači}

Ovo zapravo uopće neće uspjeti. Ako bismo pokušali ovo serializirati, dobili bismo NotSerializableException:

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

I stvarno, dok se serijalizira Neobvezno mogu raditi s drugim knjižnicama, sigurno dodaje ono što može biti nepotrebna složenost.

Pogledajmo još jednu primjenu te iste neusklađenosti serializacije, ovaj put s JSON-om.

3.2. JSON

Moderne aplikacije cijelo vrijeme pretvaraju Java objekte u JSON. Ako geter vrati Neobvezno tipa, najvjerojatnije ćemo u konačnom JSON-u vidjeti neku neočekivanu strukturu podataka.

Recimo da imamo grah s neobaveznim svojstvom:

private String firstName; javno Izborno getFirstName () {return Izborno.ofNullable (firstName); } javna praznina setFirstName (String firstName) {this.firstName = firstName; }

Dakle, ako koristimo Jacksona za serializiranje instance Neobvezno, dobit ćemo:

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

Ali, ono što bismo stvarno željeli je:

{"firstName": "Baeldung"}

Tako, Neobvezno je muka za slučajeve korištenja serializacije. Dalje, pogledajmo rođaka na serializaciju: upisivanje podataka u bazu podataka.

3.3. JPA

U JPA-u, getter, setter i polje trebaju imati naziv, kao i ugovor o tipu. Na primjer, a ime polje tipa Niz treba biti uparen s geterom pozvanim getFirstName koji također vraća a Niz.

Slijeđenje ove konvencije pojednostavljuje nekoliko stvari, uključujući upotrebu refleksije u knjižnicama kao što je Hibernate, dajući nam veliku podršku za objektno-relacijsko mapiranje.

Pogledajmo naš isti slučaj upotrebe neobavezno ime u POJO-u.

No, ovaj put to će biti JPA entitet:

@Entity javna klasa UserOptionalField implementira serializable {@Id private long userId; privatno Neobvezno firstName; // ... geteri i postavljači}

I idemo naprijed i pokušajmo to ustrajati:

UserOptionalField user = novi UserOptionalField (); user.setUserId (1l); user.setFirstName (Izborno.of ("Baeldung")); entityManager.persist (korisnik);

Nažalost, nailazimo na pogrešku:

Uzrokovano: javax.persistence.PersistenceException: [PersistenceUnit: com.baeldung.optionalReturnType] Nije moguće izgraditi Hibernate SessionFactory na org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException (EntityjnagerBagenbugAberBajnerBajgerBagenbugArberManagerBagenbugArberManagerBajerbug. .boot.internal.EntityManagerFactoryBuilderImpl.build (EntityManagerFactoryBuilderImpl.java:941) na org.hibernate.jpa.HibernatePersistenceProvider.createEntityManagerFactory (HibernatePersistenceProvider.java:56g. persistence.Persistence.createEntityManagerFactory (Persistence.java:54) na com.baeldung.optionalReturnType.PersistOptionsTypeExample. (PersistOptionalTypeExample.java:11) Uzrok: org.hibernate.MappingException: Nije moguće odrediti vrstu za: java.u tablica: UserOptionalField, za stupce: [org.hibernate.mapping.Column (firstName)]

Mogli bismo pokušati odstupajući od ovog standarda. Na primjer, mogli bismo zadržati imovinu kao Niz, ali promijenite geter:

@Kolona (nullable = true) private String firstName; javno Izborno getFirstName () {return Izborno.ofNullable (firstName); }

Čini se da bismo mogli imati oba načina: imati Neobvezno povratni tip za geter i trajno polje ime.

Međutim, sada kada nismo u skladu s našim geterom, postavljačem i poljem, bit će teže iskoristiti zadane vrijednosti JPA i alate izvornog koda IDE.

Sve dok JPA ne dobije elegantnu podršku za Neobvezno tipa, trebali bismo se držati tradicionalnog koda. Jednostavnije je i bolje:

private String firstName; // ... tradicionalni getter i setter

Pogledajmo napokon kako ovo utječe na prednji kraj - provjerite zvuči li problem na koji nailazimo poznat.

3.4. Jezici izražavanja

Priprema DTO za front-end predstavlja slične poteškoće.

Na primjer, zamislimo da koristimo JSP predloške za čitanje našeg KorisnikObavezno DTO-ovi ime iz zahtjeva:

Budući da je Neobvezno, nećemo vidjeti “Baeldung“. Umjesto toga, vidjet ćemo Niz predstavljanje Neobvezno tip:

Neobvezno [Baeldung] 

I to nije problem samo s JSP-om. Bilo koji jezik predloška, ​​bilo da je to Velocity, Freemarker ili nešto drugo, trebat će dodati podršku za to. Do tada, nastavimo držati naše DTO jednostavnima.

4. Zaključak

U ovom uputstvu naučili smo kako možemo vratiti Neobvezno objekt i kako postupati s ovom vrstom povratne vrijednosti.

S druge strane, također smo saznali da postoji mnogo scenarija koje bi bilo bolje da ih ne koristimo Neobvezno povratni tip za geter. Dok možemo koristiti Neobvezno tipa kao nagovještaj da možda ne postoji vrijednost koja nije null, trebali bismo biti oprezni da ne pretjeramo s Neobvezno tip povratka, posebno u geteru graha entiteta ili DTO.

Izvorni kod primjera u ovom vodiču može se naći na GitHubu.