Tôi đã thực hiện một số thử nghiệm hiệu suất bằng cách sử dụng thuật toán sử dụng rất nhiều kiểm tra null cũng như quyền truy cập vào trường có khả năng không có giá trị. Tôi đã triển khai một thuật toán đơn giản loại bỏ phần tử ở giữa khỏi danh sách liên kết đơn lẻ.
Trước tiên, tôi đã triển khai hai lớp nút danh sách được liên kết: an toàn - với tùy chọn và không an toàn - không có.
Node Safe
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; }
}
Node không an toàn
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;
}
}
Sau đó, tôi thực hiện hai phương pháp tương tự với sự khác biệt duy nhất - đầu tiên sử dụng Node<T>
và thứ hai sử dụng NodeUsafe<T>
lớp 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));
}
}
So sánh hai lần chạy với kích thước khác nhau của danh sách cho thấy cách tiếp cận với mã số sử dụng Optional
ở mức tốt nhất là hai lần chậm hơn một với nullables. Với các danh sách nhỏ, nó chậm hơn 3 lần.
Nguồn
2017-02-11 18:31:24
Tại sao bạn không đánh giá nó? –
bạn không nên làm 'isPresent', thay vào đó sử dụng' map' và 'orElse'. –
@ Łukasz: Điều đó cần biện minh. Đôi khi nó đúng, nhưng nếu bạn muốn thực hiện tác vụ phụ khi giá trị có mặt, bạn sẽ làm gì nếu không 'if (isPresent()) doSomething()'? Cả bản đồ lẫn orElse đều không có ý nghĩa ở đó. –