Java Grammar

This post talks about the grammar of Java.

Data Types

Category of Type

  • Basic type: byte, short, int, long, boolean, float, double, char
    • cannot be set to null
    • use == to check equals
  • Reference type: class, (interface is also class)
    • can be set to null
    • use equals to check equals

Common Classes

  • Wrapper class
    • Boolean, Byte, Short, Integer, Long, Float, Double, Character
    • Wrap the basic type to reference type, could be set to null
      1
      2
      3
      int i = 3;
      Integer n = new Integer(i);
      int x = n.intValue();
  • String
    • is a class
    • the content cannot be changed, every modification returns new string object
    • “”.match could use regex
  • JavaBean
    • classes that obey the rule to use properties (getter, setter) to get access to private fields
      • field: private Type xyz
      • getter: public Type getXyz()
      • setter: public void setXyz()
  • Optional
    • Optional.isPresent() -> boolean
    • Optional.get() -> T
  • Regex
    1
    2
    3
    4
    5
    6
    7
    8
    import java.util.regex.*;

    Pattern pattern = Pattern.compile("xxxx");
    Matcher matcher = pattern.matcher("input string");
    matcher.matches(); // true of false
    matcher.group(0); // whole expression
    matcher.group(1); // first group substring
    matcher.find(); // find the next match

Anonymous Class

1
2
3
4
5
6
7
8
9
10
11
12
13
Runnable r = new Runnable() {
@Override
public void run() {
// ...
}
};

List array = new ArrayList() {
{
add(1);
add(2);
}
};

Lambda Expression

Lambda Expression is a coding style that supports Functional Programming, which treats functions as the units to operate.

It could replace the anonymous class which is for the FunctionalInterface (interface owning 1 single funciton).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Anonymous Class
Arrays.sort(array, new Comparator<String>() {
public int compare(String s1, String s2) {
return s1.compareTo(s2);
}
});

// Lambda Expression
Arrays.sort(array, (s1, s2) -> {
return s1.compareTo(s2);
});

// or
Arrays.sort(array, (s1, s2) -> s1.compareTo(s2));

Reflection (Class Instance)

Reflection could get the information of an object in runtime even know nothing about the specific types of the object.

  • When JVM loads a type of class, JVM creates one Class instance, which contains all the information of the type of class. e.g. class name, package name, base class, implemented interfaces, methods, fields
  • In the runtime, if we can get the Class instance, we could get the information of the binded class. This process is called reflection

Note. the Class is a class with name of Class

Get Class Instance

To get a Class instance, we could uses the following methods

1
2
3
4
5
6
7
8
9
// By static field of a class
Class cls = String.class; // String[].class

// By method of an object
String s = "Hello";
Class cls = s.getClass();

// By static method and the name of the class
Class cls = Class.forName("java.lang.String");

Usages of Class Instance (Reflection)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Class cls = T.class;

// Some common methods
cls.getName();
cls.getSimpleName();
cls.getPackage().getName();
cls.isInterface();
cls.isEnum();
cls.isArray();
cls.isPrimitive();
cls.getSuperclass();
cls.getInterfaces();

// Create new object without arguments
T obj = (T) cls.newInstance();
// Create new object with arguments
Constructor con = cls.getConstructor(Class);
T obj = (T) con.newInstance(xxx);

// Get fields
Field a = cls.getField(name);
Field b = cls.getDeclaredField(name);
a.get() // get value
a.set(obj, xxx) // set xxx to the field of the obj

// Get methods
Method a = cls.getMethod(name, Class...); // Class... is the Class
Method b = cls.getDeclaredMethod(name, Class...); // instance of arguments
T ans = (T) a.invoke(obj, xxx) // call the method a of obj with arguments

Annotation

Annotation is a special comment or mark for codes. It will be ignored by compiler but could be put into the .class file. It could do the following things.

  • (SOURCE) Let compiler check the code (not put into .class file)
    • e.g. @Override checks whether the father class has the same method
    • Help to generate document
  • (CLASS) Let tools to modify classes dynamically during class loading
  • (RUNTIME) Used in JVM runtime
    • for reflection (Require @Target(RUNTIME))

Common Used Annotation

Meta annotation: use to annotate other annotation

  • @Documented content appears in javadoc
  • @Inherited indicates that annotation could pass to the subclass of baseclass who is annotated by the annotation
  • @Target set the ElementType of an annotation (where to use)
    • values: TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE
    • Indicate what type(s) of content this annotion describes
    • Default: all types
  • @Rentention set the RententionPolicy of an annotation
    • values: SOURCE, CLASS, RUNTIME
    • Indicate which stage the compiler should keep this annotation
    • Default: RentionPolicy.CLASS
  • @Report indicates that annotation can be used several time in a place

