Java 9集合'便利工厂方法作为集合文字的替代方法

时间:2017-10-05 13:30:05

标签: java collections java-9

考虑这种方法(仅用于说明):

boolean isSmallNumber(String s) {
    return (n in ["one", "two", "three", "four"]);
}

当然,这不是 Java ,但它可能是您最喜欢的支持集合文字的替代语言,例如 Groovy Kotlin 。表达式非常简洁,就像字符串文字一样,允许编译器将集合文字放在某个静态存储区域(甚至可能是"intern()")。

现在输入 Java 9

boolean isSmallNumber(String s) {
    return Set.of("one", "two", "three", "four").contains(s);
}

这也很简洁,但遗憾的是,每次调用它时,它都会在堆上分配一个新的Set,然后立即将其用于垃圾回收。

当然,您可以定义一个集合常量:

private static final Set<String> SMALL_NUMBERS = Set.of(...);

但是,这个定义可能距离大类中的方法定义一千行,并且您可能无法想到一个好的描述性名称,而文字可能更清晰(在这个假设的情况下)。

所以,如果我在方法中使用Set.of(...),那么 JIT 编译器会在每次调用方法时优化新对象的创建吗?

1 个答案:

答案 0 :(得分:15)

我制作了一个简单的JMH基准:

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class Temp {

    private Object value;

    @Setup
    public void setUp() {
        value = 50;
    }

    @Benchmark
    public boolean list1() {
        return List.of("one").contains(value);
    }

    @Benchmark
    public boolean list2() {
        return List.of("one", "two").contains(value);
    }

    @Benchmark
    public boolean list3() {
        return List.of("one", "two", "three").contains(value);
    }

    @Benchmark
    public boolean list4() {
        return List.of("one", "two", "three", "four").contains(value);
    }

    @Benchmark
    public boolean set1() {
        return Set.of("one").contains(value);
    }

    @Benchmark
    public boolean set2() {
        return Set.of("one", "two").contains(value);
    }

    @Benchmark
    public boolean set3() {
        return Set.of("one", "two", "three").contains(value);
    }

    @Benchmark
    public boolean set4() {
        return Set.of("one", "two", "three", "four").contains(value);
    }
}

在使用-prof gc运行基准测试后,我可以得出以下结论:JIT优化list1list2set1set2,但不是{ {1}},list3list4set3 [1]

这似乎完全合理,因为set4 N >= 3 / listN创建了比setN更复杂的List / Set实现。

N <= 2实现2个元素:

List

static final class List2<E> extends AbstractImmutableList<E> { private final E e0; private final E e1; ... } 实现3个或更多元素:

List

static final class ListN<E> extends AbstractImmutableList<E> { private final E[] elements; ... } 包含另一个间接层(数组),这显然使得逃逸分析变得更加困难。

JMH输出(略微改为适合页面):

ListN

[1] Java HotSpot(TM)64位服务器VM(内置9 + 181,混合模式)