为什么我需要在这里添加类型,有更好的方法吗?

时间:2018-03-09 11:40:22

标签: java generics types compiler-errors java-8

以下代码无法编译,

  Validation<String, AdRequest> validateTrackingRequest(final AdRequest request) {
    return request.getTracking().stream()
        .filter(tracker -> tracker.url().length() > URL_CHAR_LIMIT).findAny()
        .map(tracker ->
            Validation.invalid("Tracking URL for event " + tracker.type() + " exceeds "
                               + URL_CHAR_LIMIT + " character limit: " + tracker.url()))
        .orElse(Validation.valid(request));
  }

带有错误消息

Incompatible types. Required: Validation<String, AdRequest>. Found Validation<String, Object>.

尝试一下,我发现在调用map之前添加这种奇怪的语法可以解决问题:

        .<Validation<String, AdRequest>>map(tracker ->

(之前我见过其他人这样做过。)

这是什么语法?

我知道发生这种情况是因为Validation.invalid的基础机制必须基于通用Object,因此需要某种类型的转换。所以也许这个语法是&#34; cast&#34;。

但是,还有更好的方式来写我正在做的事情吗?

(这是javaslang a.k.a. vavr的验证库。)

1 个答案:

答案 0 :(得分:3)

它被称为带有显式类型参数的方法调用。你可以使用一种不那么“怪异”的语法:

Validation.<String, AdRequest>invalid(...)

问题在于如何定义Validation.invalid方法以及将在其中调用的上下文。

static <E, T> Validation<E, T> invalid(E error)

无法隐式确定第二个通用参数T,因为map并不关心结果的类型。

// no context
Validation<String, Object> v1 = Validation.invalid("error");

// the context set explicitly 
Validation<String, AdRequest> v2 = Validation.<String, AdRequest>invalid("error");

// the type is determined by the context implicitly
Validation<String, AdRequest> v3 = Validation.invalid("error");

要弄清楚类型,应该存在上下文。 Optional.map没有给你这个背景。它适用于您传递的任何结果类型R

// v1 = Validation<String, Object>
Optional<Validation<String, Object>> o1 = ofNullable(null).map(i -> v1);

// v2 = Validation<String, AdRequest>
Optional<Validation<String, AdRequest>> o2 = ofNullable(null).map(i -> v2);

它将按您提供的类型返回一个通用实例。您正在提供一个Validation<String, Object>对象,因此您收到的map(Function<..., Validation<String, Object>>)会混淆orElse并与返回类型相矛盾。

这是一个品味问题,但我会把一些东西放到变量中:

Validation<String, AdRequest> validateTrackingRequest(AdRequest request) {
    Validation<String, AdRequest> valid = Validation.valid(request);
    Function<Tracker, Validation<String, AdRequest>> mapper = tracker -> Validation.invalid(...);
    Predicate<Tracker> predicate = tracker -> ...;

    return request.getTracking().stream().filter(predicate).findAny().map(mapper).orElse(valid);
}