Java - 将元素添加到空集(不可变)

时间:2017-03-10 00:23:32

标签: java methods data-structures set immutability

我一直在尝试从头开始实现一个不可变集,所以我没有使用HashSet或java.util.Set

我在Empty类中使用此方法将元素添加到空集:

public Set<T> add(T x) {
  return new Element<T>(x, new Empty<T>());
}

在另一个名为Element的类中,我有以下构造函数:

     public Element(T element, Empty<T> empty) {
     assert(element != null);
     assert(empty != null);

     this.element = element;
     this.set = empty;
   }

编辑:这是我的另一个Element构造函数,用于向集合中添加元素。

public Element(T x, Set<T> set) {
            this.element = x;
            this.set = set;
        }

但是当我尝试添加一个元素时,它失败并且该集仍然是空的。 我在创建一个不可变的二进制搜索树时使用了类似的代码并且它工作正常,所以我假设我可以做同样的但是对于一个不可变的Set。

我只是想知道问题是我的add方法还是我的构造函数

谢谢

尺寸方法: 对于Empty类

/**
     * returns number of elements in the set
     * @return size  - number of elements in the set
     */
    public int size(){
        return -1;
        }

表示元素类:

   @Override
        public int size() {
            if (set.isEmpty() == true) {
                return -1;
            } else {
                return set.toList().size();
            }
        }

toList()方法:

@Override
    public List<T> toList() {
        List<T> list = new ArrayList<T>();
        int i;
        for(i = 0; i < set.size(); i++){
            list.set(i, element);
        }
        return list;
    }

阅读本部分我意识到返回大小的问题可能来自我写的toList方法,但我认为这不应该对向集合中添加元素产生影响吗?

toString - 元素类:

 @Override
        public String toString() {
            return "Set = [" + set + "]";
        }

toString - 空类:

public String toString() {
        return "";
    }

JUnit Test for Add: 编辑:意识到该集是不可变的,所以试图创建一个新的集合,该集合等于具有附加值的空集 - 存储更改但保持得到相同的NullPointerException错误。

 @Test
        public final void testAdd() {
            Set<Integer> set1;
            set1 = set.add(1);
            int i = 20;
            set.add(i);

            assertSame("Last element should be the newly added name object", i, set.toList().get(set.size()-1));
            assertEquals("Set size should be two", 2, set.size());
        }

assertSame给出了一个NullPointerException(所以我猜测这意味着添加没有工作,并且该集仍然是空的);如果我把它注释掉来测试下一行,那么assertEquals说set.size()是-1(空)

2 个答案:

答案 0 :(得分:0)

现有代码中的几乎所有内容都存在缺陷。您的Element的ctor没有意义,size()toList()以奇怪的方式实现,即使单元测试在基本Java中存在缺陷。

一些伪代码

interface Set<T> {
  Set<T> add(T v);
  int size();
  boolean contains(T v);
}

class Element<T> extends Set<T> {
  T value;
  Set<T> next;
  public Element<T>(T element, Set<T> next) {...}

  public Set<T> add(T value) {
    if contains(value) { // already in set
      return this;
    }
    return new Element(value, this);
  }
  public int size() {
    return next.size() + 1;
  }
  public boolean contains(T value) {
    return (this.value.equals(value) || next.contains(value));
  }
}

public class Empty<T> extends Set<T> {

  public Set<T> add(T value) {
    return new Element(value, this);
  }
  public int size() {
    return 0;  // come on! 0 means empty, not -1!
  }
  public boolean contains(T value) {
    return false;
  }
}

答案 1 :(得分:-1)

审查了我的代码之后,我意识到我犯了错误。

除了其他方面的凌乱代码之外,add(T x)方法没有按预期工作,因为我没有将Empty或Element类导入Demo集或JUnit测试,如上所述通过@shmosel,我的toString方法无法正常工作,因为我没有包含元素字段,因此不会输出任何内容。

以下是我的演示代码,显示我是如何添加导入行的。此外,Element的构造函数也可以正常工作。同样,我只需要导入一个空集的类来使其工作。

 package immutable.set;

    import immutable.set.Empty;

    public class DemoSet {

        public static void main(String[] args) {
            Set<Integer> set, set1, set2;

            set = new Empty<Integer>();
            System.out.println(set.isEmpty());

            set1 = set.add(1).add(2);
            set2 = set.add(3);

            System.out.println(set1.toString());
            System.out.println(set1.isEmpty());
            System.out.println(set2.toString());
            System.out.println(set2.isEmpty());

        }

    }

它确实打印出了预期的结果。

谢谢你的帮助。