writing beautiful code with java 8

27
Writing beautiful code with Java 8 [email protected]

Upload: sergiu-mircea-indrie

Post on 13-Jan-2017

55 views

Category:

Software


2 download

TRANSCRIPT

Page 1: Writing beautiful code with Java 8

Writing beautiful code with Java 8

[email protected]

Page 2: Writing beautiful code with Java 8

Disclaimer

This is not a clean code presentation, but rather a code esthetics oriented presentation which may include clean code.

Page 3: Writing beautiful code with Java 8

Beautiful code?

● Easy to read/understand/write● Concise● DSL-like● Clean code ++

Page 4: Writing beautiful code with Java 8

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);

Page 5: Writing beautiful code with Java 8

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();

Page 6: Writing beautiful code with Java 8

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);

}

Page 7: Writing beautiful code with Java 8

Ugly vs Beautiful

// guarded logging

if (logger.isDebugEnabled()) {

logger.debug("This {} and {} with {} ", 1, that, compute());

}

VS

logger.debug("This {} ", () -> compute());

Page 8: Writing beautiful code with Java 8

What’s “new” in Java 8?

● LambdasRunnable r2 = () -> System.out.println("Hello world two!");

● StreamsList<Room> rooms = microsoftExchangeService.getRoomLists().getItems().parallelStream()

.filter(this::isValidRoomList)

.map(this::retrieveRoomsInRoomList)

.flatMap(List::stream)

.collect(Collectors.toList());

● OptionalOptional<Meeting> meeting = meetingsDao.findById(meetingId);

meeting.ifPresent(this::setMeetingAsManuallyEnded);

Page 9: Writing beautiful code with Java 8

PS - Help from IDEA

● Migration suggestions (more to come in IDEA 2016.3)

Page 10: Writing beautiful code with Java 8

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);

}

Page 11: Writing beautiful code with Java 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?

Page 12: Writing beautiful code with Java 8

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

Page 13: Writing beautiful code with Java 8

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);

}

Page 14: Writing beautiful code with Java 8

Enemy #1: Checked Exceptions - Solution

● A more functional approach

Page 15: Writing beautiful code with Java 8

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");

Page 16: Writing beautiful code with Java 8

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

Page 17: Writing beautiful code with Java 8

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());

Page 18: Writing beautiful code with Java 8

Java 8 is nice, but

Java 8 Computation Style

Page 19: Writing beautiful code with Java 8

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

Page 20: Writing beautiful code with Java 8

Level up: Javaslang

● “...greatly inspired by Scala”

● Hence very functional

● facilitates functional programming through immutability

Page 21: Writing beautiful code with Java 8

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

Page 22: Writing beautiful code with Java 8

● 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

Page 23: Writing beautiful code with Java 8

● 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

Page 24: Writing beautiful code with Java 8

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.

Page 25: Writing beautiful code with Java 8

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)

}

Page 26: Writing beautiful code with Java 8

References

https://github.com/tedyoung/awesome-java8https://blog.jooq.org/2014/05/02/java-8-friday-lets-deprecate-those-legacy-libs/https://blog.jetbrains.com/idea/2016/07/java-8-top-tips/http://blog.agiledeveloper.com/2015/06/lambdas-are-glue-code.htmlhttps://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-log4j-api-and-lambda-basics/https://dzone.com/articles/java-8-functional-interfaces-0http://openjdk.java.net/jeps/269https://blogs.oracle.com/briangoetz/entry/exception_transparency_in_javahttp://www.artima.com/intv/handcuffs.htmlhttp://www.mindview.net/Etc/Discussions/CheckedExceptionshttps://github.com/jOOQ/jOOL#orgjooqlambdauncheckedhttp://iteratrlearning.com/java9/2016/08/06/java9-streams.htmlhttp://www.javaslang.io/http://www.scala-lang.org/

Page 27: Writing beautiful code with Java 8

That’s all folks!