LinkedHashMap在JDK11中是否存在死代码?

16

我正在阅读JDK 11中LinkedHashMap的源代码,发现了一段死代码(我不确定)。

众所周知,LinkedHashMap使用双向链表来维护所有元素的顺序。它有一个名为accessOrder的成员。

final boolean accessOrder;

默认情况下是 false,但如果设置为 true,则每次运行 get,它都会将获取到的元素移动到链表的末尾。这就是函数 afterNodeAccess 的作用。

//if accessOrder were set as true, after you visit node e, if e is not the end node of the linked list,
//it will move the node to the end of the linkedlist. 
    void afterNodeAccess(Node<K, V> e) {
        LinkedHashMap.Entry<K, V> last;

        if(accessOrder && (last = tail) != e) {

            //if enter `if` ,it indicates that e is not the end of the linked list, because (last=tail!=e)
            //then `a` as the after node of p(p is e after casting to LinkedHashMap.Entry) is never gonna be null. Only if p is last node of the linked list then a will be null.
            LinkedHashMap.Entry<K, V> p = (LinkedHashMap.Entry<K, V>) e, b = p.before, a = p.after;

            p.after = null;

            if(b == null) {
                head = a;
            } else {
                b.after = a;
            }

            // Is the if else clasue redundant? `a` must not be null.. the else clase will never be excuted.
            if(a != null) {
                a.before = b;
            } else {
                last = b;
            }

            if(last == null) {
                head = p;
            } else {
                p.before = last;
                last.after = p;
            }

            tail = p;

            ++modCount;
        }
    }

这里有一个问题:
假设 (accessOrder && (last = tail) != e ,这意味着 e 不是链表的最后一个节点。如果 e 已经是最后一个节点,我们就不需要做什么了对吧?
然后令 a 为 p 的下一个节点(p 是将 LinkedHashMap.Entry 转换后的 e),那么它不能为 null。只有当 p 是最后一个节点时,a 才可能为 null。
那么接下来的代码片段有什么用呢?
 // Is the if else clasue redundant? `a` must not be null.. the else clase will never be excuted.
            if(a != null) {
                a.before = b;
            } else {
                last = b;
            }

a 始终 != null,否则子句 last = b 将永远不会被执行...那么它是死代码吗?

此外,我用 accessorder 设置为 true 进行了一项实验,然后在调试模式下获取了最后一个节点,似乎我永远无法进入上面的 else 子句 last = b

有什么建议吗?


12
我不确定为什么这个问题会遭到任何反对票。它似乎是一个很好的问题。 - John Mercier
4
在我看来,同样地,后续的 last == null 永远不可能为 true。显然,这只是单纯地复制粘贴了普适的单向链表操作,未针对当前情况进行调整。 - Holger
1
@JohnMercier:让我感到担忧的是,你的评论已经有7个赞,而我看到问题本身的支持很少(4个赞)(+1我的)。 - Nikolas Charalambidis
1
@Nikolas 我觉得我漏掉了什么。你的评论让我应该得出什么结论? - John Mercier
2
为什么你的评论被点赞了8次,而问题只有5次?如果一个人同意你的评论,也应该对问题表达同样的感受。这对我来说很奇怪。 - Nikolas Charalambidis
1
在OpenJDK中有很多这样的代码。请随意在core-libs-dev邮件列表上提交补丁。也许你的补丁会被接受。祝你好运。 - Johannes Kuhn
1个回答

4

这个代码是用于单向链表节点删除的算法,它会将被删除的节点作为链表的尾部(重新定位到尾部):

        LinkedHashMap.Entry<K, V> current = (LinkedHashMap.Entry<K, V>) e
        LinkedHashMap.Entry<K, V> pred = current.before, succ = current.after;

        current.after = null;

        // position the successor of the removed node correctly 
        // (either as the head of the list or as the successor of the node BEFORE the removed node)
        if(pred == null) {
            head = succ;
        } else {
            pred.after = succ ;
        }

        // position the predecessor of the removed node correctly
        // (either as the tail of the list or as the predecessor of the node AFTER the removed node)
        if(succ != null) {
            succ.before = pred;
        } else { // unreachable for non tail nodes
            last = pred;
        }

        // final step - if the predecessor of the removed node was null then the head
        // of the list is the removed node (the list contains a single node).
        // otherwise update the removed node as the tail of the list -
        // its predecessor will be the previous tail of the list
        if(last == null) { // unreachable for non tail nodes
            head = current;
        } else { 
            current.before = last;
            last.after = current;
        }

        tail = current;

这个算法处理了将一个节点重新定位为链表尾的所有可能情况。

afterNodeAccess方法的上下文中,由于重新定位的节点永远不会成为列表的尾部,所以一般情况下的算法会存在一些冗余,这要归功于(last = tail) != e。因此,更有效的算法应该是:

        current.after = null;
        // position the successor of the removed node correctly 
        // (either as the head of the list or as the successor of the node BEFORE the removed node)
        if(pred == null) {
            head = succ;
        } else {
            pred.after = succ ;
        }

        // position the predecessor of the removed node correctly
        // (as the predecessor of the node AFTER the removed node)
        // update the removed node as the tail of the list -
        // its predecessor will be the previous tail of the list
        succ.before = pred;
        current.before = last;
        last.after = current;
        tail = current;

正如holger 在评论中提到的,这是一个经典的'复制粘贴'解决方案,我认为在某些情况下重用代码可能会显得低效和不清晰。

Johannes Kuhn所建议的,您可以考虑向OpenJDK社区提交修复无法到达的代码的修复程序。请参阅以下引用了解如何执行此操作:

参考资料:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接