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

为什么要从树集中删除对象时会出现不受支持的操作异常

郏扬
2023-03-14

我有三门课:

第一张

private List<Domino> pile = new ArrayList<Domino>();    
    
    public DominoPile(List<Domino> list) {
        this.pile = list;
            
    }
    public List<Domino> getList(){
        return List.copyOf(pile);
    }
    public void getOutLastOne() {
        pile.remove(this.getLast(0));
    }
    public Domino getLast(int nbr) {
        return nbr  == 0 || nbr > this.getSize() ? pile.get(pile.size() - 1) : pile.get(pile.size() - 1 - nbr);
    }
    public int getSize() {
        return pile.size();
    }
    
}

第二个

public class KingdominoGameFactory {
    
    private List<Player> pl;
    private List<Domino> dom;
    private int selected;
    private DominoPile pile;
    private int nbrPl;
    
    
    public KingdominoGameFactory(List<Player> p, List<Domino> d) {
        // TODO Auto-generated constructor stub
        this.setPl(List.copyOf(p));
        this.setDom(List.copyOf(d));
    }


    public List<Player> getPl() {
        return pl;
    }


    public void setPl(List<Player> pl) {
        this.pl = pl;
    }


    public List<Domino> getDom() {
        return dom;
    }


    public void setDom(List<Domino> dom) {
        this.dom = dom;
    }


    public int getSelected() {
        return selected;
    }


    public void setSelected(int selected) {
        this.selected = selected;
    }


    public int getNbrPl() {
        return nbrPl;
    }


    public void setNbrPl() {
        if(selected == 0) this.nbrPl = 2;
        else if(selected == 1) this.nbrPl = 3;
        else this.nbrPl = 4;
    }

    public DominoPile getPile() {
        return pile;
    }


    private void setPile(DominoPile pile) {
        this.pile = pile;
    }
    public void nbrDomFinal() {
        if(this.getNbrPl() == 2) this.setPile(new DominoPile(this.getDom().subList(0, 24)));
        else if(this.getNbrPl() == 3) this.setPile(new DominoPile(this.getDom().subList(0, 36)));
        else this.setPile(new DominoPile(this.getDom()));
    }
    public void nbrPlFinal() {
        if(this.getNbrPl() == 2) this.setPl(this.getPl().subList(0, 2));
        else if(this.getNbrPl() == 3) this.setPl(this.getPl().subList(0, 3));
        else this.setPl(this.getPl());
    }

第三个

public class Game {

    private List<Player> players;
    private DominoPile pile;
    private DrawLine actual = new DrawLine(new TreeSet<Domino>());
    private final int nbrDraw;
    
    public Game(KingdominoGameFactory kg){
        this.nbrDraw = kg.getNbrPl() == 3 ? 3 : 4;
        this.pile = new DominoPile(List.copyOf(kg.getPile().getList()));
        this.players = this.getListPlayers();
    }
    private void addActual(){
        actual.add(pile.getLast(0));
    }
    public int getNbrDraw() {
        return nbrDraw;
    }
    public List <Player> getListPlayers(){
        return players;
    }
    public void setDrawActual() {
        actual.clear();
        for(int i = 0; i < nbrDraw; ++i) {
            this.addActual();
            pile.getOutLastOne();
        }
    }
    public DrawLine getActual() {
        return actual;
    }
    
    public DominoPile getPile() {
        return pile;
    }
    
}

然后我做了这个测试

