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>