Advanced Java
Tipps & Tricks
1. Lambdas
2. Streams
3. Debugging
Don't force
Only use when you are sure
Not applicable everywhere
Lambdas
Basics
Lambdas are short-forms for functions
Great for tasks that are 1-5 lines long
Helpful to break tasks in to elementary blocks
(a, b) -> {
// CODE here
return abc;
}Input list
Lambda arrow
Function braces
Raw code
Consumer<T>
// Notation
(input) -> {
execute(input);
}
// Example
list.forEach((input) -> {
execute(input);
});
// Equivalent Code
for (int i = 0; i < list.size(); i++) {
__consumer_lambda(list.get(i));
}
private void __consumer_lambda(Object input) {
execute(input);
}- Consumes 1 Object, returns void
- Often used in forEach functions
Supplier<T>
// Notation
() -> {
return new Object();
}
// Example
stream.reduce(() -> {
return new Integer(0);
}, (a, b) -> {
return a + b;
});
// Equivalent Code
private Object __supplier_lambda() {
return new Object();
}- Consumes nothing, supplies 1 object
- Rarely used, more in PProg
Function<T, R>
// Notation
(a) -> {
return new Person(a);
}
// Example
stream.map((a) -> {
return new Person(a);
});
// Equivalent Code
for (int i = 0; i < ageList.size(); i++) {
int age = ageList.get(i);
Person person = __function_lambda(age);
personList.add(person);
}
private Person __function_lambda(int age) {
return new Person(age);
}- Consumes 1 object, returns 1 object
- Used to map from a→b
BiFunction<T, U, R>
// Notation
(a, b) -> {
return (a + b)/2;
}
// Example
stream.reduce((a, b) -> {
return a + "-" + b;
});
// Equivalent Code
String reduced = list.get(0);
for (int i = 1; i < list.size(); i++) {
reduced = __bifunction_lambda(reduced, list.get(i));
}
private String __bifunction_lambda(String a, String b) {
return a + "-" + b;
}- Consumes 2 objects, returns 1 object
- Used to sort
Sugar

Nicer syntax
- One liners don't need braces
{} - Existing functions can be referenced with
:: - Use
.x().x()for chaining
(a) -> {
return a - 1;
}(a) -> a - 1(a) -> {
return this.func(a);
}this::funcStream<?> a = list.stream();
Stream<?> b = a.filter(...);
Stream<?> c = b.map(...);
Stream<?> d = c.distinct();Stream<?> d = list.stream()
.filter(...)
.map(...)
.distinct();Streams!
This is ugly
int[] ages; // This is given from Thomas Gross
int pos;
int temp;
for (int i = 0; i < ages.length; i++) { // Sort ages
pos = i;
for (int j = i+1; j < ages.length; j++) {
if (ages[j] < ages[pos]) {
pos = j;
}
}
temp = ages[pos];
ages[pos] = ages[i];
ages[i] = temp;
}
List<Person> personList = new LinkedList<>();
for (int i = 0; i < ages.length; i++) {
if (ages[i] > 25) { // Exclude by age
personList.add(new Person(ages[i]));
}
}
return personList.get(0); // Return firstmin. 28 Points of failure
This is better
int[] ages; // This is given from Thomas Gross
return IntStream.of(ages)
.sorted()
.filter(age -> age > 25)
.mapToObj(age -> new Person(age))
.findFirst()
.get();Sort
Filter by age
Map to person
Retrieve first
7 Points of Failure
Streams are:
- less prone to errors
- pre-built
- easy to reuse
- available (almost) everywhere
(new ArrayList<>()).stream();
(new LinkedList<>()).stream();
(new HashSet<>()).stream();
(new HashMap<>()).entrySet().stream();
(new PriorityQueue<>()).stream();Stream Structure
- Start often via
.stream() - Intermediate steps
- Terminal operation
Intermediate
Terminal
.map(Function<A,B>).filter(Predicate<A>).distinct().sorted().limit(long).flatMap(Function<A,B>)
.reduce(BinaryOperator<T>).allMatch(Predicate<T>).anyMatch(Predicate<T>).forEach(Consumer<T>).count().collect().min().max()
Example 1
Get the unique surnames in uppercase of the first 15 book authors that are 50 y/o or older.
class Book {
Author author;
}
class Author {
String firstname;
String surname;
int age;
}
List<Book> library;library.stream()
.map(book -> book.getAuthor())
.filter(author -> author.getAge() >= 50)
.map(author -> author.getSurname())
.distinct()
.limit(15)
.map(name -> name.toUpperCase())
.collect(Collectors.toList());Example 2
Compute the sum of ages of all female authors younger than 25
class Book {
Author author;
}
class Author {
String firstname;
String surname;
int age;
Gender gender;
}
enum Gender {
MALE, FEMALE;
}
List<Book> library;library.stream()
.map(book -> book.getAuthor())
.distinct()
.filter(author -> author.getAge() < 25)
.filter(author -> author.getGender() == FEMALE)
.mapToInt(author -> author.getAge())
.sum();Collectors

