将实例转换为设计不良的类型。 尽管如此,在某些情况下没有其他选择。 从第一天开始,这种能力就已经成为Java的一部分。
我认为Java 8提出了对这种古老技术稍加改进的需求。
静态铸造
用Java进行转换的最常见方法如下:
静态铸造
Object obj; // may be an integer
if (obj instanceof Integer) {Integer objAsInt = (Integer) obj;// do something with 'objAsInt'
}
这使用了嵌入到该语言中的instanceof
和cast运算符。 实例转换为的类型(在本例中为Integer
在编译时必须是静态已知的,因此我们将其称为静态转换。
如果obj
不是Integer
,则上述测试将失败。 如果我们尝试将其强制转换,则会得到ClassCastException
。 如果obj
为null
,则它无法通过instanceof
测试,但可以强制转换,因为null
可以是任何类型的引用。
动态铸造
我很少遇到的一种技术是使用Class
上与运算符相对应的方法:
动态转换为已知类型
Object obj; // may be an integer
if (Integer.class.isInstance(obj)) {Integer objAsInt = Integer.class.cast(obj);// do something with 'objAsInt'
}
请注意,尽管在此示例中,在编译时也知道要强制转换为的类,但不一定如此:
动态铸造
Object obj; // may be an integer
Class<T> type = // may be Integer.class
if (type.isInstance(obj)) {T objAsType = type.cast(obj);// do something with 'objAsType'
}
因为类型在编译类型时是未知的,所以我们将其称为动态转换。
类型和空引用错误的实例的测试和转换结果与静态转换完全相同。
在流中投放和可选
现在
转换Optional
的值或Stream
的元素是一个两步过程:首先,我们必须过滤掉错误类型的实例,然后才能将其转换为所需的类型。
使用Class
上的方法,我们使用方法引用来实现。 以Optional
为例:
强制转换
Optional<?> obj; // may contain an Integer
Optional<Integer> objAsInt = obj.filter(Integer.class::isInstance).map(Integer.class::cast);
我们需要两个步骤来执行此操作没什么大不了的,但是我觉得这有点尴尬,而且比必要时更冗长。
未来(也许)
我建议在Class
上实现返回Optional
或Stream
转换方法。 如果传递的实例类型正确,则将返回Optional
或包含转换实例的Singleton Stream
。 否则,两者都将为空。
实现这些方法很简单:
课堂上的新方法
public Optional<T> castIntoOptional(Object obj) {if (isInstance(obj))return Optional.of((T) obj);elseOptional.empty();
}public Stream<T> castIntoStream(Object obj) {if (isInstance(obj))return Stream.of((T) obj);elseStream.empty();
}
这使我们可以使用flatMap一步进行过滤和转换:
该死的FlatMap
Stream<?> stream; // may contain integers
Stream<Integer> streamOfInts = stream.flatMap(Integer.class::castIntoStream);
类型错误或引用为空的实例将使实例测试失败,并导致空的Optional
或Stream
。 永远不会有ClassCastException
。
成本与收益
还需要确定这些方法是否会发挥自己的作用:
- 实际可以使用多少代码?
- 它们会提高普通开发人员的可读性吗?
- 节省一行值得吗?
- 实施和维护它们的成本是多少?
我回答的问题不多 , 很少 , 是的 , 很少 。 因此,它接近于零和游戏,但我确信这是一个很小但不可忽略的收益。
你怎么看? 您看到自己使用这些方法了吗?
翻译自: https://www.javacodegeeks.com/2015/07/casting-in-java-8-and-beyond.html