java安装_Java 9中的无限集

java安装

java安装

一套

Set是元素的集合,从而在任何给定的元件Set只出现一次。

更正式地说,集合不包含元素e1e2对,因此e1.equals(e2)

我们可以像这样在Java 9中轻松创建Set

final Set<Integer> s = Set.of(1, 2, 3);
System.out.println(s);

这可能会产生以下输出:

[2, 3, 1]

上面产生的Set是不可变的,即它不能更改,并且也是有限的,因为Set有不同数量的元素,即三个。 未指定通过其读取方法(例如stream()iterator()forEach() )返回元素的顺序。

无限集

无限集包含无限数量的元素。 无限集的一个示例是所有整数的集合[…,-1,0,1,2,…],其中整数不是Java Integer类的整数,而是根据整数的数学定义得出的整数,其中存在对于任何给定的整数n,始终为更大的整数n + 1。

有许多无限集,例如所有质数的集合,偶数整数的集合,斐波那契数的集合等。

由于明显的原因,我们无法预先计算和存储无限Java Set所有元素。 如果尝试,最终将耗尽内存。

我们必须问自己的一个基本问题是:对于我们拥有的Java类型,实际上是否存在无限集? 如果我们有一个Set<Byte>中有最多256个元素的Set ,这是远离无限的,同样的道理也适用于Short ,甚至Integer 。 毕竟,只有大约40亿个不同的Integer对象,如果使用位图表示成员身份,则可以在0.5 GB的空间中容纳Set<Integer> 。 尽管很大,但不是无限的。

但是,如果我们谈论的是LongString元素,那么至少实际上是在接近无限集。 要存储所有Long的位图,将需要许多PB内部存储空间。 真正的无限Set将是具有任意长度的字符[az]的所有可能组合的String Set

在继续之前,我想提一下,这篇文章中的代码也可以在GitHub上找到,如文章结尾处所述。

ImmutableStreamSet

为了摆脱存储Set元素的范式,我们可以创建一个ImmutableStreamSet ,仅通过其stream()方法定义Set的元素。 可以将ImmutableStreamSet定义为如下所示的FunctionalInterface

@FunctionalInterface
public interface ImmutableStreamSet<E> extends Set<E> {

    // This is the only method we need to implements
    @Override
    public Stream<E> stream(); 

    @Override
    default int size() {
        return (int) stream().limit(Integer.MAX_VALUE).count();
    }

    @Override
    default boolean contains(Object o) {
        return stream().anyMatch(e -> Objects.equals(e, o));
    }

    @Override
    default boolean containsAll(Collection<?> c) {
        return (this == c) ? true : c.stream().allMatch(this::contains);
    }

    @Override
    default boolean isEmpty() {
        return !stream().findAny().isPresent();
    }

    @Override
    default <T> T[] toArray(T[] a) {
        return stream().collect(toList()).toArray(a);
    }

    @Override
    default Object[] toArray() {
        return stream().toArray();
    }

    @Override
    default Spliterator<E> spliterator() {
        return stream().spliterator();
    }

    @Override
    default Iterator<E> iterator() {
        return stream().iterator();
    }

    @Override
    default Stream<E> parallelStream() {
        return stream().parallel();
    }

    @Override
    default void forEach(Consumer<? super E> action) {
        stream().forEach(action);
    }

    // We are immutable
    @Override
    default boolean removeIf(Predicate<? super E> filter) {
        throw new UnsupportedOperationException();
    }

    @Override
    default void clear() {
        throw new UnsupportedOperationException();
    }

