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
javadoc: If the mapped keys contains duplicates (according to
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
Use: map.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
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
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>
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
vs List
Arrays.asList(arr).contains(targetValue);
Arrays.binarySearch() returns ( - insertion_index - 1) in cases where the element was not found in the 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 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
javadoc: If 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
Use: map.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