2016-08-11 3 views
2

У меня есть список карт с определенными ключами, которые соответствуют строковым значениям.Java Map Lambda Exception

Что-то вроде List<Map<String,String>> aMapList;

Цель: поток по этому списку карт и собирать значения одного ключа во всех картах.

Как я это делаю ->

key = "somekey"; 
aMapList.stream().map(a -> a.get(key)).collect(Collectors.averagingInt()); 

Проблема: я получаю исключение из-за a.get (ключ), если нет такого ключа! потому что усреднение этого даст нуль. Как проверить или сделать лямбда игнорировать любые такие карты и двигаться дальше.

Я знаю, что я могу добавить фильтр на a -> a.contains(key), а затем продолжить. Редактировать: Я могу добавить еще несколько фильтров или просто проверить несколько условий на одном фильтре. Возможное решение:

aMapList.stream().filter(a -> a.contains(key)). 
     map(a -> a.get(key)).collect(Collectors.averagingInt()); 

Может ли это быть красивей? Вместо того, чтобы останавливать операцию, просто пропустите их? Есть ли еще один общий способ пропускать исключения или нули. Например. Мы можем развернуть лямбда и поставить блок try-catch, но мне все равно нужно что-то вернуть, что, если я хочу сделать эквивалент «продолжить».

Например.

(a -> {return a.get(key) }). 

Может быть расширен ->

(a -> {try{return a.get(key)} 
catch(Exception e){return null} }). 

Значение выше по-прежнему возвращает нуль, а не просто пропуская.

Я выбираю лучший ответ для предоставления двух вариантов, но я не нашел их красивее. Кажется, что для этого подходят цепочки фильтров.

+1

Почему у вас есть исключения? Разве вы не получите нуль? –

+0

Я знаю одно решение. Я просто спрашиваю, могу ли я сделать это короче. Слишком много фильтров выглядят уродливыми и запутывают. – Pranay

+0

@ cricket_007, потому что будущие операции будут вызывать исключение. Я получу нуль, но потом он сломается позже и выбросит исключение. – Pranay

ответ

2

Как насчет обертывание результат с Optional:

List<Optional<String>> values = aMapList.stream() 
      .map(a -> Optional.ofNullable(a.get(key))) 
      .collect(Collectors.toList()); 

Позже код будет знать, предвидеть возможные пустые элементы ,


Решение вы предлагаете имеет потенциальную ошибку для карт, которые позволяют null значения.Например:

Map<String, String> aMap = new HashMap<>(); 
aMap.put("somekey", null); 

aMapList.add(aMap); 

aMapList.straem() 
    .filter(a -> a.contains("somekey")) // true returned for contains 
    .map(a -> a.get("somekey")) // null returned for get 
    .collect(Collectors.toList()); 
+0

Я забыл добавить, что в фильтре я также могу фильтровать нулевые значения. Извини за это. Я имею в виду, что я могу отфильтровать любое количество вещей, объединив фильтры и, таким образом, отфильтровать нуль. Мне было интересно, есть ли способ сделать что-то вроде «try {}, catch {ignore}». Там, где любые такие случаи игнорируются, и мы переходим в список. – Pranay

0

Простейшим я мог придумать было:

aMapList.stream() 
     .filter(map -> map.containsKey(key)) 
     .map(map -> map.get(key)) 
     .collect(Collectors.toList()); 

После форматирования лямбда таким образом, легче увидеть различные шаги, что процессы кода.

+0

Я уже предлагал это как возможное решение. Я пытаюсь спросить, есть ли способ, чтобы моя лямбда продолжала работать, даже если есть какое-то исключение. – Pranay

+0

Я предлагаю форматирование, которое упрощает чтение и понимание лямбда. Я думаю, что эта лямбда (которая, как вы говорите, в основном такая же, как ваша), является самым простым решением. – Jason

0

Хотя я считаю, что это не совсем красивее подход, вы можете сделать:

aMapList.stream().map(a -> a.containsKey(key) ? a.get(key) : null).collect(Collectors.toList()); 
+1

'a.get (key)' возвращает null, поэтому проверка, если он содержит, кажется бессмысленной –

+0

, кроме того, что сказал крикет, я бы добавил еще один фильтр :) – Pranay

2

Основываясь на Map documentation, и на ваш комментарий под ваш вопрос, вы на самом деле не получаю исключение из a.get(key). Скорее, это выражение создает нулевое значение, и у вас возникают проблемы позже, когда вы запускаете эти нулевые значения. Так просто отфильтровывать эти нулевые значения сразу же должны работать нормально:

aMapList.stream() 
    .map(a -> a.get(key)) 
    .filter(v -> v != null) 
    .collect(Collectors.toList()); 

Это похорошела, проще и работает лучше, чем обходной путь в вашем вопросе.

Я должен упомянуть, что я обычно предпочитаю тип Optional<> при работе с нулевыми значениями, но этот подход к фильтрации лучше работает в этом случае, поскольку вы специально сказали, что хотите игнорировать элементы, где ключ не существует в списке карт.

+0

Должно быть 'v! = Null'. –

+1

@LukeLee 'v! = Null' также имеет потенциальную ошибку, когда карта имеет ключ с значением« null ». –

+0

В настоящее время я больше беспокоюсь о том, чтобы не получить правильный результат для обычных случаев. –

Смежные вопросы