Last active
May 6, 2017 16:30
-
-
Save yradtsevich/991ca6896998c371b4d5b7ca20144d25 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
import java.util.Optional; | |
import java.util.Random; | |
import java.util.function.Supplier; | |
/* | |
================= RESULTS ================= | |
============================= | |
NpeCatchDeepGetter: | |
dt = 200, c = 8190023 | |
dt = 170, c = 8190023 | |
dt = 153, c = 8190023 | |
dt = 149, c = 8190023 | |
dt = 143, c = 8190023 | |
dt = 131, c = 8190023 | |
dt = 152, c = 8190023 | |
dt = 147, c = 8190023 | |
dt = 144, c = 8190023 | |
dt = 139, c = 8190023 | |
Call statistics (except the first 5 calls): LongSummaryStatistics{count=5, sum=713, min=131, average=142.600000, max=152} | |
============================= | |
IfDeepGetter: | |
dt = 180, c = 8190023 | |
dt = 142, c = 8190023 | |
dt = 136, c = 8190023 | |
dt = 133, c = 8190023 | |
dt = 162, c = 8190023 | |
dt = 149, c = 8190023 | |
dt = 150, c = 8190023 | |
dt = 148, c = 8190023 | |
dt = 147, c = 8190023 | |
dt = 145, c = 8190023 | |
Call statistics (except the first 5 calls): LongSummaryStatistics{count=5, sum=739, min=145, average=147.800000, max=150} | |
============================= | |
LambdaElvisDeepGetter: | |
dt = 969, c = 8190023 | |
dt = 611, c = 8190023 | |
dt = 644, c = 8190023 | |
dt = 604, c = 8190023 | |
dt = 732, c = 8190023 | |
dt = 659, c = 8190023 | |
dt = 669, c = 8190023 | |
dt = 370, c = 8190023 | |
dt = 620, c = 8190023 | |
dt = 367, c = 8190023 | |
Call statistics (except the first 5 calls): LongSummaryStatistics{count=5, sum=2685, min=367, average=537.000000, max=669} | |
============================= | |
TernaryDeepGetter: | |
dt = 237, c = 8190023 | |
dt = 239, c = 8190023 | |
dt = 171, c = 8190023 | |
dt = 177, c = 8190023 | |
dt = 191, c = 8190023 | |
dt = 174, c = 8190023 | |
dt = 190, c = 8190023 | |
dt = 198, c = 8190023 | |
dt = 172, c = 8190023 | |
dt = 168, c = 8190023 | |
Call statistics (except the first 5 calls): LongSummaryStatistics{count=5, sum=902, min=168, average=180.400000, max=198} | |
============================= | |
LambdaNpeCatchDeepGetter: | |
dt = 262, c = 8190023 | |
dt = 199, c = 8190023 | |
dt = 211, c = 8190023 | |
dt = 199, c = 8190023 | |
dt = 208, c = 8190023 | |
dt = 192, c = 8190023 | |
dt = 196, c = 8190023 | |
dt = 209, c = 8190023 | |
dt = 227, c = 8190023 | |
dt = 237, c = 8190023 | |
Call statistics (except the first 5 calls): LongSummaryStatistics{count=5, sum=1061, min=192, average=212.200000, max=237} | |
*/ | |
/** @author Yahor Radtsevich */ | |
public class Elvis { | |
private static final int N = 10_000_000; | |
public static void main(String[] args) { | |
A[] a = new A[N]; | |
Arrays.setAll(a, index -> randomA()); | |
for (DeepGetter deepGetter : new DeepGetter[]{new NpeCatchDeepGetter(), new IfDeepGetter(), new LambdaElvisDeepGetter(), new TernaryDeepGetter(), new LambdaNpeCatchDeepGetter()}) { | |
List<Long> dtList = new ArrayList<>(); | |
System.out.println("=============================\n" | |
+ deepGetter.getClass().getSimpleName() + ":"); | |
for (int i = 0; i < 10; i++) { | |
long t0 = System.currentTimeMillis(); | |
int c = 0; | |
for (int j = 0; j < N; j++) { | |
c += deepGetter.getLength(a[j]); | |
} | |
long dt = System.currentTimeMillis() - t0; | |
dtList.add(dt); | |
System.out.println("dt = " + dt + ", c = " + c); | |
} | |
System.out.println("Call statistics (except the first 5 calls): " + dtList.stream().skip(5).mapToLong(x -> x).summaryStatistics()); | |
} | |
} | |
private interface DeepGetter { | |
int getLength(A a); | |
} | |
private static class LambdaElvisDeepGetter implements DeepGetter { | |
public int getLength(A a) { | |
return Optional.ofNullable(a) | |
.map(A::getB) | |
.map(B::getC) | |
.map(C::getS) | |
.map(String::length) | |
.orElse(0); | |
} | |
} | |
private static class TernaryDeepGetter implements DeepGetter { | |
public int getLength(A a) { | |
return a == null ? 0 | |
: a.getB() == null ? 0 | |
: a.getB().getC() == null ? 0 | |
: a.getB().getC().getS() == null ? 0 | |
: a.getB().getC().getS().length(); | |
} | |
} | |
private static class IfDeepGetter implements DeepGetter { | |
public int getLength(A a) { | |
if (a != null) { | |
B b = a.getB(); | |
if (b != null) { | |
C cc = b.getC(); | |
if (cc != null) { | |
String s = cc.getS(); | |
if (s != null) { | |
return s.length(); | |
} | |
} | |
} | |
} | |
return 0; | |
} | |
} | |
private static class NpeCatchDeepGetter implements DeepGetter { | |
public int getLength(A a) { | |
try { | |
return a.getB().getC().getS().length(); | |
} catch (NullPointerException e) { | |
return 0; | |
} | |
} | |
} | |
private static class LambdaNpeCatchDeepGetter implements DeepGetter { | |
public int getLength(A a) { | |
return NpeSafeLambda.get(() -> a.getB().getC().getS().length()); | |
} | |
} | |
static class NpeSafeLambda { | |
static Integer get(Supplier<Integer> f) { | |
try { | |
return f.get(); | |
} catch (NullPointerException e) { | |
return 0; | |
} | |
} | |
} | |
private static Random random = new Random(1); | |
private static A randomA() { | |
int rand = random.nextInt(); | |
A a = null; | |
if ((rand & 0xF) != 0) { // probability = 15/16 = 0.9375 | |
a = new A(); | |
if ((rand & (0x7 << 4)) != 0) { // probability = 7/8 * 15/16 = 0.8203125 | |
B b = new B(); | |
a.setB(b); | |
if ((rand & (0x3 << 7)) != 0) { // probability = 3/4 * 7/8 * 15/16 = 0.615234375 | |
C c = new C(); | |
b.setC(c); | |
if ((rand & (0x1 << 9)) != 0) { // probability = 1/2 * 3/4 * 7/8 * 15/16 = 0.3076171875 | |
StringBuilder sBuilder = new StringBuilder(10); | |
for (int i = 0; i < random.nextInt(10); i++) { | |
sBuilder.append((char) (random.nextInt('Z' - 'A' + 1) + 'A')); | |
} | |
c.setS(sBuilder.toString()); | |
} | |
} | |
} | |
} | |
return a; | |
} | |
private static class A { | |
B b; | |
public B getB() { | |
return b; | |
} | |
public void setB(B b) { | |
this.b = b; | |
} | |
} | |
private static class B { | |
C c; | |
public C getC() { | |
return c; | |
} | |
public void setC(C c) { | |
this.c = c; | |
} | |
} | |
private static class C { | |
String s; | |
public String getS() { | |
return s; | |
} | |
public void setS(String s) { | |
this.s = s; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment