Java
Javadoc
Reference a method
{@link Class#method()}
If you get Symbol ... is inaccessible from here
in Intellij, check intellij note
Get size/length
- String : length()
- Collections : size()
- Map : size()
- Array : length
Collections / Map
To have the map with the order of presence in the list when grouping
list.stream().collect(Collectors.groupingBy(Object::getKey, LinkedHashMap::new, Collectors.toList()));
add element into ArrayList in HashMap
Map<String, List<Item>> items = new HashMap<>();
items.computeIfAbsent(key, k -> new ArrayList<>()).add(item);
ArrayList vs LinkedList
- Internal Implementation
- ArrayList internally uses a dynamic array to store its elements.
- LinkedList uses Doubly Linked List to store its elements.
- Manipulation
- ArrayList is slow as array manipulation is slower.
- LinkedList is faster being node based as not much bit shifting required.
- Implementation
- ArrayList implements only List.
- LinkedList implements List as well as Queue. It can act as a queue as well.
- Access
- ArrayList is faster in storing and accessing data.
- LinkedList is faster in manipulation of data.
String
Concatenation
Java does string concatenation using StringBuilder by default for simple cases (checkout the bytecode using javap -c
).
String a = b + c + d;
is converted to String a = new StringBuilder(b).append(c).append(d).toString();
String.format
with same value multiple times
String s = "%s %1$s %1$s".
String.format(s, "hello");
Move one element to first place in a map
Map<String, String> copy = new LinkedHashMap<>(origin);
origin.keySet().retainAll(Collections.singleton(value));
origin.putAll(copy);
Date handling
Transform a time in string without time zone info to epoch
String aDate = "2024-04-30 15:00:00";
LocalDateTime.parse(aDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
LocalDateTime does not contain zone info, so it fits to parse this date in string. And then transform to Instant
with a zone.
Calculate difference between 2 instants
ChronoUnit.MINUTES.between(Instant.ofEpochMilli(123L), Instant.ofEpochMilli(Instant.now().toEpochMilli()));
Decimal format
private DecimalFormat decimalFormat = new DecimalFormat("#,###.00;-#,###.00", new DecimalFormatSymbols(Locale.US));
Without second parameter, it will use os locale and will cause potential pb, for ex still convert 12.00 to 12,00 if os has french region
windows os -> settings -> TIme&Language -> region -> regional format
String.format(Locale.US, "%,.3f", number)
Type erasure
To understand why primitive data types cannot be used to generics, let's remember that generics are a compile-time feature, meaning the type parameter is erased and all generic types are implemented as type Object. Therefore, type parameters must be convertible to Object. Since primitive types don't extend Object, we can't use them as type parameters.
Logging
log.isDebugEnabled()
It's used just for performance reasons. log.debug(...)
statement won't be evaluated (especially for +
operator).
If you use SLF4J
, you can avoid the log.isDebugEnabled()
call, by using messaging formatting.
logger.debug("The entry is {}", entry);
The message formatting will not be evaluated unless debug is enabled.
Test util
Test private method
Ex : Object returnValue = executeMethod(getMethod(TestClass.class, "methodName", RequestParam.class), testClass, requestParam)
private static Object executeMethod(Method method, Object obj, Object... params) throws InvocationTargetException, IllegalAccessException {
method.setAccessible(true);
return method.invoke(obj, params)
}
private static Method getMethod(Class<?>... clazz, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
return clazz.getDeclaredMethod(methodName, parameterTypes);
}
Dynamically get/set field
@SneakyThrows
public static <T> T get(String fieldName, Object instance, Class<?> instanceClass) {
return (T) instanceClass.getDeclaredField(fieldName).get(instance);
}
@SneakyThrows
public static <T> void set(String fieldName, Object instance, T value) {
Field field = instance.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(instance, value);
}