DO NOT TRY THIS AT HOME*
* unless you are really, really, really good
// Accumulate names into a List
List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
// Accumulate names into a TreeSet
Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
// Convert elements to strings and concatenate them, separated by commas
String joined = things.stream()
.map(Object::toString)
.collect(Collectors.joining(", "));
// Compute sum of salaries of employee
int total = employees.stream()
.collect(Collectors.summingInt(Employee::getSalary)));
// Group employees by department
Map<Department, List<Employee>> byDept
= employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
// Compute sum of salaries by department
Map<Department, Integer> totalByDept
= employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment,
Collectors.summingInt(Employee::getSalary)));
// Partition students into passing and failing
Map<Boolean, List<Student>> passingFailing =
students.stream()
.collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));Debugging

Stuck? Use auto-complete

name(Argument) : returnType
filter(Predicate<Integer>) : Steam<Integer>
filter die Daten
das jede Zahl hier true ergibt
gib uns wieder einen Stream zurück
Crtl + Space
Stuck? Use auto-complete

x 2
EXERCISE!
Exercise
Print the titles of all books that aren't in the library.
Get Titles
Check in library
Get all books
MODULAR DESIGN
Exercise
Print the titles of all books that aren't in the library.
Get Titles
Check in library
Get all books
MODULAR DESIGN
Exercise
Print the titles of all books that aren't in the library.
Get Titles
Check in library
Get all books
MODULAR DESIGN
Exercise
Print the titles of all books that aren't in the library.
Get Titles
Check in library
Get all books
MODULAR DESIGN
Exercise
Print the titles of all books that aren't in the library.
Get Titles
Check in library
Get all books
MODULAR DESIGN
Exercise
Print the titles of all books that aren't in the library.
Get Titles
Check in library
Get all books
author.authoredlibrary.contains()book.titleSystem.out.println()MODULAR DESIGN
Exercise
Print the titles of all books that aren't in the library.
class Book {
Author author;
String title;
}
class Author {
String firstname;
String surname;
int age;
List<Book> authored;
}
List<Book> library;library.stream()
.map(book -> book.author)
.flatMap(author -> author.authored.stream())
.filter(book -> !library.contains(book))
.distinct()
.map(book -> book.title)
.forEach(title -> System.out.println(title));Hint: flatMap(item -> item.list.stream())
Previous Exams
A1, FS18


Hint 1: Automate the iteration
Hint 2: Calculate the difference per entry
A2, HS18
Hint 1: Collections.reverseOrder()
Hint 2: .limit()

A2, HS18

A4, FS19
Hint 1: Collectors.toMap()

A4, FS19
public class Inspektor {
// Store a reference to all stalls that have previously been scanned
private List<Stall> stalls = new ArrayList<Stall>();
// Store references to stalls that had parasites at some point in time
private Set<Stall> parasiteStalls = new HashSet<Stall>();
public Map<String, String> besteStaelle() {
return stalls.stream()
// Grab a stream of all distinct manufacturer names
.map(stall -> stall.manufacturer)
.distinct()
// Generate pairs (manufacturer, bestStall)
.map(manufacturer -> bestStallPair(manufacturer))
// Remove manufacturers that have no best stall
.filter(p -> p.stallName != null)
// Accumulate all Pairs to a map
.collect(Collectors.toMap(p -> p.manufacturerName, p -> p.stallName));
}
private Pair bestStallPair(String manufacturer) {
String bestStall = stalls.stream()
// Grab a stream of all candidates for this manufacturer
.filter(stall -> !parasiteStalls.contains(stall) && stall.manufacturer.equals(manufacturer))
// Choose the best one
.sorted() // Note that .sorted() requires my custom implementation
.findFirst() // of compareTo(:) in the Stall class!
// Save its name...
.map(stall -> stall.name)
// ... or null if it doesn't exist.
.orElse(null);
return new Pair(manufacturer, bestStall);
}
private static class Stall implements Comparable<Stall> {
String name, manufacturer;
float averageEggs, foodQuantity;
public Stall(String name, float averageEggs, float foodQuantity, String manufacturer) {
this.name = name;
this.averageEggs = averageEggs;
this.foodQuantity = foodQuantity;
this.manufacturer = manufacturer;
}
public Stall(String name) {
this.name = name;
this.averageEggs = 0;
this.foodQuantity = 0;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Stall))
return false;
// Two objects are "identical" if their name is the same!
return name.equals(((Stall) obj).name);
}
@Override
public int hashCode() {
// Two objects are "identical" if their name is the same!
return Objects.hash(name);
}
@Override
public int compareTo(Stall o) {
// Sort in decreasing efficiency
return Float.compare(o.averageEggs / o.foodQuantity, this.averageEggs / this.foodQuantity);
}
}
private static class Pair {
String stallName, manufacturerName;
public Pair(String manufacturerName, String stallName) {
this.stallName = stallName;
this.manufacturerName = manufacturerName;
}
}
}Good Classes
IntStream (for 1,2,3,...)
Collectors (for collecting)
Collections (sort, min, max)
Best of luck for your exams!
Advanced JavaTipps & Tricks
By Finlay Fehlauer
Advanced JavaTipps & Tricks
- 71