当前位置: 首页 > 知识库问答 >
问题:

删除地图条目会导致地图条目中的对象引用发生更改(可选)

韩阳飙
2023-03-14

当我从地图检索地图条目时,将其存储在可选中,然后使用remove(entry.getKey())从地图中删除相同的条目,然后可选的突然开始指向地图中可用的下一个地图条目。

让我进一步解释一下:

我有一堆要排序的注释对象。注释列表应始终以被接受为答案的注释开始,它应是列表中的第一个元素。排序方法从一个映射开始,并使用entrySet上的流检索第一条注释,该注释的布尔值设置为true。

Map<Long, CommentDTO> sortedAndLinkedCommentDTOMap = sortCommentsAndLinkCommentRepliesWithOwningComments(commentDTOSet);
Optional<Map.Entry<Long, CommentDTO>> acceptedAnswerCommentOptional = sortedAndLinkedCommentDTOMap.entrySet().stream()
        .filter(entry -> entry.getValue().isAcceptedAsAnswer()).findFirst();

假设Map包含3个id3、6和11的注释。键始终是注释的id,注释始终是值。标记为答案的注释具有id6。在这种情况下,执行以下代码:

if(acceptedAnswerCommentOptional.isPresent()){
    Map.Entry<Long, CommentDTO> commentDTOEntry = acceptedAnswerCommentOptional.get();
    sortedAndLinkedCommentDTOMap.remove(commentDTOEntry.getKey());
}

当使用acceptedAnswerCommentOptional的值初始化commentDTOEntry时,它会引用id为6的已接受答案。现在,当我从SortedAndLinkedCommentDomain映射中删除该条目时,对接受答案注释的引用不仅会从SortedAndLinkedCommentDomain映射中删除,还会从acceptedAnswerCommentOptional中删除!但现在开始指向sortedAndLinkedCommentDTOMap的下一个条目,即带有键11的条目,而不是变为null。

我不明白是什么导致了这种奇怪的行为。为什么acceptedAnswerCommentOptional的值不变成null?为什么当我从地图中删除接受的回答注释时,它不能保持对接受的回答注释的引用?

当使用调试模式在intellij IDEA中运行代码时,您可以自己看到这种行为,只要将删除方法称为注释的解释性调试标签,注释位于接受答案注释可选的旁边-

编辑:我根据WJSs的意愿制作了一个可重复的示例。这是代码:

import java.util.*;

import java.math.BigInteger;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.function.Function;

class CommentDTO implements Comparable<CommentDTO> {
    private BigInteger id;

    private BigInteger owningCommentId;

    private BigInteger commenterId;

    private Long owningEntityId; 
    private String commenterName;
    private String commenterRole;
    private String country;
    private String thumbnailImageUrl;

    private String content;
    private String commentDateVerbalized;
    private boolean flagged;
    private Integer flagCount;
    private boolean deleted; 
    private boolean liked;
    private Integer likeCount;
    private String lastEditedOnVerbalized;
    private boolean acceptedAsAnswer;
    private boolean rightToLeft;

    private TreeSet<CommentDTO> replies = new TreeSet<>(); 

    public CommentDTO() {
    }
    
    public CommentDTO(boolean acceptedAsAnswer, BigInteger id){
    this.acceptedAsAnswer = acceptedAsAnswer;
    this.id = id;
    }
    
    public CommentDTO(boolean acceptedAsAnswer, BigInteger id, BigInteger owningCommentId){
    this.acceptedAsAnswer = acceptedAsAnswer;
    this.id = id;
    this.owningCommentId = owningCommentId;
    }


    public BigInteger getId() {
        return id;
    }

    public void setId(BigInteger id) {
        this.id = id;
    }

    public BigInteger getOwningCommentId() {
        return owningCommentId;
    }

    public void setOwningCommentId(BigInteger owningCommentId) {
        this.owningCommentId = owningCommentId;
    }

    public BigInteger getCommenterId() {
        return commenterId;
    }

    public void setCommenterId(BigInteger commenterId) {
        this.commenterId = commenterId;
    }

    public Long getOwningEntityId() {
        return owningEntityId;
    }

    public void setOwningEntityId(Long owningEntityId) {
        this.owningEntityId = owningEntityId;
    }

    public String getCommenterName() {
        return commenterName;
    }

    public void setCommenterName(String commenterName) {
        this.commenterName = commenterName;
    }

    public String getCommenterRole() {
        return commenterRole;
    }

