2014-10-15 2 views
4

Я преобразовал некоторый код, чтобы использовать функции Java 8. В следующем примере надуманногоТип вывода на lambdas

Arrays.asList("1", "2", "3", "cheese", "5").stream().map(line -> { 
     try { 
      return Optional.of(Integer.parseInt(line)); 
     } catch (NumberFormatException xep) { 
      return Optional.empty(); 
     } 
    }).forEach(v -> 
     System.out.println(v.orElse(999)) 
    ); 

(намерение, чтобы разобрать некоторые строки как Интс и замените значения с не поддается синтаксическим анализ 999)

Компилятор отчеты

error: incompatible types: int cannot be converted to CAP#1 
System.out.println(v.orElse(999)) 
where CAP#1 is a fresh type-variable: 
CAP#1 extends Object from capture of ? extends Object" 

Я пробовал литье 999 к Integer или Object без успеха.

Кажется, что реальная проблема заключается в том, что выведенный тип возврата первого лямбда является Optional<Object> и не Optional<Integer>

Если я это

Arrays.asList("1", "2", "3", "cheese", "5").stream().map(line -> { 
     Optional<Integer> ans; 
     try { 
      ans = Optional.of(Integer.parseInt(line)); 
     } catch (NumberFormatException xep) { 
      ans = Optional.empty(); 
     } 
     return ans; 
    }).forEach(v -> 
     System.out.println(v.orElse(999)) 
    ); 

он прекрасно работает, но не совсем так элегантно. Есть ли лучший способ «направить» компилятор на возвращаемый тип, который я хочу?

+2

вы пытались использовать 'Дополнительно пустой()' –

ответ

4

Простое исправление использовать тип цели:

return Optional.<Integer> empty(); 

Также замечу, что вы используете Integer.parseInt, который возвращает int, так что вы можете также использовать OptionalInt, который позволит решить проблему и сохранить операцию по боксу :

try { 
    return OptionalInt.of(Integer.parseInt(line)); 
} catch (NumberFormatException xep) { 
    return OptionalInt.empty(); 
} 
+1

Re: 'OptionalInt' - хороший момент, хотя я был только.? используя 'int' как si Пример. Моя реальная проблема в том, что я просто не могу вспомнить, что параметризованный тип приходит _after_ точка - я попробовал «Необязательный .empty()», а затем отказался от этого подхода! –

1

вы могли бы это сделать, если вы не хотите переменную-член ans:

try { 
    return Optional.<Integer>of(Integer.parseInt(line)); 
} catch (NumberFormatException xep) { 
    return Optional.<Integer>empty(); 
} 

Тип вывода сложный и имеет ограничения, если вы действительно хотите знать, почему это происходит в этом случае, вам нужно изучить Java Language Specification.

+0

Нет необходимости в целевом типе в блоке try – assylias

+0

@assylias Я просто попробовал, вы правы. Странно, хотя в этом нет необходимости ... – Jesper

+2

Я полагаю, что 'Optional.of (someInteger)' явно является «Необязательным », тогда как компилятор не может определить общий тип 'Optional.empty()' без дополнительных контекст. – assylias

1

Правильность @Assilyas answer. Я хотел бы предложить альтернативу на основе гуавы утилиты Ints::tryParse:

В отличие от Integer.parseInt(String), этот метод возвращает нуль, а не бросать исключение, если синтаксический анализ терпит неудачу

с ним и новый method references, вы могли бы написать:

Arrays.asList("1", "2", "3", "cheese", "5") 
     .stream() 
     .map(Ints::tryParse) 
     .map(Optional::ofNullable) 
     .forEach(v -> System.out.println(v.orElse(999))); 
3

Как said by assylias, вы можете исправить это с помощью return Optional.<Integer> empty();.

Однако, большой вопрос, почему вы используете Optional здесь вообще?

Stream.of("1", "2", "3", "cheese", "5").mapToInt(line -> { 
    try { 
     return Integer.parseInt(line); 
    } catch (NumberFormatException xep) { 
     return 999; 
    } 
}).forEach(System.out::println); 

делает работу намного проще, если вы все равно хотите заменить значение.

Если вы хотите, чтобы выполнить действие для действительных значений только (эквивалент Optional.ifPresent(Consumer)) вы можете рассмотреть правила, которые вы должны предпочесть предварительные проверки через перехват исключений, когда вы ожидать недопустимых значений:

Stream.of("1", "2", "3", "cheese", "5") 
     .filter(Pattern.compile("^[+-]?[0-9]{1,9}$").asPredicate()) 
     .mapToInt(Integer::parseInt) 
     .forEach(System.out::println); 

(я упростил регулярное выражение, оно не принимает все возможные значения int но отвергнет все недействителен)

+0

«int» был просто простым примером, мой фактический код включал поиск вещей в сложном объекте, подобном карте. Спасибо за 'Stream.of()' хотя, я не знал об этой функции. –

+0

Понятно, что это всего лишь простой пример, но шаблоны все еще применяются: вам не нужно «Необязательно», если вы используете 'orElse' в рамках одной и той же операции потока, и вы можете рассмотреть предварительную проверку при ловле. Так же, как пища для размышлений ... – Holger