Skip to main content

Immediate Java code quality-of-life improvers

· 3 min read

This is kind of like a "Top 10 libraries java developers should know" blog post, but more focused specifically on features (not just libraries) that could apply to any Java codebase. I find myself using these things in tiny personal Java projects as well as large, shared codebases. I primarily work in Java 8 and use IntelliJ. The credit for some of these go to my teammates. If you're a teammate and see this and would like credit, let me know!

Syntax

Lombok - no more IDE-generated code

Replaces many common generate-able code with small Java annotations. For example: Intellij generators (@Getter, @Setter, @AllArgsConstructor), removing method() throws CheckedException usage (@SneakyThrows), cleaning getLogger usage (@Slf4j)

Examples:

val complexMap = new HashMap<String, List<<Pair<String, String>>>>();

@Getter
@AllArgsConstructor
static class Pair {
String left, right;
}

firstNonNull

Tired of staring at ternary operators? Guava has a two-arg solution and Apache commons has a var-args soluion:

// Before
first != null ? first : second;
// After: Guava
MoreObjects.firstNonNull(first, second);
// After: Apache
ObjectUtils.firstNonNull(first, second, third);

Optional map() chaining for catching null in JSON

Typically used when going through JSON trees, you can catch nested nulls or empty lists like so:

JsonNode root = mapper.readTree(jsonString);
String result = Optional
.ofNullable(rootNode.get("users"))
.filter(users -> users.isArray() && !users.isEmpty())
.map(users -> users.iterator().next().get("address"))
.map(addr -> addr.get("city"))
.map(JsonNode::asText)
.orElse("user city was not found");

Intellij "Use static import for"

If you hit "Show Context Actions" (typically Alt+Enter or Option+Enter) over code like this, a "Use static import option" will typically show up for adding some readability:

Arrays.asList() --> asList()
Collections.singletonList() --> singletonList()
Collectors.toList() --> toList()

Lists / Maps

Guava Lists.partition() into equal sizes

Lists.partition(asList(1, 2, 3, 4, 5, 6, 7, 8), 3);
// returns [[1, 2, 3], [4, 5, 6], [7, 8]]

StreamEx - do .stream().map() on Map key values

The StreamEx library has many nice add-ons to Java Streams API but I found EntryStream especially useful:

// Make everything lowercase
map = EntryStream.of(map)
.mapKeys(String::toLowerCase)
.mapValues(String::toLowerCase)
.toMap();
// Map or remove keys at the same time
onlyEntriesInOtherMap = EntryStream.of(map)
.mapToKeyPartial((k, v) -> Optional.ofNullable(otherMap.get(k)))
.toMap();

Logging

Logback - set log level of libraries via environment variable

Being able to set individual log levels from the Java args is nice. It seems the alternatives of doing it dynamically in code, or via passing in different logback.xml files can be a larger headache.

This example will use the env var values from $ZK_LOG_LEVEl and $KAFKA_LOG_LEVEL and default to WARN if not set:

<logger name="org.apache.zookeeper" level="${ZK_LOG_LEVEL:-WARN}">
<appender-ref ref="FILE"/>
</logger>
<logger name="org.apache.kafka" level="${KAFKA_LOG_LEVEL:-WARN}">
<appender-ref ref="FILE"/>
</logger>