有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

数据结构一个Java集合最多可容纳2个对象

我正在编写一个返回Set<String>的方法。该集合可以包含0、1或2个对象。字符串键也很小(最多8个字符)。然后,该集合在一个紧密循环中使用,多次迭代调用contains()

对于0个对象,我将返回Collections.emptySet()

对于1对象,我将返回Collections.singleton()

对于2个对象(可能的最大数量),一个HashSet似乎是杀伤力过大。难道没有更好的结构吗?也许TreeSet稍微好一点?不幸的是,我仍然在使用Java7:-(因此不能使用像Set.of()这样的现代工具)

由2个字符串组成的数组可能会提供最佳性能,但这不是一组。我希望代码是自文档化的,所以我真的希望返回一个集合,因为这是所需的逻辑接口


共 (3) 个答案

  1. # 1 楼答案

    The set is then used in a tight loop with many iterations calling contains().

    我可能会为此简化它。也许是这样的:

    public static class TwoSet<T> extends AbstractSet<T> {
        T a = null;
        T b = null;
    
        @Override
        public boolean contains(Object o) {
            return o.equals(a) || o.equals(b);
        }
    
        @Override
        public boolean add(T t) {
            if(contains(t)){
                return false;
            }
            if ( a == null ) {
                a = t;
            } else if ( b == null ) {
                b = t;
            } else {
                throw new RuntimeException("Cannot have more than two items in this set.");
            }
            return true;
        }
    
        @Override
        public boolean remove(Object o) {
            if(o.equals(a)) {
                a = null;
                return true;
            }
            if(o.equals(b)) {
                b = null;
                return true;
            }
            return false;
        }
    
        @Override
        public int size() {
            return (a == null ? 0 : 1) + (b == null ? 0 : 1);
        }
    
        @Override
        public Iterator<T> iterator() {
            List<T> list;
            if (a == null && b == null) {
                list = Collections.emptyList();
            } else {
                if (a == null) {
                    list = Arrays.asList(b);
                } else if (b == null) {
                    list = Arrays.asList(a);
                } else {
                    list = Arrays.asList(a, b);
                }
            }
            return list.iterator();
        }
    
    }
    
  2. # 2 楼答案

    你可以通过

    • 创建一个实现Set接口的类
    • 重写添加和删除方法
    • 通过super.add(E element)初始化类时添加值
    • 改用那个类
  3. # 3 楼答案

    只需用AbstractSet包装一个数组。假设您想要一个不可修改的集合,则只需实现2种方法:

      class SSet extends AbstractSet<String> {
        private final String[] strings;
    
        SSet(String[] strings) {
          this.strings = strings;
        }
    
        @Override
        public Iterator<String> iterator() {
          return Arrays.asList(strings).iterator();
        }
    
        @Override
        public int size() {
          return strings.length;
        }
      }
    

    如果需要,可以在字段中存储Arrays.asList(strings)而不是String[]。如果希望将数组限制为该长度,还可以提供0、1和2-arg构造函数

    您还可以覆盖contains

    public boolean contains(Object obj) {
      for (int i = 0; i < strings.length; ++i) {
        if (Objects.equals(obj, strings[i])) return true;
      }
      return false;
    }
    

    如果您不想创建一个列表来创建一个迭代器,您可以简单地将其实现为一个内部类:

    class ArrayIterator implements Iterator<String> {
      int index;
    
      public String next() {
        // Check if index is in bounds, throw if not.
        return strings[index++];
      }
    
      public boolean hasNext() {
        return index < strings.length;
      }
    
      // implement remove() too, throws UnsupportedException().
    }