Performance of Java Optional

前端 未结 3 2215
野的像风
野的像风 2020-12-09 03:37

I just stumbled upon the Optional class in Java 8 - I really like the approach of replacing some of the null checks (which literally means \"is the value present?\") in my c

3条回答
  •  南笙
    南笙 (楼主)
    2020-12-09 03:39

    I did some performance testing using an algorithm that heavily uses null checks as well as access to a potentially nullable field. I implemented a simple algorithm that removes the middle element from the single linked list.

    First I implemented two classes of linked list node: safe - with Optional and unsafe - without.

    Safe Node

    class Node {
        private final T data;
        private Optional> next = Optional.empty();
    
        Node(T data) {
    
            this.data = data;
        }
    
        Optional> getNext() {
            return next;
        }
    
        void setNext(Node next) { setNext(Optional.ofNullable(next)); }
    
        void setNext(Optional> next ) { this.next = next; }
    }
    

    Unsafe Node

    class NodeUnsafe {
        private final T data;
        private NodeUnsafe next;
    
        NodeUnsafe(T data) {
            this.data = data;
        }
    
        NodeUnsafe getNext() {
            return next;
        }
    
        void setNext(NodeUnsafe next) {
            this.next = next;
        }
    }
    

    Then I implemented two similar methods with the only difference - first uses Node and the second uses NodeUsafe

    class DeleteMiddle {
        private static  T getLinkedList(int size, Function supplier, BiConsumer 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 head){
            Optional> oneStep = Optional.of(head);
            Optional> doubleStep = oneStep;
            Optional> prevStep = Optional.empty();
    
            while (doubleStep.isPresent() && doubleStep.get().getNext().isPresent()){
                doubleStep = doubleStep.get().getNext().get().getNext();
                prevStep = oneStep;
                oneStep = oneStep.get().getNext();
            }
    
            final Optional> toDelete = oneStep;
            prevStep.ifPresent(s->s.setNext(toDelete.flatMap(Node::getNext)));
        }
    
        private static void deleteMiddleUnsafe(NodeUnsafe head){
            NodeUnsafe oneStep = head;
            NodeUnsafe doubleStep = oneStep;
            NodeUnsafe 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 head = getLinkedList(size, Node::new, Node::setNext);
            Long before = System.currentTimeMillis();
            deleteMiddle(head);
            System.out.println("Safe: " +(System.currentTimeMillis() - before));
    
            NodeUnsafe headUnsafe = getLinkedList(size, NodeUnsafe::new, NodeUnsafe::setNext);
            before = System.currentTimeMillis();
            deleteMiddleUnsafe(headUnsafe);
            System.out.println("Unsafe: " +(System.currentTimeMillis() - before));
        }
    }
    

    Comparison of two several runs with different size of the list shows that approach with code that uses Optionalat the best is twice slower than one with nullables. With small lists it is 3 times slower.

提交回复
热议问题