Java

Safely retrieve properties using Supplier and Optional in Java

Safely Retrieve Properties Using Supplier and Optional in Java

The supplier allows you to pass something but not retrieve it right away. One use case is retrieving a property an object that could throw a null pointer exception. By not retrieving right away, but instead using a supplier, the supplier can be later executed inside a try/catch block and handle any exceptions thrown.

public void example() {
    // Without supplier - could throw a nullpointer exception on any getter
    try {
        String str = someObject.getLevel1().getLevel2().getLevel3().getString();
        someOtherObject.appendValue(str);
    catch (Exception e) {
        // Exception throw - do nothing
        // This code is ugly!!!
    }

    // With supplier
    Optional<String> result = resolve() => someObject.getLevel1().getLevel2().getLevel3().getString());
    // Now we can do something if the property is present or skip if it doesn't exist
    // Much cleaner code
    result.ifPresent(someOtherObject::appendValue);
}


// This resolve method can be reused
protected <T> Optional<T> resolve(Supplier<T> supplier) {
    try {
        T result = resolver.get();
        return Optional.ofNullable(result);
    } catch (NullPointerException) {
        return Optional.empty();
    }
}

Function Composition in Java

Function Composition in Java

An incredible tool in Java is the ability to create functions and compose them.

One common use case is to extract a variable from an object and then transform it.

In the object oriented paradigm, you would have a method that extracts and another that transforms. Then intermediate variables would be used to convert from the initial object to the final transformed result.

With function composition this is greatly simplified. The separate steps can be defined as functions and then composed together to create the chain of events that need to occur. Then, the final composed function can be used instead of manually calling each method. See the examples below.

Convert String into LocalDate

Convert String Into LocalDate

Code


   public static LocalDate parseDate(String date) {
        DateTimeFormatter formatter =
                 DateTimeFormatter.ofPattern("M/d/y");
        return LocalDate.parse(date,formatter);
    }

Unit Tests

    @Test
    public void testDateParsing() {
        String testDate;
        testDate ="01/01/2022";
        LocalDate expected = LocalDate.of(2022, 1, 1);
        assertEquals(expected, DateParser.parseDate(testDate));
    }

    @Test
    public void testDateParsingSingleDigitMonthAndYear() {
        String testDate;
        testDate = "1/1/2022";
        LocalDate expected = LocalDate.of(2022, 1, 1);
        assertEquals(expected, DateParser.parseDate(testDate));
    }

Java Tip: Method Reference

Java Tip: Method Reference

Instead of

for(String name: names) {
	System.out.println(name);
}

Do

// This is called a method reference
names.foreach(System.out::println);

Java Tip: ComputeIfAbsent

Java Tip: ComputeIfAbsent

Often we have to loop through a list of items and convert it into a map, with the key being some sort of category and the value being a set of the associated items ie Map<Key, Set<Object>>. The old way of doing this looped through the list and before adding checked if the key was present. Using computeIfAbsent we can clean up this syntax considerably.

Instead of


// Map of item types to items
Map<String, Set<Items>> map = new HashMap<>();

for (Item item: items) {
    if (map.containsKey(item.getType())) {
        map.get(item.getType().add(item));
    } else {
        Set newSet = new HashSet<>();
        newSet.add(item);
        map.put(item.getType(), newSet));
    }
}

Do

// Map of item types to items
Map<String, Set<Items>> map = new HashMap<>();

for (Item item: items) {
    map.computeIfAbsent(item.getType(), v -> new HashSet<>()).
    add(item);
}