2

I have some problems with using Optional.ifPresent statement. I would like to reduce number of NullPointerExceptions, so I decided to use Optional values.

Also I am trying to avoid a ladder of if statements anti-pattern.

So I implemented Optional.isPresent statement. But it's not really that what I expected.

Please look at these listings:

This is a part of my service:

    if (getAllComputerProducers().isPresent()) {
        if (isComputerProducerAlreadyExist(computerProducer))
            return new ResponseEntity<>(HttpStatus.CONFLICT);
    }

    computerProducerRepository.save(computerProducer);
    return new ResponseEntity<>(HttpStatus.CREATED);

getAllComputerProducers function looks like that:

private Optional<List<ComputerProducer>> getAllComputerProducers() {
    return Optional.ofNullable(computerProducerRepository.findAll());
}

As you can see, this function returns Optional of List.

The isComputerProducerAlreadyExist function is implemented like that:

private boolean isComputerProducerAlreadyExist(ComputerProducer computerProducer) {
    return getAllComputerProducers()
            .get()
            .stream()
            .anyMatch(producer -> producer.getProducerName()
                    .equalsIgnoreCase(computerProducer.getProducerName()));
}

It's so much code and I believe that it could be made simpler. My target is to reduce code to one line command like:

getAllCimputerProducers().ifPresent(***and-here-some-anyMatch-boolean-function***)

but I can't insert there a function which returns something. How can I do it?

Regards to everyone :)

Dmitriy Popov
  • 2,150
  • 3
  • 25
  • 34
TravelerVihaan
  • 201
  • 2
  • 6
  • 19
  • 3
    You can't return from the method in which you invoke `ifPresent`, from inside `ifPresent`: it's a fundamental limitation of lambdas. You just have to use an `if` checking `isPresent()`, and return in the block. – Andy Turner Jul 01 '19 at 12:31
  • The [ifPresent](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#ifPresent-java.util.function.Consumer-) has no return value. – Rashin Jul 01 '19 at 12:32
  • 2
    [From a Java Language Architect](https://stackoverflow.com/a/26328555): "_For example, you probably should never use it for something that returns an array of results, or a list of results; instead return an empty array or list._" – Ivar Jul 01 '19 at 12:33
  • But I also can't do something like that: getAllSomething().ifPresent().stream().anyMatch(something-here) I want to check if something in list match to argument given to the function, but only if list exists. – TravelerVihaan Jul 01 '19 at 12:33
  • One of the clean code rules : never return NULL by a function. Instead throw an exception. If you use this rule, you will no need to use Optional at all. – The Bitman Jul 01 '19 at 12:39

3 Answers3

3

You could try something like

private boolean isComputerProducerAlreadyExist(ComputerProducer computerProducer){
    return this.getAllComputerProducers()
            .map((List<ComputerProducer> computerProducers) -> computerProducers.stream()
                    .anyMatch(producer -> producer.getProducerName().equalsIgnoreCase(computerProducer.getProducerName())))
            .orElse(Boolean.FALSE);
}

Or instead of loading all computer producers load only the ones using its name.

private boolean isComputerProducerAlreadyExist(ComputerProducer computerProducer){
    return computerProducerRepository.findByName(computerProducer.getProducerName()).isEmpty();
}

And as far as I know Spring supports also "exist" methods for repositories without even the need to load the Entity.

Smutje
  • 17,733
  • 4
  • 24
  • 41
  • I'm not sure how I completely overlooked that last sentence. But at least I can [confirm](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#new-features.1-11-0) that it is supported from Spring Data JPA 1.11. – Ivar Jul 01 '19 at 12:51
2

The following should work

Predicate<ComputerProducer> cpPredicate = producer -> producer.getProducerName()
    .equalsIgnoreCase(computerProducer.getProducerName());

boolean compProdExists = getAllCimputerProducers()
    .map(list -> list.stream()
        .filter(cpPredicate)
        .findFirst()))
    .isPresent();
Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
1

You can pass the computerProducer.getProducerName() to repository to get the existing record. Method name will be 'findByProducerName(String producerName)', if producerName has unique constraint, return type will be Optional<ComputerProducer>, else Optional<List<ComputerProducer>>. However, JPA returns empty list instead of null, so optional on list is not required.