Java opcional vs. Opció Vavr: Quina diferència hi ha?

Bloc

Java opcional vs. Opció Vavr: Quina diferència hi ha?

Java opcional vs. Opció Vavr: Quina diferència hi ha?

Avui m’agradaria parlar d’un tema essencial de Java: l’ús de Optional class - i compareu-ho amb una alternativa de la biblioteca Vavr. Opcionalment es va introduir inicialment a Java 8 i es va definir com un objecte contenidor que pot contenir o no un valor no nul.



Els desenvolupadors utilitzen Opcionals per evitar la comprovació nul·la en llocs quan l'execució de codi no comporta un resultat, sinó també un nul valor, i, en aquest sentit, pot resultar en un NullPointerException. En aquests casos, Opcional ens ofereix algunes funcions elegants, però no totes es van introduir a la vuitena versió, algunes funcions requereixen Java 11 . Una altra manera de tractar aquests problemes és amb Option de Vavr classe.

En aquesta publicació, aprendrem a utilitzar Optional de Java classe i després compareu-la amb Option de Vavr classe. Nota: aquest codi requereix Java 11 + i es va provar amb Vavr 0.10.2 .



Comencem.

Presentació de Java opcional

El concepte d'Opcional no és nou i ja s'ha implementat a llenguatges de programació funcionals M'agrada Haskell o bé Escala . Resulta molt útil a l’hora de modelar casos en què una trucada de mètode pot retornar un valor desconegut o un valor que no existeix (per exemple, nuls). Vegem com gestionar-ho.



Creació d’Opcional

Primer de tot, hem d’obtenir una instància opcional. Hi ha diverses maneres de fer-ho i, a més, també podem crear un fitxer buit Opcional. Mireu el primer mètode: crear a partir de valor és bastant senzill:

Optional four = Optional.of(Integer.valueOf(4)); if (four.isPresent){ System.out.println('Hoorayy! We have a value'); } else { System.out.println('No value'); }

Construïm un Optional d'un Integer valor de 4, és a dir, que sempre hi ha d’haver un valor i no pot ser nul, però aquest és només un exemple. Comprovem l’existència o l’absència de valor amb el ifPresent() mètode. Podeu observar que four no és un Integer; és un contenidor que conté sencer a l'interior . Quan estem segurs que el valor està dins, el podem desempaquetar amb el get() mètode. Irònicament, si fem servir get() sense comprovar-ho, podem acabar-ho amb NoSuchElementException.

Una altra manera d'obtenir un Optional utilitza corrents. Diversos mètodes del flux de terminal tornar opcionals, de manera que puguem manipular-los i comprovar-ne l'existència o l'absència, per exemple:

Consulteu el fragment de codi següent:

Optional car = cars.stream().filter(car->car.getId().equalsIgnoreCase(id)).findFirst();

La següent opció és crear Optional de codi que pot produir potencialment nul , per exemple. de Nullable:

Optional nullable = Optional.ofNullable(client.getRequestData());

Finalment, podem crear un fitxer buit Optional:

Optional nothing = Optional.empty();

Com s'utilitza Opcional

Sempre que obtinguem Optional, el podem utilitzar. Un dels casos més estesos és utilitzar-lo als dipòsits de Spring per trobar un registre per identificador, de manera que puguem construir la nostra lògica a Optional i eviteu la comprovació de nuls (per cert, Spring també admet Opcions Vavr). Suposem que tenim un dipòsit de llibres i que volem trobar-ne un.

Optional book = repository.findOne('some id');

En primer lloc, podem executar alguna lògica, en aquest cas, si el llibre es presenta . Ho hem fet amb if-else a la secció anterior, però no cal: Optional ens proporciona un mètode que accepta un Consumidor amb l'objecte:

repository.findOne('some id').ifPresent(book -> System.out.println(book));

O bé, ho podem fer encara més senzill; podem escriure el mateix amb referències de mètodes:

repository.findOne('some id').ifPresent(System.out::println);

Si no tenim cap llibre al dipòsit, podem proporcionar una devolució de trucada alternativa amb el ifPresentOrElseGet mètode:

