RFR: updated draft API for JEP 269 Convenience Collection Factories

Peter Levart peter.levart at gmail.com
Sun Nov 8 19:30:08 UTC 2015


Hi Michael,

You see, switch2 is on par with explicit for 0 and 1 args.

switch10 probably suffers from to-many-bytecodes-per-method syndrome.

I tried to shorten your switch2 and switch10 methods by delegating to 
explicit/varargs methods:

   @SafeVarargs
   static <E> List<E> varargs_switch2(E... ea) {
     switch (ea.length) {
       case 0: return explicit();
       case 1: return explicit(ea[0]);
       default: return varargs(ea);
     }
   }

   @SafeVarargs
   static <E> List<E> varargs_switch10(E... ea) {
     switch (ea.length) {
       case 0: return explicit();
       case 1: return explicit(ea[0]);
       case 2: return explicit(ea[0], ea[1]);
       case 3: return explicit(ea[0], ea[1], ea[2]);
       case 4: return explicit(ea[0], ea[1], ea[2], ea[3]);
       case 5: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4]);
       case 6: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
       case 7: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], 
ea[6]);
       case 8: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], 
ea[6], ea[7]);
       case 9: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], 
ea[6], ea[7], ea[8]);
       case 10: return explicit(ea[0], ea[1], ea[2], ea[3], ea[4], 
ea[5], ea[6], ea[7], ea[8], ea[9]);
       default: return varargs(ea);
     }
   }


... and the results are as follows (JDK8u60, i7-2600K, Linux):


ListOf.explicit_00                                           avgt 10     
2.600 ±    0.022   ns/op
ListOf.explicit_01                                           avgt 10     
4.032 ±    0.237   ns/op
ListOf.explicit_02                                           avgt 10     
7.255 ±    0.457   ns/op
ListOf.explicit_03                                           avgt 10     
7.684 ±    0.485   ns/op
ListOf.explicit_04                                           avgt 10     
8.401 ±    0.803   ns/op
ListOf.explicit_05                                           avgt 10     
9.001 ±    0.771   ns/op
ListOf.explicit_06                                           avgt 10     
9.467 ±    1.008   ns/op
ListOf.explicit_07                                           avgt 10    
10.506 ±    0.774   ns/op
ListOf.explicit_08                                           avgt 10    
11.218 ±    0.946   ns/op
ListOf.explicit_09                                           avgt 10    
12.466 ±    0.735   ns/op
ListOf.explicit_10                                           avgt 10    
13.160 ±    1.680   ns/op

ListOf.varargs_00                                            avgt 10     
6.701 ±    0.986   ns/op
ListOf.varargs_01                                            avgt 10     
7.244 ±    0.775   ns/op
ListOf.varargs_02                                            avgt 10     
9.751 ±    0.931   ns/op
ListOf.varargs_03                                            avgt 10    
10.730 ±    1.055   ns/op
ListOf.varargs_04                                            avgt 10    
11.615 ±    0.995   ns/op
ListOf.varargs_05                                            avgt 10    
12.923 ±    1.057   ns/op
ListOf.varargs_06                                            avgt 10    
12.688 ±    0.963   ns/op
ListOf.varargs_07                                            avgt 10    
14.509 ±    0.964   ns/op
ListOf.varargs_08                                            avgt 10    
15.214 ±    1.613   ns/op
ListOf.varargs_09                                            avgt 10    
15.796 ±    0.099   ns/op
ListOf.varargs_10                                            avgt 10    
17.381 ±    2.089   ns/op

ListOf.varargs_switch10_00                                   avgt 10     
2.598 ±    0.031   ns/op
ListOf.varargs_switch10_01                                   avgt 10     
4.200 ±    0.377   ns/op
ListOf.varargs_switch10_02                                   avgt 10     
6.829 ±    0.445   ns/op
ListOf.varargs_switch10_03                                   avgt 10     
8.074 ±    1.230   ns/op
ListOf.varargs_switch10_04                                   avgt 10     
8.254 ±    0.644   ns/op
ListOf.varargs_switch10_05                                   avgt 10     
9.955 ±    1.643   ns/op
ListOf.varargs_switch10_06                                   avgt 10     
9.856 ±    1.172   ns/op
ListOf.varargs_switch10_07                                   avgt 10    
11.230 ±    1.182   ns/op
ListOf.varargs_switch10_08                                   avgt 10    
17.431 ±    2.253   ns/op
ListOf.varargs_switch10_09                                   avgt 10    
18.439 ±    2.199   ns/op
ListOf.varargs_switch10_10                                   avgt 10    
20.477 ±    2.698   ns/op

