0

values in the code below comes from redis. What's the best way to convert it back to a list of Items. I am new to Java and have this code below but I am hoping there's a better way?

@AllArgsConstructor
public class Item {
  public String key;
  public Map<String, Integer> values;
}


public static List<Item> getItems() {

  Map<String, String> values = Map.of("k1", "{\"key1\":1,\"key2\":2}", "k2", "{\"key1\":3,\"key2\":4}");
  
  List<Item> items = values.entrySet().stream().map(entry -> {
    try {
      TypeReference<HashMap<String, Integer>> typeRef = new TypeReference<HashMap<String, Integer>>() {};
      var itemValues = new ObjectMapper().readValue(entry.getValue(), typeRef);
      return Optional.of(new Item(entry.getKey(), itemValues));
    } catch (JsonProcessingException ex) {
      Optional<Item> emptyItem = Optional.empty();
      return emptyItem;
    }
  }).flatMap(Optional::stream).collect(Collectors.toList());
  return items;
}

pradhyo
  • 157
  • 1
  • 2
  • 19

2 Answers2

0

Immutable values should be declared as constants. The part that throws an exception in the lambda expression should be a separate method.

static final TypeReference<HashMap<String, Integer>> TYPEREF_MAP =
    new TypeReference<HashMap<String, Integer>>() {};

static final Map<String, String> ITEM_VALUES = Map.of(
    "k1", "{\"key1\":1,\"key2\":2}",
    "k2", "{\"key1\":3,\"key2\":4}");

static final HashMap<String, Integer> FAILED_MAP = new HashMap<>();

static HashMap<String, Integer> toMap(String s) {
    try {
        return new ObjectMapper().readValue(s, TYPEREF_MAP);
    } catch (JsonProcessingException e) {
        return FAILED_MAP;
    }
}

public static List<Item> getItems() {
    return ITEM_VALUES.entrySet().stream()
        .map(entry -> new Item(entry.getKey(), toMap(entry.getValue())))
        .filter(item -> item.getValues() != FAILED_MAP)
        .collect(Collectors.toList());
}
  • that's definitely cleaner but what if I needed to convert to an object instead of `toMap` where the function could default to return an empty Map when there are exceptions? Is there a way to use flatMap to ignore the `Optional.empty()` values somehow? I couldn't find something like [Scala's flatten](https://stackoverflow.com/a/2895185/7788900) for this. – pradhyo Oct 05 '22 at 14:28
  • @pradhyo I changed my answer. I may not agree with you, but I think you can do what you want. –  Oct 05 '22 at 14:45
0

Instead of using Optional to manage the default case, you can use Stream's flatMap.

MAPPER.readerForMapOf is a shortcut of new TypeReference<..>

public class Example {
    
    static final ObjectMapper MAPPER = new ObjectMapper();
    
    static final Map<String, String> ITEM_VALUES = Map.of(
        "k1", "{\"key1\":1,\"key2\":2}",
        "k2", "{\"key1\":3,\"key2\":4}"
    );

    static Stream<Item> toItemOrEmpty(Map.Entry<String, String> entry) {
        try {
            return Stream.of(
                new Item(
                    entry.getKey(),
                    MAPPER.readerForMapOf(Integer.class).readValue(entry.getValue())
                )
            );
        } catch (Exception e) {
            return Stream.empty();
        }
    }

    public static List<Item> getItems() {
        return ITEM_VALUES
            .entrySet()
            .stream()
            .flatMap(Example::toItemOrEmpty)
            .collect(Collectors.toList());
    }

}