所以我有目前看起来像这样的代码

    public boolean in(TransactionType... types)
    {
        if (types == null || types.length == 0)
            return false;

        for (int i = 0; i < types.length; ++i)
            if (types[i] != null && types[i] == this)
                return true;
        return false;
    }

我把它改成了这个
    public boolean in(TransactionType... types)
    {
        if (types == null || types.length == 0)
            return false;

        for (int i = 0; i < types.length; ++i)
            if (types[i] == this)
                return true;
        return false;
    }

(TransactionType是其中包含大约30个值的枚举)

结果震惊了我。在我所有的测试中,第二个要快一个数量级。我预计可能会快2倍,但不会提高一个数量级。为什么会有所不同?是nullcheck这么慢还是因为额外的数组访问发生了奇怪的事情?

我的基准代码看起来像这样
public class App
{
    public enum TransactionType
    {
        A(1, "A", "A"),
        B(3, "B", "B"),
        C(5, "C", "C"),
        D(6, "D", "D"),
        E(7, "E", "E"),
        F(8, "F", "F"),
        G(9, "G", "G"),
        H(10, "H", "H"),
        I(11, "I", "I"),
        J(12, "J", "J"),
        K(13, "K", "K"),
        L(14, "L", "L"),
        M(15, "M", "M"),
        N(16, "N", "N"),
        O(17, "O", "O"),
        P(18, "P", "P"),
        Q(19, "Q", "Q"),
        R(20, "R", "R"),
        S(21, "S", "S"),
        T(22, "T", "T"),
        U(25, "U", "U"),
        V(26, "V", "V"),
        W(27, "W", "W"),
        X(28, "X", "X"),
        Y(29, "Y", "Y"),
        Z(30, "Z", "Z"),
        AA(31, "AA", "AA"),
        AB(32, "AB", "AB"),
        AC(33, "AC", "AC"),
        AD(35, "AD", "AD"),
        AE(36, "AE", "AE"),
        AF(37, "AF", "AF"),
        AG(38, "AG", "AG"),
        AH(39, "AH", "AH"),
        AI(40, "AI", "AI"),
        AJ(41, "AJ", "AJ"),
        AK(42, "AK", "AK"),
        AL(43, "AL", "AL"),
        AM(44, "AM", "AM"),
        AN(45, "AN", "AN"),
        AO(46, "AO", "AO"),
        AP(47, "AP", "AP");

        public final static TransactionType[] aArray =
        {
            O, Z, N, Y, AB
        };

        public final static TransactionType[] bArray =
        {
            J, P, AA, L, Q, M, K, AE, AK,
            AF, AD, AG, AH
        };

        public final static TransactionType[] cArray =
        {
            S, U, V
        };

        public final static TransactionType[] dArray =
        {
            A, B, D, G, C, E,
            T, R, I, F, H, AC,
            AI, AJ, AL, AM, AN,
            AO
        };

        private int id;
        private String abbrev;
        private String name;

        private TransactionType(int id, String abbrev, String name)
        {
            this.id = id;
            this.abbrev = abbrev;
            this.name = name;
        }

        public boolean in(TransactionType... types)
        {
            if (types == null || types.length == 0)
                return false;

            for (int i = 0; i < types.length; ++i)
                if (types[i] == this)
                    return true;
            return false;
        }

        public boolean inOld(TransactionType... types)
        {
            if (types == null || types.length == 0)
                return false;

            for (int i = 0; i < types.length; ++i)
            {
                if (types[i] != null && types[i] == this)
                    return true;
            }
            return false;
        }
    }

    public static void main(String[] args)
    {
        for (int i = 0; i < 10; ++i)
            bench2();

        for (int i = 0; i < 10; ++i)
            bench1();
    }

    private static void bench1()
    {
        final TransactionType[] values = TransactionType.values();
        long runs = 0;
        long currTime = System.currentTimeMillis();
        while (System.currentTimeMillis() - currTime < 1000)
        {
            for (TransactionType value : values)
            {
                value.inOld(TransactionType.dArray);
            }
            ++runs;
        }
        System.out.println("old " + runs);
    }

    private static void bench2()
    {
        final TransactionType[] values = TransactionType.values();
        long runs = 0;
        long currTime = System.currentTimeMillis();
        while (System.currentTimeMillis() - currTime < 1000)
        {
            for (TransactionType value : values)
            {
                value.in(TransactionType.dArray);
            }
            ++runs;
        }
        System.out.println("new " + runs);
    }
}

这是基准测试运行的结果
new 20164901
new 20084651
new 45739657
new 45735251
new 45757756
new 45726575
new 45413016
new 45649661
new 45325360
new 45380665
old 2021652
old 2022286
old 2246888
old 2237484
old 2246172
old 2268073
old 2271554
old 2259544
old 2272642
old 2268579

这是使用Oracle JDK 1.7.0.67

最佳答案

空检查没有完成任何事情,我也很惊讶它能带来如此大的改变。但我相信您的评论实质上可以回答您自己的问题。

@Cogman写道:



如果编译您的类并使用javap为这两种方法打印反汇编的字节码,您将看到:

  public boolean in(App$TransactionType...);
Code:
   0: aload_1
   1: ifnull        9
   4: aload_1
   5: arraylength
   6: ifne          11
   9: iconst_0
  10: ireturn
  11: iconst_0
  12: istore_2
  13: iload_2
  14: aload_1
  15: arraylength
  16: if_icmpge     34
  19: aload_1
  20: iload_2
  21: aaload
  22: aload_0
  23: if_acmpne     28
  26: iconst_1
  27: ireturn
  28: iinc          2, 1
  31: goto          13
  34: iconst_0
  35: ireturn

并且:
 public boolean inOld(App$TransactionType...);
Code:
   0: aload_1
   1: ifnull        9
   4: aload_1
   5: arraylength
   6: ifne          11
   9: iconst_0
  10: ireturn
  11: iconst_0
  12: istore_2
  13: iload_2
  14: aload_1
  15: arraylength
  16: if_icmpge     40
  19: aload_1
  20: iload_2
  21: aaload
  22: ifnull        34
  25: aload_1
  26: iload_2
  27: aaload
  28: aload_0
  29: if_acmpne     34
  32: iconst_1
  33: ireturn
  34: iinc          2, 1
  37: goto          13
  40: iconst_0
  41: ireturn

您的新方法删除了六个操作和一个潜在的分支站点。

循环以前很紧,现在 super 紧。

我本来以为Java会将这两种方法JIT本质上是同一件事。您的计时编号建议不然。

一些随机数:

1.6.33 32b:646100和727173

1.6.33 64b:1667665和2668513

1.7.67 32b:661003和716417

1.7.07 64b:1663926和32493989

1.7.60 64b:1700574和32368506

1.8.20 64b:1648382和32222823

所有64位JVM的执行两种实现都比32位版本快得多。

关于java - 为什么我的空值检查这么慢?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26513492/

10-10 08:13