你可以拥有集合而不用Java存储值吗?

use*_*303 6 java collections iterator set

我有一个关于Java集合的问题,例如Set或List.更常见的是可以在for-each循环中使用的对象.是否有任何要求它们的元素实际上必须存储在数据结构中的某个位置,或者它们是否只能根据某种要求进行描述并在需要时动态计算?感觉这应该可以完成,但我没有看到任何java标准集合类做这样的事情.我在这里违反任何合同吗?

我正在考虑使用它们的主要是数学.比如说我希望有一个代表所有素数低于1 000 000的集合.将它们保存在内存中可能不是一个好主意,而是要检查一个特定数字是否在集合中.

我也不是java流的专家,但我觉得这些应该可以在java 8流中使用,因为对象具有非常小的状态(在你尝试迭代它们之前,集合中的对象甚至不存在或检查集合中是否存在特定对象).

是否有可能使集合或迭代器具有几乎无限多的元素,例如"表格6*k + 1上的所有数字","10以上的所有素数"或"此基础跨越的所有向量"?我正在考虑的另一件事是结合两个集合,例如低于1 000 000的所有素数的并集,以及形式2 ^ n-1的所有整数,并列出低于1 000 000的mersenne素数.我觉得它会更容易关于某些数学对象的理由,如果它是以这种方式完成的,并且在实际需要之前不会明确地创建元素.也许我错了.

这是我写的两个模拟类,试图说明我想做什么.它们的行为并不像我期望的那样(参见输出),这让我觉得我在这里与可迭代接口打破某种契约或者执行错误.如果您看到它或者在集合框架下甚至允许这种代码,请随意指出我在这里做错了什么.

import java.util.AbstractSet;
import java.util.Iterator;

public class PrimesBelow extends AbstractSet<Integer>{

    int max;
    int size;

    public PrimesBelow(int max) {
        this.max = max;
    }

    @Override
    public Iterator<Integer> iterator() {
        return new SetIterator<Integer>(this);
    }

    @Override
    public int size() {
        if(this.size == -1){
            System.out.println("Calculating size");
            size = calculateSize();
        }else{
            System.out.println("Accessing calculated size");
        }
        return size;
    }

    private int calculateSize() {
        int c = 0;
        for(Integer p: this)
            c++;
        return c;
    }

    public static void main(String[] args){
        PrimesBelow primesBelow10 = new PrimesBelow(10);
        for(int i: primesBelow10)
            System.out.println(i);
        System.out.println(primesBelow10);
    }
}
Run Code Online (Sandbox Code Playgroud)

.

import java.util.Iterator;
import java.util.NoSuchElementException;

public class SetIterator<T> implements Iterator<Integer> {
    int max;
    int current;
    public SetIterator(PrimesBelow pb) {
        this.max= pb.max;
        current = 1;
    }

    @Override
    public boolean hasNext() {
        if(current < max) return true;
        else return false;
    }

    @Override
    public Integer next() {
        while(hasNext()){
            current++;
            if(isPrime(current)){
                System.out.println("returning "+current);
                return current;
            }
        }
        throw new NoSuchElementException();
    }

    private boolean isPrime(int a) {
        if(a<2) return false;
        for(int i = 2; i < a; i++) if((a%i)==0) return false;
        return true;
    }
}

Main function gives the output
returning 2
2
returning 3
3
returning 5
5
returning 7
7
Exception in thread "main" java.util.NoSuchElementException
    at SetIterator.next(SetIterator.java:27)
    at SetIterator.next(SetIterator.java:1)
    at PrimesBelow.main(PrimesBelow.java:38)
Run Code Online (Sandbox Code Playgroud)

编辑:在next()方法中发现错误.更正了它并将输出更改为新的输出.

Kay*_*man 1

好吧,正如您在(现已修复)示例中看到的那样,您可以使用Iterables/轻松做到这一点Iterators。如果没有支持集合,这个示例会更好,只需使用Iterable您希望计算素数的最大数字即可。您只需要确保hasNext()正确处理该方法,这样就不必从next().

现在,可以更轻松地使用 Java 8 流来执行此类操作,但没有理由不能拥有一个只是Iterable. 如果你开始实现Collection它会变得更困难,但即使如此,这也不是完全不可能,具体取决于用例:例如,你可以实现contains()对素数的检查,但你必须计算它,并且对于大量数字来说它会很慢。

一个(有点复杂的)半无限奇数集的示例,它是不可变的并且不存储任何值。

public class OddSet implements Set<Integer> {
    public boolean contains(Integer o) {
        return o % 2 == 1;
    }
    public int size() {
        return Integer.MAX_VALUE;
    }
    public boolean add(Integer i) {
        throw new OperationNotSupportedException();
    }

    public boolean equals(Object o) {
        return o instanceof OddSet;
    }
    // etc. etc.
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,您需要创建一个“OddSetIterator”,然后它会执行实际的迭代,并且可能也有大小限制。并发不是问题,因为“iterator()”可以而且应该每次都返回一个新的迭代器。迭代器本身很少是线程安全的,而且您无论如何也不想在线程之间共享迭代器。您的示例存在缺陷,因为 `hasNext()` 可以返回 true,但 `next()` 仍然可以抛出异常。你需要更多的诡计和计算。 (2认同)