Use to annotate codes

  • @Deprecated compiler throws warning if this function is used
  • @Override compiler throws error if base class doesn’t have the same function
  • @SuppressWarnings compiler keeps silent for specific warnings
  • @SafeVarargs Suppress warnings for all callers of a method or constructor
  • @FunctionalInterface Specifies that type declaration is intended to be a functional interface
  • @Repeatable Specifies that the annotation can be applied more than once to the same declaration
  • @Test JUnit run this function as a test case

Custom Annotation Definition

  • Type: declared by @interface (java.lang.annotation.Annotation)
  • Annotation Body: set parameters (method without arguments) and default values
  • Use other meta annotation to configure
    • @Target
    • @Retention
1
2
3
4
5
6
7
@Target(ELEmentType.TYPE)          // Means could annotate class, interface
@Rention(RententionPolicy.RUNTIME) // Means could be used at runtime
public @interface MyAnnotation { // This actual inherit the Annotation class
int type() default 0;
String value() default "";
String level() default "info";
}

Usages

Annotation is only a comment of codes, it should be used by other tools. e.g. SOURCE annotation is used by compiler, RUNTIME annotation is used by code.

In order to use the RUNTIME annotation, reflection is used to get the annotation.

1
2
3
4
// A: annotation type
Class cls = obj.getCLass();
MyAnnotation annotation = cls.getAnnotation(MyAnnotation.class);
// Use annotation.type(), annotation.value(), annotation level() to do something

Generics

Java uses Type Erasure to implement the generics, which means the compiler takes <T> as object, and do the cast type convertion for <T>

  • The template T cannot be the basic type
  • Cannot get the Class instance of a generic e.g. Pair<String>.class
  • Cannot initialize a T e.g. new T()
  • Subclass<T> can converts to Baseclass<T>
  • Type<Subclass> cannot converts to Type<Baseclass>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Pair<T> {
T first;
T last;

public Pair(T first, T last) {
this.first = first;
this.last = last;
}

// K and T is not the same meaning
public static <K> Pair<K> create(T first, T last) {
return new Pair<K>(first, last);
}
}

// Means the sumOfList function cannot use the add method of list
int sumOfList(List<? extends Integer> list) {...}

?, extends and super

For the arguments of a function, there could be 4 types of generics indicators

  • <T>: receive the T type
  • <?>: receive any types, but the arguments cannot be read or write, can only used for null check
    • can use as a variable
    • baseclass of any <T>
  • <? extends T>: arguments could be T or subclass of T, read-only
    • could use T get() to get reference of type T
    • couldn’t use set(T) to pass reference of type T, except null
  • <? super T>: arguments could be T or baseclass of T, write-only
    • couldn’t use T get() to get reference of type T, except Object
    • could use set(T) to pass reference of type T

PECS principle (Producer Extends Consumer Super)

  • Producer: return T, use <? extends T>
  • Consumer: receive T, use <? super T>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static <T> boolean isNull(Pair<T> p) {
return p.getFirst() == null || p.getLast() == null;
}

static boolean isNull(Pair<?> p) {
return p.getFirst() == null || p.getLast() == null;
}

Pair<Integer> p = new Pair<>(123, 456);
Pair<?> p2 = p;

// ? super T refers to write-only
// ? extends T refers to read-only
public class Collections {
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i=0; i<src.size(); i++) {
T t = src.get(i); // src is producer
dest.add(t); // dest is consumer
}
}
}

Collections

Abstract programming means we need to own the interface, but assign a specific class to it. e.g.

1
Queue<Integer> queue = new LinkedList<>();  // LinkedList<Integer>
  • Collection (interface)
    • List, AbstractList (interface)
      • ArrayList: implement with array
      • LinkedList: implement with linkedlist
      • Vector
    • Set, SortedSet (interface)
      • HashSet: no ordered
      • LinkedHashSet
      • TreeSet: sorted key
    • Queue (interface)
      • LinkedList
      • PriorityQueue: sorted the element
      • Dequeue: double ended queue
  • Map (interface)
    • AsbtractMap (interface)
      • HashMap
        • .keySet()
        • .entrySet(), .getKey(), .getValue()
      • LinkedHashMap
      • EnumMap: stores enum type key
      • HashTable
    • SortedMap (interface)
      • TreeMap: sorted the key with Comparable interface of key

Create and initilization for array and collections

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Array
dataType[] arrayRefVar = new dataType[arraySize];
dataType[] arrayRefVar = {value0, value1, ..., valuek};
dataType[] matrixVar = {
{value0, value1},
{value2, value3, value4}
};

// List
List<Integer> list = List.of(1, 2, 3); // read-only list
List<Integer> list = List.of(array);
List<Integer> list = Collections.emptyList()
List<Integer> list = new ArrayList<>(); // new ArrayList<Integer>()
list.add("XXX")