    @BeforeEach
    void setup() {
        List<Domino> liste = new ArrayList<Domino>();
        liste.add(new Domino(1, new Tile(Terrain.CASTLE, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(2, new Tile(Terrain.CASTLE, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(3, new Tile(Terrain.CASTLE, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(4, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(5, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(6, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(7, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(8, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(9, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(10, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(11, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(12, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(13, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(14, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(15, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(16, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(17, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(18, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(19, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(20, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(21, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(22, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(23, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(24, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        liste.add(new Domino(25, new Tile(Terrain.EMPTY, 2), new Tile(Terrain.CASTLE, 1)));
        List<Player> liste2 = new ArrayList<Player>();
        liste2.add(new Player("Jeff", "366"));
        liste2.add(new Player("Jeff", "366"));
        liste2.add(new Player("Jeff", "366"));
        liste2.add(new Player("Jeff", "366"));
        
        kg = new KingdominoGameFactory(liste2, liste);
        kg.setSelected(0);
        kg.setNbrPl();
        kg.nbrDomFinal();
        kg.nbrPlFinal();
        
        game = new Game(kg);
    }


    @Test
    void setActual() {
        game.setDrawActual();
        assertEquals(game.getActual().getSize(), 4);
    }

然后我有这个错误

java.lang.UnsupportedOperationException
    at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:72)
    at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.remove(ImmutableCollections.java:79)
    at kingdomino.domains.DominoPile.getOutLastOne(DominoPile.java:23)
    at kingdomino.domains.Game.setDrawActual(Game.java:35)
    at kingdomino.domains.GameTest.setActual(GameTest.java:87)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)

我不知道为什么我不能从游戏类中删除,因为DominoFile的测试都成功了,这是唯一一个有问题的测试,我不知道如何解决这个问题我已经尝试更改我的集合类型,我也尝试更改我的方法“GetOutlasne”

共有1个答案

公冶桐
2023-03-14

列表。副本

这使得你传递给它的任何东西都是一个不可变的(即只读)副本。复制这些内容没有任何意义(事实上,我相信,如果你在其中传递一个已经不可变的列表,它只会逐字返回;复制无法修改的内容没有任何意义)。

创建DominoPile对象时,传递List的结果。copyOf到它的构造函数,这意味着DominoPile中的pile字段现在是这些不可变列表之一。不久之后,您的代码调用getOutLastOne,它修改(变异)由pile字段引用的列表,该字段不起作用,因为它无法修改。正如例外情况所述。

这就是问题所在。您可以使用3种不同的策略来解决问题。概括地说:

  1. DominoPile的构造函数中记录传入的列表是逐字获取的并将按原样修改,这意味着:它不能是不可变的(现在调用者的职责是阅读文档并按它说的做),并且DominoPile对列表造成的任何影响(例如删除最后一个)首先回响到用于创建DominoPile对象的列表。

完成此操作后(基本上,您需要做的就是添加一些javadoc),然后调用者(您当前有new DominoPile(List.copyOf(kg......)))需要停止传递不可变列表。这很容易-将List.copyOf(X)替换为new ArrayList

或者,你也可以选择一种稍微不同的设计:让DominoPile把提供的列表仅仅当作一个模板,从而让你的DominoPile构造函数创建一个新的(可变的!)列出它的副本。换言之,将此替换为。pile=pile,在构造函数和set方法中,使用this。pile=新阵列列表

DominoPile变得不可变,所有的set方法都需要消失,所有的数据结构都变得不可变,像. getOutLastOne这样的方法实际上并没有删除任何东西(它不能-所有东西都不能被修改),而是它创建了一个全新的DominoPile对象,它是自己的克隆,除了删除了一个多米诺骨牌。现在,如果有什么好处的话,您的列表是不可变的这一事实是一个好处。我认为,这是......在很大程度上过度设计了东西。

这些选项是按照我将如何做的顺序列出的——所以,除非你有一个紧迫的理由为什么第一个选项听起来不好,否则我只会选择第一个,在这里。基于你的API设计(比如拥有一个集合方法,这意味着你似乎并不特别想要不变性)。

 类似资料:
  • 作为测试的一部分,我一直在尝试创建一个用户,然后将其删除,但我不断收到相同的错误组织。冬眠hql。内部的QueryExecutionRequestException:即使在我的存储库和控制器中不断更改代码之后,DML操作也不受支持。 这是我的存储库中的代码: 这是我的控制器中的代码:

  • 通过执行下面的代码,为什么我得到了 这是代码。

  • 当类显式声明复制操作(即复制构造函数或复制赋值操作符)时,不会为该类声明移动操作。但是当类显式声明移动操作时,复制操作被声明为删除。为什么会存在这种不对称?为什么不指定如果声明了移动操作,则不会声明复制操作?据我所知,不会有任何行为差异,也不需要对移动和复制操作进行不对称处理。 [对于喜欢引用该标准的人,12.8/9和12.8/20中规定了具有复制操作声明的类的移动操作声明的缺失,12.8/7和1

  • 问题内容: 我写了一个查询来删除我的扩展接口中的某些对象,但是当我执行查询时,它会抛出异常!谁能为我解释一下? 查询: 我收到了此错误,请问,请为我解释一下,谢谢大家:) 例外: 问题答案: 尝试这个: 每当您尝试修改db中的记录时,都必须将其标记为@Transactional和@Modifying,这将指示Spring可以修改现有记录。 存储库方法必须为空,否则将不断抛出异常。

  • 我已经编写了一个查询来删除扩展接口中的一些对象,但是当我执行查询时,它会抛出一个异常!谁能给我解释一下吗? 查询: 我犯了这个错误,请任何人帮我解释一下,谢谢大家:) 例外情况:

  • 相反,将引发“UnsupportedOperationException”。看起来ContainerRequest没有从修改的请求中提取UserPrincipal。 修改是通过 问题是如何将主体信息从HttpServerProbe传输到ContainerRequestFilter。request具有安全信息(在本例中是SSL客户机证书信息),而com.sun.jersey.spi.containe