refactoring to java 8 (devoxx be)
TRANSCRIPT
It’s Faster
•Performance Improvements in Common Data Structures
•Fork/Join Speed Improvements
•Changes to Support Concurrency
•…and more
http://bit.ly/refJ8
Anonymous Inner Classes vs Lambdas
public String[] decodeWithAnonymousInnerClass(final BenchmarkState state) {
IterHelper.loopMap(state.values, new IterHelper.MapIterCallback<Integer, String>() {
@Override
public void eval(final Integer key, final String value) {
state.arrayOfResults[key] = value;
}
});
return state.arrayOfResults;
}
public void decodeWithLambda(final BenchmarkState state) {
IterHelper.<Integer, String>loopMap(state.values,
(key, value) -> state.arrayOfResults[key] = value) ;
}
0
20
40
60
80
100
120
140
160
180O
ps/
ms
Anonymous Inner Classes vs Lambdas
Anonymous Inner Class Lambda
http://www.oracle.com/technetwork/java/jvmls2013kuksen-2014088.pdf
0
2
4
6
8
10
12
14
16
18
20
single thread max threads
nse
c/o
p
Performance of Capture
anonymous(static) anonymous(non-static) lambda
Logging Performance
public void loggingConstantMessage(BenchmarkState state) {
log("Logging");
}
public void loggingConstantMessageWithLambda(BenchmarkState state) {
log(() -> "Logging");
}
public void loggingVariableMessage(BenchmarkState state) {
log("Logging: " + state.i);
}
public void loggingVariableMessageWithLambda(BenchmarkState state) {
log(() -> "Logging: " + state.i);
}
0
50,000
100,000
150,000
200,000
250,000
300,000
350,000
400,000
450,000
500,000
Constant message Variable message
Op
s/m
sLogging Performance
Direct call Lambda
EntityScanner– forEach()
public void mapAllClassesAnnotatedWithEntity (Morphia m) {
final Reflections r = new Reflections(conf);
final Set<Class<?>> entities = r.getTypesAnnotatedWith(Entity.class);
for (final Class<?> c : entities) {
m.map(c);
}
}
public void mapAllClassesAnnotatedWithEntity(Morphia m) {
new Reflections(conf).getTypesAnnotatedWith(Entity.class).forEach(m::map);
}
BasicDAO – map & collectpublic List originalIterationCode() {
final List<Object> ids = new ArrayList<>(keys.size() * 2)
for (final Key<Object> key : keys) {
ids.add(key.getId());
}
return ids;
}
public List simplifiedIterationCode() {
final List<Object> ids = new ArrayList<>()
for (final Key<Object> key : keys) {
ids.add(key.getId());
}
return ids;
}
public List refactoredCode() {
return keys.stream()
.map(Key::getId)
.collect(toList());
0
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
Op
s/s
BasicDAO – map().collect() - 10 elements
original simplified refactored parallel
0
0.5
1
1.5
2
2.5
3
3.5
Op
s/s
BasicDAO – map().collect() - 10 000 element
original simplified refactored parallel
ReflectionUtils
public static List<Field> original(final Field[] fields, final boolean returnFinalFields) {
final List<Field> validFields = new ArrayList<Field>();
// we ignore static and final fields
for (final Field field : fields) {
if (!Modifier.isStatic(field.getModifiers()) && (returnFinalFields || !Modifier.isFinal(field.getModifiers()))) {
validFields.add(field);
}
}
return validFields;
}
public static List<Field> refactored(final Field[] fields, final boolean returnFinalFields) {
return Arrays.stream(fields)
.filter(field -> isNotStaticOrFinal(returnFinalFields, field))
.collect(Collectors.toList());
}
0
2000
4000
6000
8000
10000
12000
14000
Axi
s Ti
tle
ReflectionUtils – Arrays.stream().map().collect()
original refactored
0
1
2
3
4
5
6
7
8
9
10
EntityWithOneError EntityWith10Errors EntityWith20Errors
Op
s/s
Mapping Validator - multiple operations
original refactored
QueryImpl – multiple operationspublic String[] retrieveKnownFields(org.mongodb.morphia.DatastoreImpl ds, Class clazz) {
final MappedClass mc = ds.getMapper().getMappedClass(clazz);
final List<String> fields = new ArrayList<String>(mc.getPersistenceFields().size() + 1);
for (final MappedField mf : mc.getPersistenceFields()) {
fields.add(mf.getNameToStore());
}
return fields.toArray(new String[fields.size()]);
}
public String[] retrieveKnownFieldsRefactored(org.mongodb.morphia.DatastoreImpl ds, Class clazz) {
final MappedClass mc = ds.getMapper().getMappedClass(clazz);
return mc.getPersistenceFields()
.stream()
.map(MappedField::getNameToStore)
.collect(Collectors.toList())
.toArray(new String[0]);
}
public String[] retrieveKnownFields(org.mongodb.morphia.DatastoreImpl ds, Class clazz) {
final MappedClass mc = ds.getMapper().getMappedClass(clazz);
return mc.getPersistenceFields()
.stream()
.map(MappedField::getNameToStore)
.toArray(String[]::new);
}
0
500
1000
1500
2000
2500
3000
3500
4000
Op
s/s
QueryImpl - multiple operations
original simplified refactored refactoredMore
TypeConverter – anyMatch()
protected boolean oneOfClasses(final Class f, final Class[] classes) {
for (final Class c : classes) {
if (c.equals(f)) {
return true;
}
}
return false;
}
protected boolean oneOfClasses(final Class f, final Class[] classes) {
return Arrays.stream(classes)
.anyMatch(c -> c.equals(f));
}
protected boolean oneOfClasses(final Class f, final Class[] classes) {
return Arrays.stream(classes)
.parallel()
.anyMatch(c -> c.equals(f));
}
0
10000
20000
30000
40000
50000
60000
70000
Op
s/s
TypeConverter – anyMatch() – 10 Values
original refactored parallel
0
5000
10000
15000
20000
25000
30000
Axi
s Ti
tle
MapreduceType - IntStream().map().filter().findFirst()
original refactored
Mapper – findFirst()
public static Class<? extends Annotation> original(final MappedField mf) {
Class<? extends Annotation> annType = null;
for (final Class<? extends Annotation> testType : new Class[]{Property.class, Embedded.class, Serialized.class, Reference.class
if (mf.hasAnnotation(testType)) {
annType = testType;
break;
}
}
return annType;
}
public static Class<? extends Annotation> refactored(final MappedField mf) {
return (Class<? extends Annotation>) Arrays.stream(new Class[]{Property.class, Embedded.class, Serialized.class, Reference
.filter(mf::hasAnnotation)
.findFirst()
.orElse(null);
}
public static Class<? extends Annotation> refactoredMore(final MappedField mf) {
return (Class<? extends Annotation>) Stream.of(Property.class, Embedded.class, Serialized.class, Reference.class)
.filter(mf::hasAnnotation)
.findFirst()
.orElse(null);
}
0
5000
10000
15000
20000
25000
30000
35000
40000
45000
50000
Op
s/s
Mapper – Arrays.stream().filter().findFirst()
original refactored more
0
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
Op
s/s
Converters - stream().filter().findFirst() – 10 Elements
original refactored parallel
0
0.5
1
1.5
2
2.5
3
3.5
Op
s/s
Converters – stream().filter().findFirst() – 10 000 elements
original refactored parallel
0
20
40
60
80
100
120
140
160
180
Op
s/m
s…and pretty safe performance-wise
Anonymous Inner Class Lambda
0
50,000
100,000
150,000
200,000
250,000
300,000
350,000
400,000
450,000
500,000
Constant message Variable message
Op
s/m
sLogging Performance
Direct call Lambda
public List originalIterationCode() {
final List<Object> ids = new ArrayList<>(keys.size() * 2)
for (final Key<Object> key : keys) {
ids.add(key.getId());
}
return ids;
}
public List refactoredCode() {
return keys.stream()
.map(Key::getId)
.collect(toList());
BasicDAO – map().collect()
protected boolean oneOfClasses(final Class f, final Class[] classes) {
for (final Class c : classes) {
if (c.equals(f)) {
return true;
}
}
return false;
}
protected boolean oneOfClasses(final Class f, final Class[] classes) {
return Arrays.stream(classes)
.anyMatch(c -> c.equals(f));
}
TypeConverter – anyMatch()
public static Class<? extends Annotation> original(final MappedField mf) {
Class<? extends Annotation> annType = null;
for (final Class<? extends Annotation> testType : new Class[]{Property.class, Embedded.class, Serialized.class, Reference.class
if (mf.hasAnnotation(testType)) {
annType = testType;
break;
}
}
return annType;
}
public static Class<? extends Annotation> refactoredMore(final MappedField mf) {
return (Class<? extends Annotation>) Stream.of(Property.class, Embedded.class, Serialized.class, Reference.class)
.filter(mf::hasAnnotation)
.findFirst()
.orElse(null);
}
Mapper – findFirst()
0
10000
20000
30000
40000
50000
60000
70000
Op
s/s
TypeConverter - 10 Values
original refactored parallel
0
0.5
1
1.5
2
2.5
3
3.5
Op
s/s
BasicDAO – map().collect() - 10 000 element
original simplified refactored parallel