Java Tips, Tricks and Traps


Don'ts
Don't use array as Map's key
- Arrays inherit equals(Object) and hashCode() implementations from java.lang.Object, and they are based on object identity, not array contents
StringBuilder is mutable and does not override the equals(), hashcode(
- So don't use it as the map's key

Set initial size for dynamically expand objects like StringBuilder, ArrayList etc

Java Time API Use java.time.LocalDateTime/ZonedDateTime etc instead of old Date
Use DateTimeFormatter instead of SimpleDateFormate
- As these new classes are thread safe and easier to use.

yyyy-MM-dd, not YYYY-mm-dd ( YYYY is the week-based calendar year)

SimpleDateFormat
- is not threadsafe
- is by default lenient
Use ThreadLocal.
- Specify what time zone to use (usually utc), if not set explictly, it uses system default timezone

Explicitly set timezone to utc or specific time zone when use ZonedDateTime

Use ThreadLocalRandom
ThreadLocalRandom.current().nextInt(100)

Generics
public interface GenericClass <T> {
  T get();
  void set(T data);
}

public static <T> T getInstance(T data)
public static <E extends Comparable<E>> E method(E[] a)
public static <E extends Comparable<? super E>> E method(E[] a)
- compile-time construct
- type erasure
- can't create an object of parameter type!
  - new E() doesn't work
- use reflection to create instances of type parameters
-- Class<E> cls, cls.newInstance()
- can't use with instanceof
- can't create arrays of Parameterized Types
- new T[10] doesn't work
- Array contains type info at runtime

animalList = dogList doesn't work
List<Dog> is not a subclass of List<Animal>

animalArray = dogArray works
Array<Dog> is a subclass of Array<Animal>
- arrays knows its element type at runtime>

The Get and Put Principle
use an extends wildcard when you only get values out of a structure, use a super wildcard when you only put values into a structure, and don’t use a wildcard when you both get and put.


public static <T> void copy(List<? super T> dest, List<? extends T> src)
<T extends Comparable<? super T>> void sort(List<T> list)

YourEnum yourEnum = Enum.valueOf(YourEnum.class, value);
Use enum to implement singleton pattern

APIs
PriorityQueue maxPQ = new PriorityQueue(size,Collections.reverseOrder());

Collections
.sort(ar, Collections.reverseOrder(new XComparator()));
.min/max(collection, comp)

Arrays.asList(array)
- throw UnsupportedOperationException when try to add/remove elements from the returned list.

List arrayList = new ArrayList(Arrays.asList(arr));
vs List list = Arrays.asList(arr);

Arrays.asList(arr).contains(targetValue);

Arrays.binarySearch() returns ( - insertion_index - 1) in cases where the element was not found in the array


Arrays.sort(arr, Collections.reverseOrder()); Arrays.toString(array)
- syso(array), prints its address
Arrays.copyOfRange(a, 0, i)
Arrays.copyOf(original, newLength)

Arrays.fill(int[] a,int value) only works for one dimension array
-- it would fail with exception on 2-dimensions arrays - ArrayStoreException: java.lang.Integer

To fill 2-dimensions array:
int[][] target = new int[2][4];
int [] temp = new int[4];
Arrays.fill(temp, -1);
Arrays.fill(target, temp);

StringBuilder
StringBuilder/StringBuffer doesn't overwrite equals method. so different sb are different no matter what's the content.
.reverse()
.charAt(i)
.setCharAt(int, char)
.delete(start,end)
.deleteCharAt(i)
- No toCharArray()

String
char[] toCharArray()
- No reverse method

List
Keep only first n elements

list.subList(list.size() - N, list.size()).clear();

TreeSet
descendingIterator, descendingSet
first, last()
pollFirst, pollLast
lower(e), floor

headSet(e), tailSet, subSet
lower(e) - Return the greatest element in this set strictly less than the given element
floor(e) - Return the greatest element in this set less than or equal to the given element

ceiling(e) - Return the least element in this set greater than or equal to the given element
higher(e)  -  Returns the least element in this set strictly greater than the given element.
headSet/tailSet/subSet().size - O(n)

Code: java.util.TreeMap.NavigableSubMap.EntrySetView#size

clear
- O(1) for TreeMap/Set
- O(n) for ArrayList, LinkedList(it clear all elements and links)

TreeMap
- red-black tree
descendingMap
descendingKeySet
descendingKeyIterator
firstEntry, lastEntry
pollFirstEntry() and pollLastEntry()
headMap(), tailMap() and subMap()
ceilingKey(), floorKey(), higherKey() and lowerKey()
ceilingEntry(), floorEntry(), higherEntry() and lowerEntry()

Treest
- first, last
- Used when need dedup and make result sorted

You need to escape ' to '' in MessageFormat.
ArrayList 
- Cache friendly
- Compact - use less space than LinkedList(double cycle linked list)

HashMap
- implement hashcode and equals for the key
LinkedHashMap
- getHead: entrySet().iterator().next()
- getTail: O(n) while (iterator.hasNext()) { lastElement = iterator.next() }
Use apache LinkedMap which provides lastKey


Handle your special cases just once

Use ListIterator for ArrayList/LinkedList

Use Optional
- throw exception may be not good, as it forces client either handle it otherwise blown up
- return null is even worse
Optional.ofNullable(xyz).ifPresent(consumer);
Using Optional to avoid null checks
Optional.of(new Outer()).map(Outer::getNested).map(Nested::getInner).map(Inner::getFoo).ifPresent(System.out::println);

InterruptedException, isInterrupted
- indication to a thread
- common for the thread to terminate.
Usually Throws InterruptedException when interrupted
Thread.sleep(4000);
thread.join()
- if a thread goes a long time without invoking a method that throws InterruptedException, we can call Thread.interrupted to check whether an interrupt has been received.
if (Thread.interrupted()) {
       throw new InterruptedException();
}
while (!Thread.interrupted()) {}

catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    throw new DifferentException(e);

}