    @Override
    default boolean removeAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    default boolean retainAll(Collection<?> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    default boolean addAll(Collection<? extends E> c) {
        throw new UnsupportedOperationException();
    }

    @Override
    default boolean remove(Object o) {
        throw new UnsupportedOperationException();
    }

    @Override
    default boolean add(E e) {
        throw new UnsupportedOperationException();
    }

    static <E> ImmutableStreamSet<E> of(Supplier<Stream<E>> supplier) {
    // Check out GitHub to see how this Impl class is implemented
        return new ImmutableStreamSetImpl<>(supplier);
    }

}

太棒了,现在我们只需提供像这样的流提供者就可以创建无限集:

ImmutableStreamSet<Long> setOfAllLong
            = LongStream.rangeClosed(Long.MIN_VALUE, Long.MAX_VALUE)::boxed;

这将创建一Set所有Long值(例如,具有2 ^ 64个元素)。 提供流提供程序时,必须确保遵守元素唯一性的Set属性。 考虑以下非法集:

final ImmutableStreamSet<Long> illegalSet = 
            () -> Stream.of(1l, 2l, 1l);

显然,集合中发生11次两次,这使该对象违反了集合要求。

正如我们将看到的,最好创建我们正在考虑的无限集的具体类。 上面的默认实现的一个特殊问题是contains()方法可能非常慢。 阅读下一章,找出原因以及解决方法。

正长集

让我们假设我们要创建一个包含所有正长值的Set ,并且希望能够与其他Set和Object有效地使用Set 。 我们可以这样去做:

public final class PositiveLongSet implements ImmutableStreamSet<Long> {

    public static final PositiveLongSet INSTANCE = new PositiveLongSet();

    private PositiveLongSet() {
    }

    @Override
    public Stream<Long> stream() {
        return LongStream.rangeClosed(1, Long.MAX_VALUE).boxed();
    }

    @Override
    public int size() {
        return Integer.MAX_VALUE;
    }

    @Override
    public boolean contains(Object o) {
        return SetUtil.contains(this, Long.class, other -> other > 0, o);
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public String toString() {
        return SetUtil.toString(this);
    }

}

请注意,即使Set很大,我们如何遵守方法size()的形式要求,在该方法中我们返回Integer.MAX_VALUE 。 如果Set已在今天定义,则size()可能会返回long而不是int 。 但是在90年代初,内部RAM通常小于1 GB。 我们在类中使用了两种实用程序方法:

SetUtil.toString()采用Set ,对前八个元素进行迭代,并返回这些元素的String表示形式。

SetUtil.contains()方法采用Set ,Element类型类(在这里Long.class )和一个Predicate ,如果我们Long.class比较的对象属于给定的Element类型类(如果我们要比较的对象是给定的),则调用Predicate null或其他类型,则该Set不包含该对象)。

这是SetUtil样子:

final class SetUtil {

    private static final int TO_STRING_MAX_ELEMENTS = 8;

    static <E> String toString(Set<E> set) {
        final List<String> first = set.stream()
            .limit(TO_STRING_MAX_ELEMENTS + 1)
            .map(Object::toString)
            .collect(toList());

        final String endMarker = first.size() > TO_STRING_MAX_ELEMENTS ? ", ...]" : "]";

        return first.stream()
            .limit(TO_STRING_MAX_ELEMENTS)
            .collect(
                joining(", ", "[", endMarker)
            );
    }

    static <E> boolean contains(
        final Set<E> set,
        final Class<E> clazz,
        final Predicate<E> predicate,
        final Object o
    ) {
        if (o == null) {
            return false;
        }
        if (!(clazz.isAssignableFrom(o.getClass()))) {
            return false;
        }
        final E other = clazz.cast(o);
        return predicate.test(other);
    }

}

有了类ImmutableStreamSetSetUtil我们现在可以轻松地创建其他无限集,例如PostitiveEvenLongSet (以下未显示,请PrimeLongSet编写), PrimeLongSet (包含可以用Long表示的所有素数)甚至FibonacciLongSet (包含所有fibonacci数字)可以用Long表示)。 这些类如下所示:

PrimeLongSet

public final class PrimeLongSet implements ImmutableStreamSet<Long> {

    public static final PrimeLongSet INSTANCE = new PrimeLongSet();

    private PrimeLongSet() {
    }

    private static final LongPredicate IS_PRIME =
        x -> LongStream.rangeClosed(2, (long) Math.sqrt(x)).allMatch(n -> x % n != 0);

    @Override
    public Stream<Long> stream() {
        return LongStream.rangeClosed(2, Long.MAX_VALUE)
            .filter(IS_PRIME)
            .boxed();
    }