ListOf.varargs_switch2_00                                    avgt 10     
2.598 ±    0.031   ns/op
ListOf.varargs_switch2_01                                    avgt 10     
4.306 ±    0.461   ns/op
ListOf.varargs_switch2_02                                    avgt 10     
9.561 ±    0.978   ns/op
ListOf.varargs_switch2_03                                    avgt 10    
10.859 ±    0.596   ns/op
ListOf.varargs_switch2_04                                    avgt 10    
11.810 ±    0.812   ns/op
ListOf.varargs_switch2_05                                    avgt 10    
13.451 ±    1.819   ns/op
ListOf.varargs_switch2_06                                    avgt 10    
12.310 ±    0.106   ns/op
ListOf.varargs_switch2_07                                    avgt 10    
15.589 ±    2.335   ns/op
ListOf.varargs_switch2_08                                    avgt 10    
15.177 ±    0.963   ns/op
ListOf.varargs_switch2_09                                    avgt 10    
18.139 ±    1.968   ns/op
ListOf.varargs_switch2_10                                    avgt 10    
16.802 ±    1.193   ns/op


Now switch10 performs on par with explicit up to 7 arguments after which 
there's a cliff.

switch2 has a cliff where expected, when it starts to delegate to varargs.

More interesting, when profiling with "-prof gc", we can see that:


ListOf.explicit_00:·gc.alloc.rate.norm                       avgt 10    
≈ 10⁻⁶               B/op
ListOf.explicit_01:·gc.alloc.rate.norm                       avgt 10    
24.000 ±    0.001    B/op
ListOf.explicit_02:·gc.alloc.rate.norm                       avgt 10    
48.000 ±    0.001    B/op
ListOf.explicit_03:·gc.alloc.rate.norm                       avgt 10    
56.000 ±    0.001    B/op
ListOf.explicit_04:·gc.alloc.rate.norm                       avgt 10    
56.000 ±    0.001    B/op
ListOf.explicit_05:·gc.alloc.rate.norm                       avgt 10    
64.000 ±    0.001    B/op
ListOf.explicit_06:·gc.alloc.rate.norm                       avgt 10    
64.000 ±    0.001    B/op
ListOf.explicit_07:·gc.alloc.rate.norm                       avgt 10    
72.000 ±    0.001    B/op
ListOf.explicit_08:·gc.alloc.rate.norm                       avgt 10    
72.000 ±    0.001    B/op
ListOf.explicit_09:·gc.alloc.rate.norm                       avgt 10    
80.000 ±    0.001    B/op
ListOf.explicit_10:·gc.alloc.rate.norm                       avgt 10    
80.000 ±    0.001    B/op

ListOf.varargs_00:·gc.alloc.rate.norm                        avgt 10    
40.000 ±    0.001    B/op
ListOf.varargs_01:·gc.alloc.rate.norm                        avgt 10    
48.000 ±    0.001    B/op
ListOf.varargs_02:·gc.alloc.rate.norm                        avgt 10    
72.000 ±    0.001    B/op
ListOf.varargs_03:·gc.alloc.rate.norm                        avgt 10    
88.000 ±    0.001    B/op
ListOf.varargs_04:·gc.alloc.rate.norm                        avgt 10    
88.000 ±    0.001    B/op
ListOf.varargs_05:·gc.alloc.rate.norm                        avgt 10   
104.000 ±    0.001    B/op
ListOf.varargs_06:·gc.alloc.rate.norm                        avgt 10   
104.000 ±    0.001    B/op
ListOf.varargs_07:·gc.alloc.rate.norm                        avgt 10   
120.000 ±    0.001    B/op
ListOf.varargs_08:·gc.alloc.rate.norm                        avgt 10   
120.000 ±    0.001    B/op
ListOf.varargs_09:·gc.alloc.rate.norm                        avgt 10   
136.000 ±    0.001    B/op
ListOf.varargs_10:·gc.alloc.rate.norm                        avgt 10   
136.000 ±    0.001    B/op

