Jav*_*tín 13
Optional<T>它只是一个普通的泛型类,它包含一个类型为T的引用.因此,它添加了一个单向的间接层.方法调用本身也不会非常昂贵,因为类是final,因此可以避免动态调度.
你可能遇到性能问题的唯一地方就是在处理大量此类实例时,但即便如此,像a这样的东西的表现也一点Stream<Optional<String>>都不差.然而,随着大量的原始值的工作时,你会发现使用性能损失Stream<Integer>(或Integer[])与原始专业化IntStream(或int[])由于这层间接的,需要的非常频繁实例化Integer对象.然而,这是我们已经知道并且在使用类似物时付出的代价ArrayList<Integer>.
您显然会遇到与Stream<OptionalInt>/ 相同的命中OptionalInt[],因为OptionalInt基本上是一个带有int字段和存在boolean标志的类(与Optional<T>仅使用T字段的情况不同)因此非常相似,Integer尽管尺寸更大.当然,a Stream<Optional<Integer>>会增加两个间接级别,相应的双重性能损失.
Yur*_*ian 10
我使用一种大量使用空检查的算法进行了一些性能测试,并访问了一个可能为空的字段.我实现了一个简单的算法,从单个链表中删除中间元素.
首先,我实现了两类链表节点:safe - with Optional和unsafe - without.
安全节点
class Node<T> {
private final T data;
private Optional<Node<T>> next = Optional.empty();
Node(T data) {
this.data = data;
}
Optional<Node<T>> getNext() {
return next;
}
void setNext(Node<T> next) { setNext(Optional.ofNullable(next)); }
void setNext(Optional<Node<T>> next ) { this.next = next; }
}
Run Code Online (Sandbox Code Playgroud)
不安全的节点
class NodeUnsafe<T> {
private final T data;
private NodeUnsafe<T> next;
NodeUnsafe(T data) {
this.data = data;
}
NodeUnsafe<T> getNext() {
return next;
}
void setNext(NodeUnsafe<T> next) {
this.next = next;
}
}
Run Code Online (Sandbox Code Playgroud)
然后我实现了两个相似的方法,唯一的区别 - 第一次使用Node<T>,第二次使用NodeUsafe<T>
类DeleteMiddle {
class DeleteMiddle {
private static <T> T getLinkedList(int size, Function<Integer, T> supplier, BiConsumer<T, T> reducer) {
T head = supplier.apply(1);
IntStream.rangeClosed(2, size).mapToObj(supplier::apply).reduce(head,(a,b)->{
reducer.accept(a,b);
return b;
});
return head;
}
private static void deleteMiddle(Node<Integer> head){
Optional<Node<Integer>> oneStep = Optional.of(head);
Optional<Node<Integer>> doubleStep = oneStep;
Optional<Node<Integer>> prevStep = Optional.empty();
while (doubleStep.isPresent() && doubleStep.get().getNext().isPresent()){
doubleStep = doubleStep.get().getNext().get().getNext();
prevStep = oneStep;
oneStep = oneStep.get().getNext();
}
final Optional<Node<Integer>> toDelete = oneStep;
prevStep.ifPresent(s->s.setNext(toDelete.flatMap(Node::getNext)));
}
private static void deleteMiddleUnsafe(NodeUnsafe<Integer> head){
NodeUnsafe<Integer> oneStep = head;
NodeUnsafe<Integer> doubleStep = oneStep;
NodeUnsafe<Integer> prevStep = null;
while (doubleStep != null && doubleStep.getNext() != null){
doubleStep = doubleStep.getNext().getNext();
prevStep = oneStep;
oneStep = oneStep.getNext();
}
if (prevStep != null) {
prevStep.setNext(oneStep.getNext());
}
}
public static void main(String[] args) {
int size = 10000000;
Node<Integer> head = getLinkedList(size, Node::new, Node::setNext);
Long before = System.currentTimeMillis();
deleteMiddle(head);
System.out.println("Safe: " +(System.currentTimeMillis() - before));
NodeUnsafe<Integer> headUnsafe = getLinkedList(size, NodeUnsafe::new, NodeUnsafe::setNext);
before = System.currentTimeMillis();
deleteMiddleUnsafe(headUnsafe);
System.out.println("Unsafe: " +(System.currentTimeMillis() - before));
}
}
Run Code Online (Sandbox Code Playgroud)
使用不同大小的列表进行的两次运行的比较表明,使用Optional最佳代码的方法比使用nullables的代码慢两倍.使用小列表,它慢3倍.