如何在Java 8中包含upcast对象可选?

时间:2017-06-30 18:38:33

标签: java oop design-patterns java-8 optional

使用Optional对象时是否有一种有效的方法来执行向上转换。 以下是示例代码:

class A{}
class B extends A{}

B func(){
    //do something
    return new B();
}

Optional<B> func2(){
    //do something
    return Optional.of(new B());
}

main() {
    A a = func(); // Upcasting works fine
    B b = func(); // Upcasting works fine
    Optional<B> b = func2(); // 1. Works fine
    Optional<A> a = func2(); // 2. How to make this work ?
}

(2。)给出错误。我可以通过创建另一个函数来解决它。

但是有没有一种有效的方法,所以func2()可以同时用于(1.)和(2.)?

4 个答案:

答案 0 :(得分:7)

我会写一个这样的方法:

@SuppressWarnings("unchecked")  // Safe. See below.
static <T> Optional<T> copyOf(Optional<? extends T> opt) {
  return (Optional<T>) opt;
}

(如果您不喜欢名称copyOf,请参阅我对以下番石榴ImmutableList的评论

这在运行时速度方面非常有效:演员在编译时被省略:

static <T> java.util.Optional<T> copyOf(java.util.Optional<? extends T>);
    Code:
       0: aload_0  # Read the parameter.
       1: areturn  # Return the parameter.

所以唯一的代价就是方法调用;这很容易被JIT消除。

然后您可以调用:

Optional<A> a = copyOf(func2());

这是安全的,因为Optional具有以下属性:保证不会因setter方法导致任何状态更改而取决于类型变量T的参数。唷。相当满口。我会让它更具体。

因为Optional

  1. 没有setter方法(任何类型,但更常见的是没有采用类型TSomeGenericType<T>等参数的方法
  2. final(因此您不能将其子类化以添加设置者以违反前一点)
  3. Optional<T>(或者没有)保持{em>不 T的实例(或缺少)的值,你无法做任何事情

    因为T的每个实例也是其超类的一个实例,所以没有什么不安全的:

    SuperclassOfT s = optionalOfT.get();
    

    因此,此方法是类型安全的(如果您在非现有的可选项上调用它,它将失败;但这不是类型错误)。

    你可以在Guava's ImmutableList.copyOf中找到类似的代码(上面提到它的灵感来源&#34; copyOf&#34;即使它不是真正的副本)。在那里, setter方法(如add),但这些方法会立即抛出UnsupportedOperationException,因此不会影响列表的状态。

    请注意,虽然不可变类型具有上述必要属性以使这种类型转换安全,但类型不一定需要是不可变的来安全地执行转换。

    例如,您可以使用ErasableOptional<T>类型,其上有一个erase()方法,在调用时,转换为&#34; present&#34;价值进入&#34;缺席&#34;价值(即get()不再成功)。将此类实例强制转换为ErasableOptional<SupertypeOfT>是安全的,因为该值为T或不存在;你不能 SupertypeOfT或不存在的实例。

答案 1 :(得分:4)

您可以尝试使用映射功能:

var packageContents = {
    'packages': [
        {
            'price': '23',
            'name': 'Bronze Bundle Package',
            'calendar': {
                'type': '2year',
                'color': 'Brushed Nickel',
            },
            'tpoint': {
                'type': '',
                'touches': '',
                'years': '',
            }
        }
    ]
};

var bundleSet = null;

var bundleSet = null;
packageContents.packages.forEach(function (obj) {
    for (var prop in obj) {
        if (prop === 'calendar' || prop === 'tpoint') {
            for (var subProp in obj[prop]) {
                if (obj[prop][subProp] !== '') {
                    bundleSet = true;
                } else {
                    bundleSet = false;
                    var notSelected = (obj.prop.subProp).val() !== '';
                    console.log(notSelected);
                }
            }
        }

    }
    console.log(bundleSet);
});

请注意,您并非真的需要将Optional<A> oa = func2().map(v -> (A) v); 演员放在那里,但它会让您更清楚一些事情。

答案 2 :(得分:4)

可选,引自java doc:

  

一个容器对象,可能包含也可能不包含非null值....   取决于是否存在的其他方法   包含,例如orElse()......

正如我们所见,可选容器,使用泛型类型来定义要包含的对象。

Optional <T>

所以你可以这样做:

Optional<? extends A> a = func2(); // 2. Upcasting Will work :)

并且为可选对象访问类型为A的对象:

a.get();

答案 3 :(得分:0)

我认为最干净的方法是fragment Optional<A> a = func2().flatMap(Optional::of),因为两者都不需要强制转换并且仅使用现有功能。