repository.findOne('some id').ifPresentOrElseGet(book->{ // if value is presented }, ()->{ // if value is absent });

Alternativament, podem obtenir un altre valor si no es presenta el resultat de l’operació:

Book result = repository.findOne('some id').orElse(defaultBook);

No obstant això, amb les opcionals, hem de recordar possibles inconvenients. En el darrer exemple, ens garantim que podríem obtenir un llibre de totes maneres; o bé presenta el dipòsit subjacent o prové de orElse. Però, què passa si aquest valor per defecte no ho és constant , però també requereix algun mètode complex? En primer lloc, Java de totes maneres avalua findOne. Després, ha de processar el orElse mètode. Sí, si només és un valor constant per defecte, està bé, però també pot ser, com he dit abans, que consumeixi temps.

Un altre exemple

Creem un exemple senzill per comprovar com utilitzar pràcticament Optional i Option classes. Tindríem un CarRepository que trobaria un cotxe basat en la identificació subministrada (per exemple, al número de la matrícula). A continuació, veuríem com manipular Opcions i Opcions.

En primer lloc, afegim un codi

Comenceu amb la classe POJO Car. Segueix el immutable patró, de manera que tots els camps són definitius i només tenim getters sense seters. Totes les dades es proporcionen durant la inicialització.

public class Car { private final String name; private final String id; private final String color; public Car (String name, String id, String color){ this.name = name; this.id = id; this.color = color; } public String getId(){ return id; } public String getColor() { return color; } public String getName() { return name; } @Override public String toString() { return 'Car '+name+' with license id '+id+' and of color '+color; } }

El segon és crear el CarRepository classe. Requereix dues opcions per trobar el cotxe per identificador: fer servir l'antiga manera amb un possible resultat nul i fer servir Optional, tal com fem als repositoris de Spring.

public class CarRepository { private List cars; public CarRepository(){ getSomeCars(); } Car findCarById(String id){ for (Car car: cars){ if (car.getId().equalsIgnoreCase(id)){ return car; } } return null; } Optional findCarByIdWithOptional(String id){ return cars.stream().filter(car->car.getId().equalsIgnoreCase(id)).findFirst(); } private void getSomeCars(){ cars = new ArrayList(); cars.add(new Car('tesla', '1A9 4321', 'red')); cars.add(new Car('volkswagen', '2B1 1292', 'blue')); cars.add(new Car('skoda', '5C9 9984', 'green')); cars.add(new Car('audi', '8E4 4321', 'silver')); cars.add(new Car('mercedes', '3B4 5555', 'black')); cars.add(new Car('seat', '6U5 3123', 'white')); } }

Tingueu en compte que també omplim el nostre dipòsit amb alguns simuladors durant la inicialització, de manera que no tenim cap base de dades subjacent. Hem d’evitar la complexitat, així que concentrem-nos en Optional i Option, no als repositoris.

Trobar cotxes amb Java opcional

Creeu una prova nova amb JUnit:

@Test void getCarById(){ Car car = repository.findCarById('1A9 4321'); Assertions.assertNotNull(car); Car nullCar = repository.findCarById('M 432 KT'); Assertions.assertThrows(NullPointerException.class, ()->{ if (nullCar == null){ throw new NullPointerException(); } }); }

El fragment de codi anterior mostra l'antiga manera. Hem trobat un cotxe amb la matrícula txeca 1A9 4321 i comprovat que existeix. Després vam trobar un cotxe absent, ja que té una matrícula russa i només en tenim de txecs al dipòsit. És nul , de manera que pot conduir a NullPointerException.

A continuació, passem a les opcions de Java. El primer pas és obtenir un Optional instància del dipòsit mitjançant un mètode dedicat que retorna Optional:

@Test void getCarByIdWithOptional(){ Optional tesla = repository.findCarByIdWithOptional('1A9 4321'); tesla.ifPresent(System.out::println); }

En aquest cas, fem servir el findCarByIdWithOptional mètode i imprimeix un cotxe (si es presenta). Si l’executeu, obtindreu la següent sortida:

Car tesla with license id 1A9 4321 and of color red

Però, què passa si no tenim aquest mètode especial al nostre codi? En aquesta situació, podem obtenir Optional d'un mètode que potencialment podria retornar un valor nul. Es diu nullable.

Optional nothing = Optional.ofNullable(repository.findCarById('5T1 0965')); Assertions.assertThrows(NoSuchElementException.class, ()->{ Car car = nothing.orElseThrow(()->new NoSuchElementException()); });

En aquest fragment de codi, hem trobat una altra manera. Creem Optional de findCarById i això pot tornar nul si no es troba cap cotxe. Utilitzem manualment el orElseThrow mètode per llançar un NoSuchElementException quan el cotxe desitjat amb la matrícula 5T1 0965 és present. Una altra situació és utilitzar orElse amb un valor per defecte si les dades sol·licitades no estan disponibles al dipòsit:

Car audi = repository.findCarByIdWithOptional('8E4 4311') .orElse(new Car('audi', '1W3 4212', 'yellow')); if (audi.getColor().equalsIgnoreCase('silver')){ System.out.println('We have silver audi in garage!'); } else { System.out.println('Sorry, there is no silver audi, but we called you a taxi'); }

D’acord, no tenim l’Audi de plata al nostre garatge, així que hem de trucar a un taxi.

Trobar cotxes amb l’opció Vavr

Vavr Option és una altra manera de gestionar aquestes tasques. Primer, instal·leu Vavr al vostre projecte amb la gestió de dependències (faig servir Maven):

io.vavr vavr 0.10.2

En poques paraules, Vavr té API similars per crear Option casos. Podem crear Option des de nul·la, com es mostra aquí:

Option nothing = Option.of(repository.findCarById('T 543 KK'));

O podem crear un fitxer buit contenidor amb el none mètode estàtic:

Option nullable = Option.none();

A més, hi ha una manera de crear Option de Java Optional! Mireu el fragment de codi següent:

Option result = Option.ofOptional(repository.findCarByIdWithOptional('5C9 9984'));

Amb Vavr Option, podem utilitzar la mateixa API que amb Optional per dur a terme les tasques esmentades anteriorment. Per exemple, podem establir un valor per defecte d'una manera similar:

Option result = Option.ofOptional(repository.findCarByIdWithOptional('5C9 9984')); Car skoda = result.getOrElse(new Car('skoda', '5E2 4232', 'pink')); System.out.println(skoda);

O podem llançar una excepció en funció de l'absència de dades sol·licitades:

Option nullable = Option.none(); Assertions.assertThrows(NoSuchElementException.class, ()->{ nullable.getOrElseThrow(()->new NoSuchElementException()); });

Com a alternativa, podem fer una acció quan les dades no estiguin disponibles:

nullable.onEmpty(()->{ ///runnable });

Què passa si hem de dur a terme una acció basada en la presència de dades, tal com hem fet amb ifPresent d’Optional? Ho podem fer de diverses maneres. Hi ha un mètode igual a isPresent a Optional que a Option es diu isDefined:

if (result.isDefined()){ // do something }

Tot i això, fem servir Option per desfer-se de les construccions if-else. Podem flotar de la mateixa manera que amb Optional? Podem realitzar operacions basades en l'existència amb peek:

result.peek(val -> System.out.println(val)).onEmpty(() -> System.out.println('Result is missed'));

A més, hi ha alguns altres mètodes molt útils a Vavr Option que pot fer que el vostre codi sigui encara més funcional que amb el Optional integrat classe. Per tant, us animo a que preneu una mica de temps i exploreu l'opció Vavr javadocs i experimentar amb aquestes API. Seguiré endavant i anotaré algunes funcions interessants com map, narrow, isLazy i when que definitivament haureu de comprovar.

A més, Vavr Option forma part de la família Vavr i està molt integrat amb altres classes de Vavr, i fer aquesta comparació amb Opcional en absència d’aquestes classes no és correcte. Per tant, també tinc previst escriure altres articles sobre temes de Vavr com Proveu-ho , Col·leccions i corrents. Estigueu atents!

Conclusió

En aquest post, parlem del Optional classe a Java. El concepte de Optional no és una cosa nova i ja s'ha implementat en altres llenguatges de programació funcionals com Haskell i Scala. Resulta molt útil a l’hora de modelar casos en què una trucada de mètode pot retornar un valor desconegut o un valor que no existeix (per exemple, nuls). Després, vam explorar les seves API i vam crear alguns exemples de cerca de cotxes i manipulació de resultats amb Optional lògica. I, finalment, vam descobrir una alternativa a Optional - Vavr’s Option i va descriure també els seus mètodes.

Espero que us hagi agradat! Assegureu-vos de deixar pensaments o preguntes als comentaris.

#java