    public void setCommenterRole(String commenterRole) {
        this.commenterRole = commenterRole;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getCommentDateVerbalized() {
        return commentDateVerbalized;
    }

    public void setCommentDateVerbalized(String commentDateVerbalized) {
        this.commentDateVerbalized = commentDateVerbalized;
    }

    public boolean isFlagged() {
        return flagged;
    }

    public void setFlagged(boolean flagged) {
        this.flagged = flagged;
    }

    public Integer getFlagCount() {
        return flagCount;
    }

    public void setFlagCount(Integer flagCount) {
        this.flagCount = flagCount;
    }

    public boolean isDeleted() {
        return deleted;
    }

    public void setDeleted(boolean deleted) {
        this.deleted = deleted;
    }

    public boolean isLiked() {
        return liked;
    }

    public void setLiked(boolean liked) {
        this.liked = liked;
    }

    public Integer getLikeCount() {
        return likeCount;
    }

    public void setLikeCount(Integer likeCount) {
        this.likeCount = likeCount;
    }

    public TreeSet<CommentDTO> getReplies() {
        return replies;
    }

    public void setReplies(TreeSet<CommentDTO> replies) {
        this.replies = replies;
    }

    public String getLastEditedOnVerbalized() {
        return lastEditedOnVerbalized;
    }

    public void setLastEditedOnVerbalized(String lastEditedOnVerbalized) {
        this.lastEditedOnVerbalized = lastEditedOnVerbalized;
    }

    public String getThumbnailImageUrl() {
        return thumbnailImageUrl;
    }

    public void setThumbnailImageUrl(String thumbnailImageUrl) {
        this.thumbnailImageUrl = thumbnailImageUrl;
    }

    public boolean isAcceptedAsAnswer() {
        return acceptedAsAnswer;
    }

    public void setAcceptedAsAnswer(boolean acceptedAsAnswer) {
        this.acceptedAsAnswer = acceptedAsAnswer;
    }

    public boolean isRightToLeft() {
        return rightToLeft;
    }

    public void setRightToLeft(boolean rightToLeft) {
        this.rightToLeft = rightToLeft;
    }

    @Override
    public int compareTo(CommentDTO o) {
        return this.id.compareTo(o.id);
    }

    @Override
    public String toString() {
        return "CommentDTO{" +
                "id=" + id +
                ", owningCommentId=" + owningCommentId +
                ", commenterId=" + commenterId +
                ", owningEntityId=" + owningEntityId +
                ", commenterName='" + commenterName + '\'' +
                ", commenterRole='" + commenterRole + '\'' +
                ", country='" + country + '\'' +
                ", thumbnailImageUrl='" + thumbnailImageUrl + '\'' +
                ", content='" + content + '\'' +
                ", commentDateVerbalized='" + commentDateVerbalized + '\'' +
                ", flagged=" + flagged +
                ", flagCount=" + flagCount +
                ", deleted=" + deleted +
                ", liked=" + liked +
                ", likeCount=" + likeCount +
                ", lastEditedOnVerbalized='" + lastEditedOnVerbalized + '\'' +
                ", acceptedAsAnswer=" + acceptedAsAnswer +
                ", rightToLeft=" + rightToLeft +
                ", replies=" + replies +
                '}';
    }
}

public class HelloWorld implements Comparable<HelloWorld> {
    

        private Long id;
        
        private boolean acceptedAsAnswer;
        
        
        public HelloWorld(){}
        
        public HelloWorld(boolean acceptedAsAnswer, Long id){
         this.acceptedAsAnswer = acceptedAsAnswer;
         this.id = id;
        }
        
            @Override
            public String toString() {
             return "id= " + id + " acceptedAsAnswer= " + acceptedAsAnswer;   
                
                
            }
        
        public boolean isAcceptedAsAnswer(){
            return acceptedAsAnswer;
        }
        
        public long getId(){
            return id;
        }
        

     public static void main(String []args){
          HelloWorld helloWorld = new HelloWorld();
          helloWorld.doTest();
        
     }
     
         @Override
    public int compareTo(HelloWorld o) {
        return this.id.compareTo(o.id);
    }
     
      public void doTest(){
          
          Set<CommentDTO> commentDTOSet = new HashSet<>();
            commentDTOSet.add( new CommentDTO(false, BigInteger.valueOf(3)));
            commentDTOSet.add( new CommentDTO(true, BigInteger.valueOf(6)));
            commentDTOSet.add( new CommentDTO(false, BigInteger.valueOf(11)));
            commentDTOSet.add( new CommentDTO(true, BigInteger.valueOf(7), BigInteger.valueOf(6)));
            commentDTOSet.add( new CommentDTO(true, BigInteger.valueOf(8), BigInteger.valueOf(6)));
          
          
        Map<Long, CommentDTO> sortedAndLinkedCommentDTOMap = sortCommentsAndLinkCommentRepliesWithOwningComments(commentDTOSet);

        
        Optional<Map.Entry<Long, CommentDTO>> acceptedAnswerCommentOptional = sortedAndLinkedCommentDTOMap.entrySet().stream()
        .filter(entry -> entry.getValue().isAcceptedAsAnswer()).findFirst();
        
        if(acceptedAnswerCommentOptional.isPresent()){
            Map.Entry<Long, CommentDTO> commentDTOEntry = acceptedAnswerCommentOptional.get();
            System.out.println(commentDTOEntry.toString());
            sortedAndLinkedCommentDTOMap.remove(commentDTOEntry.getKey());
            System.out.println(commentDTOEntry.toString());

        }
     }
     
