Home > front end >  Can this code be reduced using Java 8 Streams?
Can this code be reduced using Java 8 Streams?

Time:12-08

I want to use Java 8 lambdas and streams to reduce the amount of code in the following method that produces an Optional. Is it possible to achieve?

My code:

protected Optional<String> getMediaName(Participant participant) {

  for (ParticipantDevice device : participant.getDevices()) {

      if (device.getMedia() != null && StringUtils.isNotEmpty(device.getMedia().getMediaType())) {

          String mediaType = device.getMedia().getMediaType().toUpperCase();
          Map<String, String> mediaToNameMap = config.getMediaMap();

          if (mediaMap.containsKey(mediaType)) {
              return Optional.of(mediaMap.get(mediaType));
          }
      }
  }
  return Optional.empty();
}

CodePudding user response:

Firstly, since your Map of media types returned by config.getMediaMap() doesn't depend on a particular device, it makes sense to generate it before processing the collection of devices. I.e. regurless of the approach (imperative or declarative) do it outside a Loop, or before creating a Stream, to avoid generating the same Map multiple times.

And to implement this method with Streams, you need to use filter() operation, which expects a Predicate, to apply the conditional logic and map() perform a transformation of stream elements.

To get the first element that matches the conditions apply findFirst(), which produces an optional result, as a terminal operation.

protected Optional<String> getMediaName(Participant participant) {
    
    Map<String, String> mediaToNameMap = config.getMediaMap();
    
    return participant.getDevices().stream()
        .filter(device -> device.getMedia() != null
            && StringUtils.isNotEmpty(device.getMedia().getMediaType())
        )
        .map(device -> device.getMedia().getMediaType().toUpperCase())
        .filter(mediaToNameMap::containsKey)
        .findFirst()
        .map(mediaToNameMap::get);
}

CodePudding user response:

Yes. Assuming the following class hierarchy (I used records here).

record Media(String getMediaType) {
}

record ParticipantDevice(Media getMedia) {
}

record Participant(List<ParticipantDevice> getDevices) {
}

It is pretty self explanatory. Unless you have an empty string as a key you don't need, imo, to check for it in your search. The main difference here is that once the map entry is found, Optional.map is used to return the value instead of the key.

I also checked this out against your loop version and it works the same.

public static Optional<String> getMediaName(Participant participant) {
     Map<String, String> mediaToNameMap = config.getMediaMap();

     return participant.getDevices().stream()
                .map(ParticipantDevice::getMedia).filter(Objects::nonNull)
                .map(media -> media.getMediaType().toUpperCase())
                .filter(mediaType -> mediaToNameMap.containsKey(mediaType))
                .findFirst()
                .map(mediaToNameMap::get);
}
  • Related