可选使用地图中的通用通配符和orElseGet

时间:2017-12-07 17:56:26

标签: java generics

我准备了一个小例子来复制我项目中发生的事情。我知道如何解决它,但我很好奇为什么它甚至不编译。问题是在我使用方法public TestElement<?> test()中的通用通配符时的最后一次返回,恰好是行return response.map((element) -> mapAux(50L)).orElseGet(()-> orElseGetAux(20)); ...我不知道它为什么不编译。我究竟做错了什么?任何线索?

提前致谢!

public class FullTest {
  public static class TestElement<T>{
    public T element;

    public TestElement(T t) {
      element = t;
    }
  }

  public static <U> TestElement<U> createElement(U input) {
    return new TestElement<>(input);
  }

  private TestElement<?> mapAux(Long element){
    return new TestElement<>(element);
  }

  private TestElement<?> orElseGetAux(Integer element){
    return new TestElement<>(element);
  }

  public TestElement<?> test(){
    Optional<Long> response =  Optional.of(5L);
    return response.map((element) -> mapAux(50L)).orElseGet(()-> orElseGetAux(20));
  }
}

更新1 - 包含错误

我使用的是Java 8,而不是上一版本的IntelliJ,错误是这样的:

  

错误:(33,78)java:不兼容的类型:lambda表达式中的错误返回类型

FullTest.TestElement<capture#1 of ?> cannot be converted to FullTest.TestElement<capture#2> of ?>

更新2 - 稍微进一步解决方法

使用外卡是因为我需要返回不同类的TesElement<>,这是我找到的唯一方法(在示例中为Long和Integer)。我对其他选择持开放态度......

这里有一个我更喜欢避免的可能的解决方法(这是一个例子,我知道isPresent()总是返回true):

public TestElement<?> testWorkAround(){
    Optional<Long> response =  Optional.of(5L);
    TestElement<?> testElement;
    if(response.isPresent()){
      testElement = mapAux(response.get());
    }
    else{
      testElement = orElseGetAux(20);
    }
    return testElement;
  }

3 个答案:

答案 0 :(得分:1)

您使用lambda map调用(element) -> mapAux(50L)会返回lambda表达式返回的Optional,即Optional<TestElement<?>>。您稍后致电orElseGet也会获取一个返回TestElement<?>的lambda表达式。

但无法保证一个通配符与另一个通配符匹配。通配符表示特定但未知的类型,因此编译器假定它们不匹配。这意味着您会收到编译器错误:

The method orElseGet(Supplier<? extends Main.TestElement<capture#1-of ?>>) in the type Optional<Main.TestElement<capture#1-of ?>> is not applicable for the arguments (() -> {})
Type mismatch: cannot convert from Main.TestElement<capture#3-of ?> to Main.TestElement<capture#1-of ?>

要编译它,你应该删除那些通配符,因此类型推断可以做它的事情和匹配。以下之一:

  1. mapAuxorElseGetAux方法都返回TestElement<Long>

    private TestElement<Long> mapAux(Long element)
    private TestElement<Long> orElseGetAux(Long element)
    
  2. 或者,将这两种方法设为通用的,这样T进入的内容就是T

    private <T> TestElement<T> mapAux(T element)
    private <T> TestElement<T> orElseGetAux(T element)
    

答案 1 :(得分:1)

为什么不这样做?

public TestElement<?> test(){
  Optional<Long> response =  Optional.of(5L);
  Optional< TestElement<?> > opResult = response.map( (element) -> mapAux(50L) );

  TestElement<?> result = opResult.orElseGet( () -> orElseGetAux(20L) );

  return result;
}

答案 2 :(得分:1)

您只需要明确指定它即可:)

public TestElement<?> test() {
   return Optional.of(5L)
       .<TestElement<?>>map(element -> mapAux(50L));
       .orElseGet(() -> orElseGetAux(20L));
}