    private Map<Long, CommentDTO> sortCommentsAndLinkCommentRepliesWithOwningComments(Set<CommentDTO> commentDTOSet){
        Map<Long, CommentDTO> commentDTOMap = commentDTOSet.stream()
                .collect(Collectors.toMap(comment -> comment.getId().longValueExact(), Function.identity(), (v1,v2) -> v1, TreeMap::new));
        commentDTOSet.forEach(commentDTO -> {
            BigInteger owningCommentId = commentDTO.getOwningCommentId();
            if(owningCommentId != null){
                CommentDTO owningCommentDTO = commentDTOMap.get(owningCommentId.longValueExact());
                owningCommentDTO.getReplies().add(commentDTO);
            }
        });
        commentDTOMap.values().removeIf(commentDTO -> commentDTO.getOwningCommentId() != null); 
        return commentDTOMap;
    }

}

您可以在此处运行上面的代码:https://www.tutorialspoint.com/compile_java_online.php

编辑2:示例代码现在再现了我的问题。

编辑3:这一行代码注释tomap。值()。删除(注释至-

共有1个答案

弘涛
2023-03-14

发生这种情况是因为您使用的地图是TreeMap

一个TreeMap实现为红黑树,它是一个自平衡二叉树。

映射的条目用作树的节点。

如果删除一个条目,则树必须重新平衡自身,然后可能会使用该条目来指向替代它的节点。

自树映射。entrySet()由映射支持,更改反映在集合中。

更改还取决于要删除的节点,例如,如果它是一片叶子,那么它可能只是与树断开链接,而条目不受影响。

如果使用另一个map实现,如HashMap,则不会出现这种行为。

顺便说一下,这里有一个更简单的示例,它甚至不涉及可选类或自定义类:

Map<Long, String> map = new TreeMap<>();
map.put(1L, "a");
map.put(2L, "b");
map.put(3L, "c");
map.put(4L, "d");
map.put(5L, "e");
map.put(6L, "f");

Map.Entry<Long, String> entry = map.entrySet().stream()
        .filter(e -> e.getKey().equals(4L))
        .findFirst()
        .get();

System.out.println(entry);   // prints 4=d
map.remove(entry.getKey());
System.out.println(entry);   // prints 5=e
 类似资料:
  • 问题内容: 我需要遍历不知道其参数化类型的映射的条目集。 遍历此类入口集时,为什么不编译呢? 但这编译: 并且也可以编译(由于我不知道地图的类型,所以我不能使用它): 问题答案: 您在第一个错误中遇到的错误是: 这是因为编译器会转换FOR-IN循环: 至: 您的第二个示例有效, 但只能通过作弊! 您正在进行未经检查的演员表转换,以 恢复 到。 成为: 更新资料 如注释中所述,在两个示例中,类型信息

  • 我正在使用AWSJavaSDK的DynamoDBMapper,并处理一个相当简单的项目:它有一个字符串属性(用作哈希键)和一个map属性。 我可以使用和方法读写我的对象。我遇到的问题是,当我需要在映射中为表中的现有项更新或添加单个条目时。在不知道所述项的映射的现有条目的情况下(并且我不想每次尝试更新或添加之前都执行),我似乎能做的最好的事情就是删除整个映射,并用我尝试更新或添加的单个条目替换它。是

  • 问题内容: 有什么办法可以将整个对象放到像这样的对象中: 而不是传递像这样的键值对: 问题答案: 我已经在Map接口方法上进行了搜索,但是没有方法接受一个条目并将其放入地图中。因此,我自己使用一点继承和Java 8接口来实现它。 的接口仅仅是一个扩展的接口通过添加一种以上的方法,该接口。除了仅定义方法外,还对默认实现进行了编码。这样做,我们现在可以通过定义一个新的实现接口的类并扩展我们选择的map

  • 如果我试图在不调用构造函数的情况下创建映射,则该对象不可用: 出于好奇,我想知道条目存储在哪里,但构造函数似乎没有添加属性: 你知道吗?

  • 结果,我收到一个System.io.Exception: npgsql.npgsqlexception(0x80004005):从流中读取时出现异常-->system.io.ioexception:冯·德·贝尔特拉贡斯维宾登·科恩·基恩·达滕·盖勒森·韦登:艾因·维宾登·维萨奇·费尔格斯拉根,达·迪·盖根斯泰尔·纳赫·艾纳·贝斯特姆滕·泽斯潘尼·尼赫特·里希蒂格·雷杰特帽子,奥德·迪·赫尔杰斯特·

  • 给定一个 如何通过流将和的值提取到以下内容中? 我尝试了以下方法,但在获取列表值的部分遇到了问题。