Coding
Group zero denotes the entire pattern
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(text);
if (m.find()) {
   m.group(0);
   m.group(1);

}

Bytes to string
String s = new String(bytes);
Not String.value(bytes) - this will return the address of the bytes.
- it calls String.value(Object o) method which calls object.toString(). byte[] toString() is the address.

Pass List to varargs parameter
list.toArray(new SomeType[list.size()])
Vararg gotchas
passing an array of primitives
Varargs only works with reference types. Autoboxing does not apply to array of primitives.
ezFormat(new int[]{1}) // not work 

passing null
count(null); // throws java.lang.NullPointerException!!!
count(new Object[] { null }); 
count((Object) null);
adding extra arguments

ezFormat({"A"}, "Z") 

Javadoc
Overwrite javadoc inherited from base class
- Need put @Override after javadoc, otherwise it doesn't work
- {@inheritDoc} to include javadoc from base class
There is no / at the end of tags.
- The javadoc starts with double *: /** - NOT /*

NPE safe
org.apache.commons.lang3.ObjectUtils.compare


Regex
http://www.regexplanet.com/advanced/java/index.html
matches vs find
- matches tries to match the expression against the entire string and implicitly add a ^ at the start and $ at the end of your pattern.
.*? - non greedy match
Named capturing group
(? ...)
matcher.group("size")


Misc
throw new UnsupportedOperationException(getClass().getSimpleName());

Traps/Bugs
Boolean.valueOf never returns null
- Use BooleanUtils.toBooleanObject instead.
hashCode method may return negative value
Math.abs may return negative value

x/y and x%y rounds to 0
1/3 => 0; -1/3 => 0
Use Math.floorDiv(-1, 3) which will return -1
Collections.contains(Object o)
Same for Map.containsKey(Object o)
Example
SecurityContextHolder.getContext().getAuthentication().getAuthorities().contains(ADMIN_GROUP)
// always false as the collection is Collection
Findbugs/Netbeans can show warnings, Eclipse can't.

obj::method != obj::method
Don't use method reference in add/remove related methods.

Collectors.toMap IllegalStateException: Duplicate key
javadocIf the mapped keys contains duplicates (according to Object.equals(Object)), an IllegalStateException is thrown when the collection operation is performed. If the mapped keys may have duplicates, use toMap(Function, Function, BinaryOperator) instead.

Overload vs Override
- Overload is determined at compile type, override is determined at runtime.
- Polymorphism applies to overriding, not to overloading.
- Overriding is a run-time concept while overloading is a compile-time concept.


Ternary expression is more complex than if/else - jls jls2
If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion to T, then the type of the conditional expression is T.

Integer a = check? 0 : someMethodWhichMayReturnNull()
This will cause NPE when check is false
over- or underflow
Off-by-one bugs
NPE
use == , maybe should use equals

map.getOrDefault(key, 0L)++ doesn't work
Usemap.put(key, 1 + map.getOrDefault(key, 0L));

equals usually check whether type are same
Long l = 0L;
Integer i = 0;
l.equals(i), i.equals(l) // both are false

int mid = low + ((high - low) / 2);
(-10) mod 3 = (3*4 – 10) mod 3 = 2
>> (Signed right shift)

>>> (Unsigned right shift)

JUnit throws AssertionError.
Java would still execute finally even if the block throws Error.

Related
Using Java 8

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)