    @Override
    public int size() {
        return Integer.MAX_VALUE; 
    }

    @Override
    public boolean contains(Object o) {
        return SetUtil.contains(this, Long.class, IS_PRIME::test, o);
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public String toString() {
        return SetUtil.toString(this);
    }

}

斐波那契长集

public final class FibonacciLongSet implements ImmutableStreamSet<Long> {

    public static final FibonacciLongSet INSTANCE = new FibonacciLongSet();

    private FibonacciLongSet() {
    }

    @Override
    public Stream<Long> stream() {
        return Stream.concat(
            Stream.of(0l),
            Stream.iterate(new Fibonacci(0, 1), Fibonacci::next)
                .mapToLong(Fibonacci::getAsLong)
                .takeWhile(fib -> fib > 0)
                .boxed()
        );
    }

    @Override
    public int size() {
        return 92;
    }

    @Override
    public boolean contains(Object o) {
        return SetUtil.contains(
            this,
            Long.class,
            other -> stream().anyMatch(fib -> Objects.equals(fib, other)),
            o
        );
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public String toString() {
        return SetUtil.toString(this);
    }

    private static class Fibonacci {

        final long beforeLast;
        final long last;

        public Fibonacci(long beforeLast, long last) {
            this.beforeLast = beforeLast;
            this.last = last;
        }

        public Fibonacci next() {
            return new Fibonacci(last, last + beforeLast);
        }

        public long getAsLong() {
            return beforeLast + last;
        }

    }

}

注意当长回绕为负值时,我们如何使用Stream::takeWhile中断流。 可以说,当我们进行预计算并提供92的大小时,我们正在“作弊”,但否则size()会慢一些。

缝合全部

通过为这些类的实例提供一个带有静态提供程序的接口,我们可以封装我们的预定义集,并确保在JVM中只有这样的一个实例,如下所示:

public interface Sets {

    static Set<Long> positiveLongSet() {
        return PositiveLongSet.INSTANCE;
    }

    static Set<Long> positiveEvenLongSet() {
        return PositiveEvenLongSet.INSTANCE;
    }

    static Set<Long> primeLongSet() {
        return PrimeLongSet.INSTANCE;
    }

    static Set<Long> fibonacciLongSet() {
        return FibonacciLongSet.INSTANCE;
    }

}

我们还可以将代码封装在Java 9模块中,通过将SetsImmutableStreamSet类暴露在项目的最顶层包中,并将所有其他类放在名为“ internal”的包中(不公开),以确保仅可见SetsImmutableStreamSet类。 )。

这是我们如何module-info.java可能看起来像规定,两个外露类在com.speedment.infinite_sets在包等,并且实现类com.speedment.infinite_sets.internal

module-info.java
module com.speedment.infinite_sets {
    exports com.speedment.infinite_sets;
}

尝试一下

现在,我们可以通过首先声明现有模块的用法来创建另一个使用无限集的模块,如下所示:

module-info.java
module Infinite_sets_app {
    requires com.speedment.infinite_sets;
}

然后,我们可以访问模块的裸露部分。 这是尝试无限集的一种方法:

import static com.speedment.infinite_sets.Sets.*;
public class Main {

    public static void main(String[] args) {

        Stream.of(
            Set.of(1, 2, 3),
            positiveLongSet(),
            positiveEvenLongSet(),
            primeLongSet(),
            fibonacciLongSet()
        ).forEachOrdered(System.out::println);

        // This actually completes fast due to identity equality
        positiveLongSet().containsAll(positiveLongSet());

    }

}

这可能会产生以下输出:

[3, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 8, ...]
[2, 4, 6, 8, 10, 12, 14, 16, ...]
[2, 3, 5, 7, 11, 13, 17, 19, ...]
[0, 1, 2, 3, 5, 8, 13, 21, ...]

参与GitHub

这篇文章中的源代码可以在GitHub上找到。游戏,设定和比赛…

翻译自: https://www.javacodegeeks.com/2018/06/infinite-sets-java.html

java安装

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值