// Iteration. Below two method uses the most efficient way to iterate
for (Iterator<Integer> it = list.iterator(); it.hasNext(); ) {
Integer s = it.next();
// ...
}

for (Integer s : list) {
//...
}

Collections support generics, to use custom class in collections, following requirements should be met.

  • List
    • implements equals()
  • Map
    • implements equals() for key
    • implements hasCode()

IO

  • Byte Stream: byte by byte
    • InputStream (Abstract)
    • OutputStream (Abstract)
  • Character Stream: character by character
    • Reader (Abstract)
    • Writer (Abstract)

Stream

Stream is a data processing pipeline for collection elements. It uses a SQL-like grammar and lambda expression to make the processing code look tidy.

To use stream, first the elements needs to be transferred as stream elements, then be operated under intermediate operations, then be output by terminal operation.

Stream won’t store any middle data and won’t change the input data. It is lazy operation which means the stream will be triggered when the output data is used.

Create Stream

  • (Collections)object[].stream
  • Collections.stream(object[])
  • Stream.of(Object[])

Intermediate Operations

  • distinct
  • filter
  • map
  • flatmap: map + flatten, put the mapped elements into new stream
  • limit: get specific numbers of elements
  • peek: exectue another function for the elements of stream, but elements keep still
  • sorted
  • skip: drop the first n elements

Terminal Operations

  • Match
    • allMatch
    • anyMatch
    • noneMatch
  • count
  • max, min
  • collect
  • find
    • findAny
    • findFirst
  • forEach: execute another function for the elements of stream (like peek), but not guranteed the order of elements
  • forEachOrdered
  • reduce: reduce (sum, multiply, etc) all elements ant put in a new stream
  • toArray

Exception

Exception Classes

  • Throwable
    • Error
      • OutOfMemoryError
      • NoClassDefFoundError
      • StackOverflowError
    • Exception
      • “Checked Exception”, need to be catch in code
        • IOException
          • UnsupportedCharsetException
          • FileNotFoundException
          • SocketException
        • ParseException
        • GeneralSecurityException
        • SQLException
        • TimeoutException
        • “CustomException”
      • “Unchecked Exception”, RuntimeException, shouldn’t catch, fix code instead
        • NullPointerException
        • IndexOutOfBoundsException
        • SecurityException
        • IllegalArgumentException
          • NumberFormatException

Try Catch Snippet

1
2
3
4
5
6
7
8
9
try {
//...
} catch (AAException e) {
//...
} catch (BBException | CCException e) {
//...
} finally {
//...
}

Useful Function of Exception

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Different constructor
public class BaseException extends RuntimeException {
public BaseException() {
super();
}

public BaseException(String message, Throwable cause) {
super(message, cause);
}

public BaseException(String message) {
super(message);
}

public BaseException(Throwable cause) {
super(cause);
}
}

// Show calling stack
e.printStackTrace();

... catch (AAException e) {
// transfer exception but keep previous exception
throw new BBException(e);
}

// Show previous exception
e.getCause();

Assert

assert could use to determine whether a condition could meet. If it is not meet, terminate the program. Therefore, the assert could only be used in test phrase rather than real production.

assert needs to be enabled by passing a -enableassertions or -ea to JVM

Logging

Logging could log useful info when running code to a file or command line. It could replace using System.out.printline to debug.

  • Logging Implementation
    • JDK Logging: java.util.logging.Logger
    • Log4j: org.apache.logging.log4j.Logger
    • Logback
  • Logging Interface: could combine with one of the logging implementation
    • Commons Logging: org.apache.commons.logging.LogFactory
  • SLF4J

Log4j 2

  • JAR files: log4j-api-2.x, log4j-core-2.x
  • Packages: org.apache.logging.log4j.LogManager, org.apache.logging.log4j.Logger
  • Logging level: OFF < FATAL < ERROR < WARN < INFO < DEBUG < TRACE < ALL
    • Log4j2 could set the logging level, only information belonging to that level or the levels below that level could be logged

JVM

Arguments

  • -cp, -classpath: set the class path, don’t set the current class path
  • -ea, -enableassertions: enable assert function
  • -Dproperty=value: pass arguments

Import Packages

Java uses JVM to load classes from other packages. When running a class which imports other packages, JVM checks the existence of those packages according to classpath. The classpath could be passed to by using the argument -cp when executing JVM.

jar is a zip file containing a folder of packages, it could also be passed as a classpath. jar file could have a /META-INF/MANIFEST.MF file, where other dependencies and the Main-Class could be set. The jar file could be executed directly by JVM.

Maven is an good tool to manage the jar packages.