ListOf.varargs_switch10_00:·gc.alloc.rate.norm               avgt 10    
≈ 10⁻⁶               B/op
ListOf.varargs_switch10_01:·gc.alloc.rate.norm               avgt 10    
24.000 ±    0.001    B/op
ListOf.varargs_switch10_02:·gc.alloc.rate.norm               avgt 10    
48.000 ±    0.001    B/op
ListOf.varargs_switch10_03:·gc.alloc.rate.norm               avgt 10    
56.000 ±    0.001    B/op
ListOf.varargs_switch10_04:·gc.alloc.rate.norm               avgt 10    
56.000 ±    0.001    B/op
ListOf.varargs_switch10_05:·gc.alloc.rate.norm               avgt 10    
64.000 ±    0.001    B/op
ListOf.varargs_switch10_06:·gc.alloc.rate.norm               avgt 10    
64.000 ±    0.001    B/op
ListOf.varargs_switch10_07:·gc.alloc.rate.norm               avgt 10    
72.000 ±    0.001    B/op
ListOf.varargs_switch10_08:·gc.alloc.rate.norm               avgt 10   
120.000 ±    0.001    B/op
ListOf.varargs_switch10_09:·gc.alloc.rate.norm               avgt 10   
136.000 ±    0.001    B/op
ListOf.varargs_switch10_10:·gc.alloc.rate.norm               avgt 10   
136.000 ±    0.001    B/op

ListOf.varargs_switch2_00:·gc.alloc.rate.norm                avgt 10    
≈ 10⁻⁶               B/op
ListOf.varargs_switch2_01:·gc.alloc.rate.norm                avgt 10    
24.000 ±    0.001    B/op
ListOf.varargs_switch2_02:·gc.alloc.rate.norm                avgt 10    
72.000 ±    0.001    B/op
ListOf.varargs_switch2_03:·gc.alloc.rate.norm                avgt 10    
88.000 ±    0.001    B/op
ListOf.varargs_switch2_04:·gc.alloc.rate.norm                avgt 10    
88.000 ±    0.001    B/op
ListOf.varargs_switch2_05:·gc.alloc.rate.norm                avgt 10   
104.000 ±    0.001    B/op
ListOf.varargs_switch2_06:·gc.alloc.rate.norm                avgt 10   
104.000 ±    0.001    B/op
ListOf.varargs_switch2_07:·gc.alloc.rate.norm                avgt 10   
120.000 ±    0.001    B/op
ListOf.varargs_switch2_08:·gc.alloc.rate.norm                avgt 10   
120.000 ±    0.001    B/op
ListOf.varargs_switch2_09:·gc.alloc.rate.norm                avgt 10   
136.000 ±    0.001    B/op
ListOf.varargs_switch2_10:·gc.alloc.rate.norm                avgt 10   
136.000 ±    0.001    B/op


switch10 allocates exactly the same as explicit up to 7 arguments, after 
that it seems that JIT doesn't want to optimize away the allocation of 
the vararg array.


So it looks like that there's no need to burden the public API with 
explicit argument overloads.

Regards, Peter


