代码之家  ›  专栏  ›  技术社区  ›  DodgyCodeException

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

  •  10
  • DodgyCodeException  · 技术社区  · 9 年前

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

    当然,事实并非如此 Java语言 Groovy公司 科特林 . 表达式是简洁的,就像字符串文字一样,编译器可以将集合文字放在一些静态存储区域(甚至可能是 "intern()" it)。

    现在输入 :

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

    这也很简洁,但不幸的是,每次调用它时,它都会在堆上分配一个新集,然后立即使其可用于垃圾收集。

    当然,您可以定义集合常数:

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

    但是在一个大类中,这个定义可能离方法定义有1000行之遥,您可能无法为它想出一个好的描述性名称,而文字可能更清晰(在这个假设的情况下)。

    所以,如果我使用 Set.of(...) 在方法内部 准时制

    1 回复  |  直到 9 年前
        1
  •  15
  •   ZhekaKozlov    9 年前

    我制作了一个简单的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优化了 list1 , list2 , set1 set2 ,但不是 list3 list4 , set3 , set4 [1]

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

    列表 2个要素的实施:

    static final class List2<E> extends AbstractImmutableList<E> {
        private final E e0;
        private final E e1;
        ...
    }
    

    列表 3个或更多元素的实现:

    static final class ListN<E> extends AbstractImmutableList<E> {
        private final E[] elements;
        ...
    }
    

    ListN


    Benchmark                  Mode  Cnt     Score      Error   Units
    list1                      avgt    5     3,075 ?    1,165   ns/op
    list1:·gc.alloc.rate       avgt    5     0,131 ?    1,117  MB/sec
    list1:·gc.alloc.rate.norm  avgt    5    ? 10??               B/op
    list1:·gc.count            avgt    5       ? 0             counts
    
    list2                      avgt    5     3,161 ?    0,543   ns/op
    list2:·gc.alloc.rate       avgt    5     0,494 ?    3,065  MB/sec
    list2:·gc.alloc.rate.norm  avgt    5     0,001 ?    0,003    B/op
    list2:·gc.count            avgt    5       ? 0             counts
    
    list3                      avgt    5    33,094 ?    4,402   ns/op
    list3:·gc.alloc.rate       avgt    5  6316,970 ?  750,240  MB/sec
    list3:·gc.alloc.rate.norm  avgt    5    64,016 ?    0,089    B/op
    list3:·gc.count            avgt    5   169,000             counts
    list3:·gc.time             avgt    5   154,000                 ms
    
    list4                      avgt    5    32,718 ?    3,657   ns/op
    list4:·gc.alloc.rate       avgt    5  6403,487 ?  729,235  MB/sec
    list4:·gc.alloc.rate.norm  avgt    5    64,004 ?    0,017    B/op
    list4:·gc.count            avgt    5   165,000             counts
    list4:·gc.time             avgt    5   146,000                 ms
    
    set1                       avgt    5     3,218 ?    0,822   ns/op
    set1:·gc.alloc.rate        avgt    5     0,237 ?    1,973  MB/sec
    set1:·gc.alloc.rate.norm   avgt    5    ? 10??               B/op
    set1:·gc.count             avgt    5       ? 0             counts
    
    set2                       avgt    5     7,087 ?    2,029   ns/op
    set2:·gc.alloc.rate        avgt    5     0,647 ?    4,755  MB/sec
    set2:·gc.alloc.rate.norm   avgt    5     0,001 ?    0,010    B/op
    set2:·gc.count             avgt    5       ? 0             counts
    
    set3                       avgt    5    88,460 ?   16,834   ns/op
    set3:·gc.alloc.rate        avgt    5  3565,506 ?  687,900  MB/sec
    set3:·gc.alloc.rate.norm   avgt    5    96,000 ?    0,001    B/op
    set3:·gc.count             avgt    5   143,000             counts
    set3:·gc.time              avgt    5   108,000                 ms
    
    set4                       avgt    5   118,652 ?   41,035   ns/op
    set4:·gc.alloc.rate        avgt    5  2887,359 ?  920,180  MB/sec
    set4:·gc.alloc.rate.norm   avgt    5   104,000 ?    0,001    B/op
    set4:·gc.count             avgt    5   136,000             counts
    set4:·gc.time              avgt    5    94,000                 ms
    

    [1] Java HotSpot(TM)64位服务器虚拟机(构建9+181,混合模式)