首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >你能在不用Java存储值的情况下拥有集合吗?

你能在不用Java存储值的情况下拥有集合吗?
EN

Stack Overflow用户
提问于 2017-08-18 03:39:59
回答 2查看 318关注 0票数 5

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

我考虑使用这些工具主要是为了数学。比方说,我想要一个集合来表示所有小于1,000,000的素数。将它们保存在内存中可能不是一个好主意,而是使用一个方法来检查集合中是否存在特定的数字。

我也不是java streams方面的专家,但我觉得这些在java 8 streams中应该是可用的,因为对象的状态非常简单(集合中的对象甚至不存在,直到您尝试遍历它们或检查集合中是否存在特定的对象)。

是否有可能拥有几乎无限多个元素的集合或迭代器,例如“6*k+1表上的所有数字”、“10以上的所有素数”或“所有以此为基的向量”?我正在考虑的另一件事是将两个集合组合在一起,比如所有小于1000000的素数和形式为2^n-1的所有整数的并集,并列出低于1000000的梅森素数。我觉得,如果以这种方式来推断某些数学对象,并且直到实际需要时才显式地创建元素,那么推断某些数学对象会更容易。也许我错了。

下面是我写的两个模型类,用来说明我想要做什么。它们的行为并不完全像我所期望的那样(参见输出),这让我认为我在这里破坏了一些关于iterable接口的约定,或者错误地实现了它。如果你看到了,或者这种代码在集合框架下是允许的,请随时指出我在这里做错了什么。

代码语言:javascript
复制
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);
    }
}

代码语言:javascript
复制
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)

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

EN

回答 2

Stack Overflow用户

发布于 2017-08-18 03:57:43

正如您在您的(现在已修复的)示例中看到的,您可以使用Iterables/Iterators轻松完成此操作。与其有一个后备的集合,这个例子可能会更好,只有一个Iterable,它接受你想要计算素数的最大值。您只需要确保正确处理hasNext()方法,这样就不必从next()抛出不必要的异常。

如今,使用Java8Streams可以更容易地执行这些事情,但您没有理由不能拥有一个“虚拟集合”,它只是一个Iterable。如果你开始实现Collection就会变得更难,但即使这样也不是完全不可能的,这取决于用例:例如,你可以实现检查素数的contains(),但你必须计算它,而且对于大数来说它会很慢。

一个(有点令人费解的)半无限奇数集的例子,它是不可变的,并且不存储任何值。

代码语言:javascript
复制
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.
}
票数 1
EN

Stack Overflow用户

发布于 2017-08-19 04:12:48

正如DwB所说的,这是不可能用实现的,因为每个元素都必须存储在内存中。然而,还有另一种选择:这正是Java的Stream API被实现的原因!

除非您显式地将它们收集到Collection中,否则Stream允许您遍历不存储在内存中的无限数量的对象。

来自IntStream#iteratedocumentation

返回通过将函数f迭代应用于初始元素seed而产生的无限顺序有序IntStream,产生由seed、f(seed)、f(Seed)等组成的流。

IntStream中的第一个元素(位置0)将是提供的种子。对于n > 0,位置n的元素将是将函数f应用于位置n- 1的元素的结果。

以下是您在问题中提出的一些示例:

代码语言:javascript
复制
public class Test {

    public static void main(String[] args) {
        IntStream.iterate(1, k -> 6 * k + 1);
        IntStream.iterate(10, i -> i + 1).filter(Test::isPrime);
        IntStream.iterate(1, n -> 2 * n - 1).filter(i -> i < 1_000_000);
    }

    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;
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45743690

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档