On 11/08/2015 12:44 AM, Michael Hixson wrote:
> Hi Peter,
>
> I've attached the source code and JMH output with two new tests:
>
> 1. varargs_switch2: Has a switch with cases for 0 and 1 that invoke
> Collections.emptyList/singletonList.
> 2. varargs_switch10:  Has a switch with ten cases that look exactly
> like the explicit versions.
>
> Both have a default case that falls back to System.arraycopy.
>
> switch2 seems like a more sane implementation and it performs better
> for 0 or 1 arguments.  For larger numbers of arguments, they're
> roughly equivalent.
>
> Here is the end snippet from the attached results:
>
>
> Benchmark                   Mode  Cnt   Score   Error  Units
> ListOf.explicit_00          avgt   40   2.550 ± 0.008  ns/op
> ListOf.explicit_01          avgt   40   6.929 ± 0.100  ns/op
> ListOf.explicit_02          avgt   40  15.011 ± 1.410  ns/op
> ListOf.explicit_03          avgt   40  16.203 ± 0.396  ns/op
> ListOf.explicit_04          avgt   40  16.397 ± 0.505  ns/op
> ListOf.explicit_05          avgt   40  18.252 ± 0.229  ns/op
> ListOf.explicit_06          avgt   40  18.623 ± 0.499  ns/op
> ListOf.explicit_07          avgt   40  20.614 ± 0.231  ns/op
> ListOf.explicit_08          avgt   40  20.792 ± 0.259  ns/op
> ListOf.explicit_09          avgt   40  22.998 ± 0.350  ns/op
> ListOf.explicit_10          avgt   40  23.105 ± 0.346  ns/op
> ListOf.varargs_00           avgt   40  11.363 ± 0.131  ns/op
> ListOf.varargs_01           avgt   40  20.877 ± 0.440  ns/op
> ListOf.varargs_02           avgt   40  20.004 ± 0.130  ns/op
> ListOf.varargs_03           avgt   40  24.264 ± 0.091  ns/op
> ListOf.varargs_04           avgt   40  24.309 ± 0.120  ns/op
> ListOf.varargs_05           avgt   40  28.936 ± 0.503  ns/op
> ListOf.varargs_06           avgt   40  28.676 ± 0.052  ns/op
> ListOf.varargs_07           avgt   40  33.858 ± 1.409  ns/op
> ListOf.varargs_08           avgt   40  33.685 ± 0.763  ns/op
> ListOf.varargs_09           avgt   40  37.639 ± 0.207  ns/op
> ListOf.varargs_10           avgt   40  39.188 ± 1.577  ns/op
> ListOf.varargs_switch10_00  avgt   40   5.575 ± 0.140  ns/op
> ListOf.varargs_switch10_01  avgt   40  13.561 ± 0.353  ns/op
> ListOf.varargs_switch10_02  avgt   40  20.145 ± 0.328  ns/op
> ListOf.varargs_switch10_03  avgt   40  24.632 ± 0.121  ns/op
> ListOf.varargs_switch10_04  avgt   40  25.360 ± 0.941  ns/op
> ListOf.varargs_switch10_05  avgt   40  28.977 ± 0.336  ns/op
> ListOf.varargs_switch10_06  avgt   40  30.471 ± 1.797  ns/op
> ListOf.varargs_switch10_07  avgt   40  33.701 ± 0.128  ns/op
> ListOf.varargs_switch10_08  avgt   40  33.737 ± 0.357  ns/op
> ListOf.varargs_switch10_09  avgt   40  38.638 ± 1.564  ns/op
> ListOf.varargs_switch10_10  avgt   40  38.042 ± 0.090  ns/op
> ListOf.varargs_switch2_00   avgt   40   2.543 ± 0.006  ns/op
> ListOf.varargs_switch2_01   avgt   40   7.069 ± 0.366  ns/op
> ListOf.varargs_switch2_02   avgt   40  20.564 ± 0.739  ns/op
> ListOf.varargs_switch2_03   avgt   40  24.453 ± 0.362  ns/op
> ListOf.varargs_switch2_04   avgt   40  24.706 ± 0.587  ns/op
> ListOf.varargs_switch2_05   avgt   40  29.451 ± 0.917  ns/op
> ListOf.varargs_switch2_06   avgt   40  28.856 ± 0.126  ns/op
> ListOf.varargs_switch2_07   avgt   40  33.300 ± 0.066  ns/op
> ListOf.varargs_switch2_08   avgt   40  36.306 ± 3.242  ns/op
> ListOf.varargs_switch2_09   avgt   40  40.739 ± 1.837  ns/op
> ListOf.varargs_switch2_10   avgt   40  37.876 ± 0.114  ns/op
>
>
> -Michael
>
> On Sat, Nov 7, 2015 at 7:41 AM, Peter Levart <peter.levart at gmail.com> wrote:
>> Hi Michael,
>>
>> The comparison between explicit and varargs is not fair. Varargs is using
>> arraycopy, which I think prevents vararg array allocation to be eliminated.
>> Try to use a switch on varargs array length and then directly reference it's
>> elements with constant indices for each case and construct list arrays as
>> you do in explicit methods. Let's see if this performs any better.
>>
>> Regards, Peter
>>
>> On Nov 7, 2015 9:43 AM, "Michael Hixson" <michael.hixson at gmail.com> wrote:
>>> (Oops, forgot to cc the mailing list)
>>>
>>> Thanks for the explanations, Stuart.  That all sounds reasonable and
>>> makes sense to me.
>>>
>>> I have some additional thoughts inline below, because this is
>>> interesting and I can't resist, but you could ignore them and not hurt
>>> any feelings.
>>>
>>> I also wrote up some quick benchmarks comparing explicit versus
>>> varargs implementations just to see the impact for myself.  The output
>>> and source code are included at the end of the email.
>>>
>>> -Michael
>>>
>>>
>>> On Fri, Nov 6, 2015 at 10:28 AM, Stuart Marks <stuart.marks at oracle.com>
>>> wrote:
>>>> On 11/6/15 5:12 AM, Michael Hixson wrote:
>>>>> +     static <E> List<E> of(E... es) {
>>>>> +         for (E e : es) {
>>>>> +             Objects.requireNonNull(e);
>>>>> +         }
>>>>> +         // NOTE: this can allow a null element to slip through
>>>>> +         return Collections.unmodifiableList(Arrays.asList(es));
>>>>> +     }
>>>>>
>>>>> Even as a skeletal implementation, this one has to be changed to be
>>>>> truly immutable, right?  It currently returns a view of the (mutable)
>>>>> argument array rather than new storage.  Sorry for not providing a
>>>>> proper test:
>>>> Good catch! Funnily I had noticed the TOCTOU case that allowed null
>>>> elements
>>>> in the array to slip through, but not that the array itself was still
>>>> modifiable from the outside. Anyway, I'll fix this. No worries about the
>>>> test.
>>>>
>>>>> Has anyone been able to quantify the advantage of having these
>>>>> overloads as opposed to having the varargs versions only?  Is it a
>>>>> matter of performance?
>>>>>
>>>>> I ask because the overloads seem like warts on the APIs (which is a
>>>>> shame -- List and Set are such important APIs).  I'm imagining a
>>>>> future where:
>>>>>
>>>>> 1. We add these overloads for performance gains now.
>>>>> 2. But they're all skeletal implementations that aren't that perfomant
>>>>> anyway.  Efficient versions don't make it into Java SE 9.  People that
>>>>> care a lot about performance avoid using these ones.
>>>>> 3. A few years later, varargs performance or some other language / VM
>>>>> / compiler-level change renders the overloads obsolete.
>>>> Yeah, the overloads seem like warts on the API, though probably
>>>> necessary
>>>> ones.
>>>>
>>>> At present, and for the forseeable future, varargs calls allocate an
>>>> array
>>>> on the heap, whereas fixed-args calls do not. I don't know how to
>>>> quantify
>>>> the difference though. Certainly the cost of allocation and
>>>> initialization
>>>> is borne in-line. Then there is the cost of collection. Collecting
>>>> short-lived objects is cheap (but not free). There is also the
>>>> possibility
>>>> of escape analysis eliminating the allocation. This seems unlikely to
>>>> me;
>>>> certainly not something to be relied upon.
>>>>
>>>> The most likely possible future optimization is "frozen arrays," part of
>>>> the
>>>> "Arrays 2.0" stuff that John Rose has talked about. This is basically
>>>> about
>>>> immutable arrays. Here, the possibility is to eliminate the defensive
>>>> copy,
>>>> if the array created to hold the varargs arguments is made immutable.
>>>> (This
>>>> will require some adjustment on the callee side, as yet unspecified.)
>>>> There's still an array, though. And a defensive copy would still have to
>>>> be
>>>> made if the caller passes an actual array, as opposed to a varargs list.
>>> (Realizing that we're discussing details of a feature that doesn't
>>> exist (frozen arrays)...)
>>>
>>> It seems to me that as long as the callee invoked the method with
>>> comma-separated arguments instead of an array, then the callee can
>>> automatically be opted into frozen arrays.  They never had access to
>>> the array box in the first place.
>>>
>>> It also seems like the varargs method could defensively call
>>> array.clone() and expect a no-op (return this) implementation if the
>>> array was already frozen, and so both sides could automatically
>>> benefit from frozen arrays without recompilation.  No?
>>>
>>>> While I can't quantify it, I do think there's an expense to creating the
>>>> varargs array, and there is only a possibility to reduce (but not
>>>> eliminate)
>>>> its cost in future JDK releases. This cost is entirely avoided by
>>>> fixed-args
>>>> overloads. (There is the cost of cluttering up the API, though.)
>>> I asked "Is it a matter of performance?" because I thought the
>>> justification for similar overloads in other APIs was different.  I
>>> thought EnumSet and Guava (for example) provided the overloads because
>>> @SafeVarargs did not exist at the time, and they didn't want to scare
>>> callers away with those silly warnings.
>>>
>>> Put another way:  if the justification for these new overloads is
>>> simply "the other APIs did it", I hope those original motivations are
>>> not being wrongly applied here.  It sounds like this is strictly about
>>> performance, though.
>>>
>>>> Turning to the skeletal vs. optimized implementation, my plan is
>>>> certainly
>>>> to ensure that the optimized implementations get into JDK 9. Of course,
>>>> plans can change. If the APIs get in without the optimized
>>>> implementations,
>>>> I think the big attractor will still be the convenience of using these
>>>> static factory methods as opposed to conventional code. They're no
>>>> slower
>>>> than conventional code, and the space consumed is the same. So I think
>>>> they'll be popular even if the space efficiency benefits aren't there
>>>> initially.
>>> For some reason I thought the optimized implementations had already
>>> been moved out of scope for Java 9.  I'm glad I was wrong!
>>>
>>>> When the optimized implementations do get in, callers will benefit, even
>>>> without recompilation. Thus there is some present value added based on
>>>> potential future benefits.
>>>>
>>>> There is always the set of possible future events that cause something
>>>> not
>>>> to work out, but I think pursuing the approach I've outlined has a good
>>>> chance of benefiting the platform in the long term.
>>>>
>>>> s'marks
>>> ----------------------------------------
>>>
>>> Benchmark           Mode  Cnt   Score   Error  Units
>>> ListOf.explicit_00  avgt   40   2.564 ± 0.007  ns/op
>>> ListOf.explicit_01  avgt   40   7.859 ± 0.022  ns/op
>>> ListOf.explicit_02  avgt   40  15.808 ± 0.338  ns/op
>>> ListOf.explicit_03  avgt   40  19.145 ± 0.978  ns/op
>>> ListOf.explicit_04  avgt   40  18.558 ± 0.314  ns/op
>>> ListOf.explicit_05  avgt   40  23.457 ± 1.069  ns/op
>>> ListOf.explicit_06  avgt   40  21.398 ± 0.255  ns/op
>>> ListOf.explicit_07  avgt   40  25.307 ± 0.672  ns/op
>>> ListOf.explicit_08  avgt   40  24.137 ± 0.376  ns/op
>>> ListOf.explicit_09  avgt   40  27.418 ± 0.560  ns/op
>>> ListOf.explicit_10  avgt   40  26.871 ± 0.506  ns/op
>>> ListOf.varargs_00   avgt   40  13.520 ± 0.177  ns/op
>>> ListOf.varargs_01   avgt   40  23.740 ± 0.346  ns/op
>>> ListOf.varargs_02   avgt   40  23.435 ± 0.321  ns/op
>>> ListOf.varargs_03   avgt   40  29.564 ± 0.744  ns/op
>>> ListOf.varargs_04   avgt   40  29.640 ± 1.329  ns/op
>>> ListOf.varargs_05   avgt   40  34.552 ± 0.639  ns/op
>>> ListOf.varargs_06   avgt   40  34.249 ± 0.476  ns/op
>>> ListOf.varargs_07   avgt   40  40.656 ± 0.589  ns/op
>>> ListOf.varargs_08   avgt   40  39.900 ± 0.595  ns/op
>>> ListOf.varargs_09   avgt   40  45.060 ± 1.098  ns/op
>>> ListOf.varargs_10   avgt   40  44.546 ± 0.816  ns/op
>>>
>>> ----------------------------------------
>>>
>>> package rnd;
>>>
>>> import org.openjdk.jmh.annotations.Benchmark;
>>> import org.openjdk.jmh.annotations.BenchmarkMode;
>>> import org.openjdk.jmh.annotations.Fork;
>>> import org.openjdk.jmh.annotations.Measurement;
>>> import org.openjdk.jmh.annotations.Mode;
>>> import org.openjdk.jmh.annotations.OutputTimeUnit;
>>> import org.openjdk.jmh.annotations.Scope;
>>> import org.openjdk.jmh.annotations.State;
>>> import org.openjdk.jmh.annotations.Warmup;
>>> import org.openjdk.jmh.runner.Runner;
>>> import org.openjdk.jmh.runner.options.Options;
>>> import org.openjdk.jmh.runner.options.OptionsBuilder;
>>>
>>> import java.util.AbstractList;
>>> import java.util.Collections;
>>> import java.util.List;
>>> import java.util.Objects;
>>> import java.util.concurrent.TimeUnit;
>>>
>>> @State(Scope.Thread)
>>> @BenchmarkMode(Mode.AverageTime)
>>> @OutputTimeUnit(TimeUnit.NANOSECONDS)
>>> @Warmup(iterations = 20)
>>> @Measurement(iterations = 20)
>>> @Fork(2)
>>> public class ListOf {
>>>
>>>    private static final String o = "";
>>>
>>>    public static void main(String[] args) throws Exception {
>>>      Options options = new OptionsBuilder()
>>>          .include(ListOf.class.getName())
>>>          .build();
>>>      new Runner(options).run();
>>>    }
>>>
>>>    @Benchmark public List<String> explicit_00() { return explicit(); }
>>>    @Benchmark public List<String> explicit_01() { return explicit(o); }
>>>    @Benchmark public List<String> explicit_02() { return explicit(o,o); }
>>>    @Benchmark public List<String> explicit_03() { return explicit(o,o,o); }
>>>    @Benchmark public List<String> explicit_04() { return explicit(o,o,o,o);
>>> }
>>>    @Benchmark public List<String> explicit_05() { return
>>> explicit(o,o,o,o,o); }
>>>    @Benchmark public List<String> explicit_06() { return
>>> explicit(o,o,o,o,o,o); }
>>>    @Benchmark public List<String> explicit_07() { return
>>> explicit(o,o,o,o,o,o,o); }
>>>    @Benchmark public List<String> explicit_08() { return
>>> explicit(o,o,o,o,o,o,o,o); }
>>>    @Benchmark public List<String> explicit_09() { return
>>> explicit(o,o,o,o,o,o,o,o,o); }
>>>    @Benchmark public List<String> explicit_10() { return
>>> explicit(o,o,o,o,o,o,o,o,o,o); }
>>>
>>>    @Benchmark public List<String> varargs_00() { return varargs(); }
>>>    @Benchmark public List<String> varargs_01() { return varargs(o); }
>>>    @Benchmark public List<String> varargs_02() { return varargs(o,o); }
>>>    @Benchmark public List<String> varargs_03() { return varargs(o,o,o); }
>>>    @Benchmark public List<String> varargs_04() { return varargs(o,o,o,o); }
>>>    @Benchmark public List<String> varargs_05() { return varargs(o,o,o,o,o);
>>> }
>>>    @Benchmark public List<String> varargs_06() { return
>>> varargs(o,o,o,o,o,o); }
>>>    @Benchmark public List<String> varargs_07() { return
>>> varargs(o,o,o,o,o,o,o); }
>>>    @Benchmark public List<String> varargs_08() { return
>>> varargs(o,o,o,o,o,o,o,o); }
>>>    @Benchmark public List<String> varargs_09() { return
>>> varargs(o,o,o,o,o,o,o,o,o); }
>>>    @Benchmark public List<String> varargs_10() { return
>>> varargs(o,o,o,o,o,o,o,o,o,o); }
>>>
>>>    static <E> List<E> explicit() {
>>>      return Collections.emptyList();
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1) {
>>>      return Collections.singletonList(Objects.requireNonNull(e1));
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1, E e2) {
>>>      return new ImmutableList<>(new Object[] {
>>>          Objects.requireNonNull(e1),
>>>          Objects.requireNonNull(e2)
>>>      });
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1, E e2, E e3) {
>>>      return new ImmutableList<>(new Object[] {
>>>          Objects.requireNonNull(e1),
>>>          Objects.requireNonNull(e2),
>>>          Objects.requireNonNull(e3)
>>>      });
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1, E e2, E e3, E e4) {
>>>      return new ImmutableList<>(new Object[] {
>>>          Objects.requireNonNull(e1),
>>>          Objects.requireNonNull(e2),
>>>          Objects.requireNonNull(e3),
>>>          Objects.requireNonNull(e4)
>>>      });
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5) {
>>>      return new ImmutableList<>(new Object[] {
>>>          Objects.requireNonNull(e1),
>>>          Objects.requireNonNull(e2),
>>>          Objects.requireNonNull(e3),
>>>          Objects.requireNonNull(e4),
>>>          Objects.requireNonNull(e5)
>>>      });
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6) {
>>>      return new ImmutableList<>(new Object[] {
>>>          Objects.requireNonNull(e1),
>>>          Objects.requireNonNull(e2),
>>>          Objects.requireNonNull(e3),
>>>          Objects.requireNonNull(e4),
>>>          Objects.requireNonNull(e5),
>>>          Objects.requireNonNull(e6)
>>>      });
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
>>>      return new ImmutableList<>(new Object[] {
>>>          Objects.requireNonNull(e1),
>>>          Objects.requireNonNull(e2),
>>>          Objects.requireNonNull(e3),
>>>          Objects.requireNonNull(e4),
>>>          Objects.requireNonNull(e5),
>>>          Objects.requireNonNull(e6),
>>>          Objects.requireNonNull(e7)
>>>      });
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E
>>> e8) {
>>>      return new ImmutableList<>(new Object[] {
>>>          Objects.requireNonNull(e1),
>>>          Objects.requireNonNull(e2),
>>>          Objects.requireNonNull(e3),
>>>          Objects.requireNonNull(e4),
>>>          Objects.requireNonNull(e5),
>>>          Objects.requireNonNull(e6),
>>>          Objects.requireNonNull(e7),
>>>          Objects.requireNonNull(e8)
>>>      });
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6, E
>>> e7, E e8, E e9) {
>>>      return new ImmutableList<>(new Object[] {
>>>          Objects.requireNonNull(e1),
>>>          Objects.requireNonNull(e2),
>>>          Objects.requireNonNull(e3),
>>>          Objects.requireNonNull(e4),
>>>          Objects.requireNonNull(e5),
>>>          Objects.requireNonNull(e6),
>>>          Objects.requireNonNull(e7),
>>>          Objects.requireNonNull(e8),
>>>          Objects.requireNonNull(e9)
>>>      });
>>>    }
>>>
>>>    static <E> List<E> explicit(E e1, E e2, E e3, E e4, E e5, E e6, E
>>> e7, E e8, E e9, E e10) {
>>>      return new ImmutableList<>(new Object[] {
>>>          Objects.requireNonNull(e1),
>>>          Objects.requireNonNull(e2),
>>>          Objects.requireNonNull(e3),
>>>          Objects.requireNonNull(e4),
>>>          Objects.requireNonNull(e5),
>>>          Objects.requireNonNull(e6),
>>>          Objects.requireNonNull(e7),
>>>          Objects.requireNonNull(e8),
>>>          Objects.requireNonNull(e9),
>>>          Objects.requireNonNull(e10)
>>>      });
>>>    }
>>>
>>>    @SafeVarargs
>>>    static <E> List<E> varargs(E... elements) {
>>>      int length = elements.length;
>>>      Object[] copy = new Object[length];
>>>      System.arraycopy(elements, 0, copy, 0, length);
>>>      for (Object e : copy) Objects.requireNonNull(e);
>>>      return new ImmutableList<>(copy);
>>>    }
>>>
>>>    static final class ImmutableList<E> extends AbstractList<E> {
>>>      final Object[] array;
>>>
>>>      ImmutableList(Object[] array) {
>>>        this.array = array;
>>>      }
>>>
>>>      @Override
>>>      @SuppressWarnings("unchecked")
>>>      public E get(int index) {
>>>        return (E) array[index];
>>>      }
>>>
>>>      @Override
>>>      public int size() {
>>>        return array.length;
>>>      }
>>>    }
>>> }




More information about the core-libs-dev mailing list