Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Writing beautiful code with Java 8

Avatar for Sergiu Indrie Sergiu Indrie
December 06, 2016

Writing beautiful code with Java 8

Java 8 helps use write better looking code. Checked exceptions, however, do not. What can we do to overcome these issues?
Lambdas and streams help us write clear and concise code, but can we do better? Javaslang helps out a bit.
Want more? Maybe turn to Scala.

Avatar for Sergiu Indrie

Sergiu Indrie

December 06, 2016
Tweet

Other Decks in Programming

Transcript

  1. Disclaimer This is not a clean code presentation, but rather

    a code esthetics oriented presentation which may include clean code.
  2. Ugly vs Beautiful for (int i = 0; i <

    meetings.size(); i++) { System.out.println(meetings); } for (Meeting meeting : meetings) { System.out.println(meeting); } meetings.forEach(System.out::println);
  3. Ugly vs Beautiful new Thread(new Runnable() { @Override public void

    run() { System.out.println("Complex stuff"); } }).start(); new Thread(() -> System.out.println("Complex stuff")).start();
  4. Ugly vs Beautiful Map<String, List<Meeting>> meetingsById = meetings.stream() .collect(Collectors.groupingBy(Meeting::getId)); Map<String,

    List<Meeting>> meetingsGrouped = new HashMap<>(); for (Meeting meeting : meetings) { if (!meetingsGrouped.containsKey(meeting.getId())) { meetingsGrouped.put(meeting.getId(), new ArrayList<>()); } meetingsGrouped.get(meeting.getId()).add(meeting); }
  5. Ugly vs Beautiful // guarded logging if (logger.isDebugEnabled()) { logger.debug("This

    {} and {} with {} ", 1, that, compute()); } VS logger.debug("This {} ", () -> compute());
  6. What’s “new” in Java 8? • Lambdas Runnable r2 =

    () -> System.out.println("Hello world two!"); • Streams List<Room> rooms = microsoftExchangeService.getRoomLists().getItems().parallelStream() .filter(this::isValidRoomList) .map(this::retrieveRoomsInRoomList) .flatMap(List::stream) .collect(Collectors.toList()); • Optional Optional<Meeting> meeting = meetingsDao.findById(meetingId); meeting.ifPresent(this::setMeetingAsManuallyEnded);
  7. Enemy #1: Checked Exceptions private static void checkedException() { List<String>

    strings = Arrays.asList(1, 2, 3, 4, 5).stream() .map(Exceptions::intToString) .collect(Collectors.toList()); System.out.println(strings); } private static String intToString(Integer number) throws Exception { if (number == 3) { throw new Exception("wrong number, pal!"); } return String.valueOf(number); }
  8. Enemy #1: Checked Exceptions • Complex issue (see Brian Goetz’s

    post from 2010) ◦ generic type parameters are monadic ⇒ one exact type ◦ throws clauses are variadic ⇒ 0 or more types • Solution?
  9. Enemy #1: Checked Exceptions - Solution • 1st Solution -

    Unchecked Exceptions* • 2nd Solution - Wrap to 1st (see org.jooq.lambda.Unchecked) public static <T> T unchecked(Callable<T> callable) { try { return callable.call(); } catch (Exception e) { throw new RuntimeException(e); } } List<Room> rooms = roomAddresses.parallelStream() .map(room -> unchecked(() -> getRoomWithoutMeetings(room))) .collect(Collectors.toList()); * Python, Scala, C#, Ruby, PHP … don’t have checked exceptions
  10. Enemy #1: Checked Exceptions - Solution public static <T> T

    unchecked(Callable<T> callable) { try { return callable.call(); } catch (ApiServiceException e) { throw new ApiServiceRuntimeException(e); } catch (Exception e) { throw runtime(e); } } private static RuntimeException runtime(Throwable e) { if (e instanceof RuntimeException) { return (RuntimeException) e; } return new RuntimeException(e); }
  11. Enemy #1: Checked Exceptions - Solution • A more functional

    approach String complexResult = Try.of(SomeClass::dangerousGet) .recover(x -> Match(x).of( Case(instanceOf(IllegalStateException.class), () -> "1st exception"), Case(instanceOf(IllegalArgumentException.class), () -> "2nd exception") )) .getOrElse("default2");
  12. By the way Java 9 brings: Collection Factory Methods* (all

    immutable) + some stream improvements like iterate, take/dropWhile * Nevermind if you’ve been using Guava, jOOQ
  13. Java 8 is nice, but don’t // long lambdas numbers.forEach(e

    -> { int count = 0; for(int i = 1; i <= e; i++) { if(e % i == 0) count++; } System.out.println(count); }); // unformatted streams List<String> strings = Arrays.asList(1, 2, 3).stream().map(Object::toString) .map(String::toUpperCase).limit(5).collect(Collectors.toList());
  14. Level up: Javaslang // Java 8 List<Integer> integers = Arrays.asList(1,

    2, 3, 4); List<Integer> evenNumbers = integers.stream() .filter(nr -> nr % 2 == 0) .collect(Collectors.toList()); // Javaslang List<Integer> integers = List.of(1, 2, 3, 4); List<Integer> evenIntegers = integers.filter(nr -> nr % 2 == 0); * javaslang.collection.List
  15. Level up: Javaslang • “...greatly inspired by Scala” • Hence

    very functional • facilitates functional programming through immutability
  16. List<Integer> integers = Arrays.asList(1, 2, 3, 4); • List is

    really javaslang.collection.List :) but we do have toJavaList/Array/Collection/Set() etc. public interface List<T> extends Kind1<List<?>, T>, LinearSeq<T>, Stack<T> { default java.util.List<T> toJavaList() { return ValueModule.toJavaCollection(this, new ArrayList<>()); } • All Javaslang collections are Iterable and thus can be used in enhanced for-statements for (String s : List.of("Java", "Advent")) { // side effects and mutation } Level up: Javaslang
  17. • Functional exception handling // no need to handle exceptions

    Try.of(SomeClass::bunchOfWork).getOrElse("default"); String complexResult = Try.of(SomeClass::dangerousGet) .recover(x -> Match(x).of( Case(instanceOf(IllegalStateException.class), () -> "1st exception"), Case(instanceOf(IllegalArgumentException.class), () -> "2nd exception") )) .getOrElse("default2"); Level up: Javaslang
  18. • Lazy Lazy<Double> lazy = Lazy.of(Math::random); lazy.isEvaluated(); // = false

    lazy.get(); // = 0.123 (random generated) lazy.isEvaluated(); // = true lazy.get(); // = 0.123 (memoized) • + other FP features like function composition, currying, memoization, lifting, immutable collections, tuples Level up: Javaslang
  19. Or maybe just switch to Scala :D // type inference,

    nice constructors, native streams API, no semicolons :) val integers = List(1, 2, 3, 4) val evenIntegers = integers.filter(_ % 2 == 0) // pre/post/infix operators val sum = (1 to 10).sum // immutable, generated equals/getter/toString/hashcode, pattern matching decomposition case class Person(firstName: String, lastName: String) object Singleton {} // immutable collections, XML processing, multiple inheritance, tuples, REPL etc.
  20. Or maybe just switch to Scala :D // pattern matching

    & decomposition object Demo { def main(args: Array[String]) { val alice = new Person("Alice", 25) val charlie = new Person("Charlie", 32) for (person <- List(alice, charlie)) { person match { case Person("Alice", 25) => println("Hi Alice!") case Person(name, age) => println( "Age: " + age + " year, name: " + name + "?") } } } case class Person(name: String, age: Int) }