Skip to content

42patterns/training-java8-refactoring

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 

Repository files navigation

10 things we can do better with Java8

Or modern Java in general

Who am I?

Jakub Marchwicki
  • developer

  • position wise: ex-architect, ex-manager, ex-consultant

  • domain wise: insurance, banking, massive scale marketing, customer service, edu cation

  • Twitter: @kubem

#1. Lamdas in tests

  • DictDictionaryClientTest uses old-school pattern of @Test(expected = Exception.class) or a `fail()`method.

 — Can it be replaced with lambda expression?

 — Does it make tests more readable?

#2. Optional type

  • Optional<T> - returning container object instead of null values

 — For class DictionaryClient replace return value of firstTranslationFor() with Optional<DictionaryWord>. When no translations were found, there is not first item present and RuntimeException (currently thrown) is not the most elegant solution

 — When dealing with Optional type try to avoid sending it between modules (between public API) and unwrap it whenever suitable (like in BatchTranslateCommand)

Note
Can we make the firstTranslationFor() any prettier? Without pesky null and empty checks?

#3. isTraceEnabled()

  • ✓ Lazy logging evaluation

 — Slf4j (used in the project) by design avoids superfluous object creation when the logger is disabled on a particular level

 — This is not the case for JUL / Log4j so both java.util.logging.Logger and org.apache.logging.log4j.Logger allows Supplier arguments

log.trace(() -> "Lazy evaluated message with expensive toString: " + obj)

 — If you encapsulate logging framework with your own logging interface, the above can be also achieved with

default void trace(Supplier<String> messageSupplier) {
    if (isTraceEnabled()) {
        trace(messageSupplier.get());
    }
}

#4. Iterations vs streams

  • ❏ Replace DictDictionaryClient magic with a a stream() over lines read directly from the URL.

 — Java8 stream API is not complete and still some methods are missing. If similar approach is taken for BablaDictionaryClient it results in cumbersome and pesky stream interestion

 — There are additional Java8 stream support libraries worth trying: StreamEx, jOOL, Javaslang

 — Both jOOL and StreamEx are stream drop-in replacements - extending the Stream<T> interfaces, adding some important methods (like zip() or tuples)

 — Javaslang is a strategic decision of complete replacement of Collections API with a new library

#5. Better file handling

  • ❏ For BatchTranslateCommand use streams to read the input file.

 — Moar streams() everywhere.

 — Classes like Scanner I hope are well known to to everyone

new Scanner(inputStream).useDelimeter("\\A").next();

#6 Rethinking external libs

 — Do you really need Guava? What are you using that for?

 — Preconditions.checkNotNull(T) vs. Objects.notNull(T)

 — ImmulableList.of() vs Collections.unmodifiableList(T). One is truly immutable while the other is read-only.

#7 Composing future operations

 — With ComputableFuture every operation can be made async by passing a supplier to a supplyAsync() method

 — This get executed asynchronously on the current ThreadPool (default) or dedicated one.

 — We can create a copy of SyncTranslateCommand class and make the calls asynchronous

#8 Running both and accepting whichever first

 — We are having two separate dictionaries. We can call them both and take whichever comes first.

 — Tip: see CompletableFuture.applyToEither()

#9 Caching and storing to a map

  • ❏ Add new translations to already existing list in AppStateImpl.translations.

 — With Java8 the Map interface got updated with a few decent methods

 — map.ifAbsent(name, Supplier<T>) and map.merge(key, value, BiFunction<V>)

 — Map.merge() works more or less like this

 V oldValue = map.get(key);
 V newValue = (oldValue == null) ? value :
              remappingFunction.apply(oldValue, value);
 if (newValue == null)
     map.remove(key);
 else
     map.put(key, newValue);

 — There are many other small improvements through out the language versions

  • Collections.sort() → List.sort()

  • Integer.valueOf(x).compareTo(Integer.valueOf(y)) → Integer.compare(x, y)

  • System.getProperty("line.separator") → System.lineSeparator()

#10 Refactoring the printing methods

 — The PrintingTemplate is pretty bad, how can we do it better?

 — Some of the enhancements are suggested by the IDE

 — Replace if statements with Optional<T>, filtering and mapping on optional types

Bonus

Some videos to follow

Thank you

About

Example project for refactoring to Java8 workshop / hands-on-lab

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published