I haven't been playing around with Java for many years already. I initially learned Java when I was in my sophomore year and it was like 6 years ago. If I had continuously learned and used Java, I would have 6 years experience in programming in Java already.

Anyway, this post is a quick and concise recap on Java learning. The content excerpts from book: Learn Java in One Day and Learn It Well written by Jamie Chan. This post will not cover everything fundamental though, and one must have at least some prior programming experiences in order to grasp it well. The idea of this post is to brush up my Java programming skills too. So, let's get started!


What is Java?

Java is an object-oriented programming language developed by James Gosling at Sun Microsystems which later acquired by Oracle. It can be used to develop applications that run anywhere: desktop, web, mobile and etc. It is also platform independent as the program written in Java can be executed on any operating system (Windows, Mac or Linux).

How Java works?

Java compiles written code into Bytecode (platform independent) first, then JVM (Java Virtual Machine) converts it into machine code.

What is JDK?

JDK (Java Development Kit) is a free kit provided by Oracle that contains a number of tools to develop Java application, such as compiler that compiles code into bytecode (javac.exe), archiver (jar.exe), and documentation generator (javadoc.exe).

What are Primitive Data Types in Java?

NameTypeRangeMemory SpaceAdditional Note
ByteInteger-128 to 1271 byteUse if storage is concerned
ShortInteger-32768 to 327672 bytes
IntInteger-231 to 231 - 14 bytes- Most commonly used
LongInteger-263 to 263 - 18 bytes- Add suffix "L" at the end of number
FloatDecimal-3.402x1038 to 3.402x10384 bytes- Precision of 7 digits
- Add suffix "F" at the end of number
DoubleDecimal-1.797x10308 to 1.797x103088 bytes- Precision of 15 digits
- By default, a floating number will be converted to double, not float
- Use Double instead of Float if memory space is not a concerned
CharCharacter2 bytes- store single Unicode characters such as 'A', '%', '@' and etc.
BooleanBoolean1 byte- only true or false

How to name variables?

A variable name can only contain letters, numbers, underscore (_) or dollar sign ($).
NOTE: variable names are case sensitive!

  • Begin name with letters, not ($) or (_) (do not use ($) even if it is allowed)
  • First character cannot be number (restriction)
  • Camel-casing (ex: thisIsFun)

Something about initializing variables:

  • We need to add suffix L to the end of number if the number is too large, else we will get an error.
  • By default, number with decimals is treated as Double, unless specified F at the end of number to denote Float data type.
  • Char data type must be enclosed in single quote (')

Type casting in Java:

Convert smaller data type into a larger data type does not explicitly specify it.

short age = 10;
double longAge = age;

If we assign larger data type to a smaller one, we need to type cast it. For example, casting a double (8 bytes) into an int (4 bytes):

int x = (int) 20.9;

NOTE: one should avoid narrowing conversion as it will result loss of data and accuracy.

String:

  • String needs to be enclosed in double quotes (") not single quotes (').
  • Some useful String methods:
    • length()
      • "hello world".length()11
    • toUpperCase() / toLowerCase()
      • "hello world".toUpperCase()"HELLO WORLD"
    • substring()
      • "hello world".substring(6) - → "world"
      • "hello world".substring(1, 6)"ello "
    • charAt()
      • "hello world".charAt(1)'e'
    • equals()
      • "hello world".equals("Hello world")false
    • equalsIgnoreCase()
      • "hello world".equals("Hello world")true
    • split()
      • "hello world".split(" "){"hello", "world"}
  • More String methods at Oracle Documentation.

Array:

  • An array is a collection of data that are related to each other
  • Two ways to declare an array variable:
    • int[] userAge (preferred way)
    • int userAge[] (adopt from C/C++, not preferred in Java)
  • Need to import java.util.Arrays to use array predefined methods:
    • equals() - determine if two arrays are equal to each other
      • int[] arr1 = {0,2,4}
      • int[] arr2 = {0,2,4,6}
      • int[] arr3 = {0,4,2}
      • Arrays.equals(arr1, arr2)false
      • Arrays.equals(arr1, arr3)false
    • copyOfRange() - copy elements of one array into another
      • int[] arr4 = {1,2,3,4,5}
      • Arrays.copyOfRange(arr, 2,4){3,4}
    • toString() - return string representation of array
      • Arrays.toString(arr4)"[1,2,3,4,5]"
    • sort()
      • Arrays.sort(arr3){0,2,4}
    • binarySearch() - search for a specific value in a sorted array
      • Arrays.binarySearch(arr2, 2)1 (found at index 1)
      • Arrays.binarySearch(arr2, 3)-3 (negative means not found, 3 means the item should be at position 3-1 = 2
  • More Arrays methods at Oracle Documentation.

Primitive Type vs Reference Type

Primitive TypeReference Type
Store by valueStore by reference to data
- byte
- short
- int
- long
- float
- double
- char
- boolean
Everything other than primitive types:
- String
- Object

Displaying output:

  • Difference between System.out.println() and System.out.print() is that println() moves cursor down to next line after displaying the message while print() doesn't.
  • Escape sequence by using (\) in front of the escape character such as \n, \t, \\, \", and etc.
  • Format output using System.out.printf():
    • System.out.printf("The answer for %.3f divied by %d is %.2f", 5.45, 3, 5.45/3)The answer for 5.450 divided by 3 is 1.82
  • Format specifiers always begin with a percent sign (%) and end with a converter such as (f) or (d).
  • NOTE: we will get error if try to replace it with non-matching specifier! For example:
    • System.out.printf("%d", 12.9) → error!
    • System.out.printf("%f", 12) → error!
  • Newline converter (n) moves the cursor to next line:
    • System.out.printf("%d%n%d", 12 ,3)
      12
      3
  • Width flag specifies the total width:
    • System.out.printf("%8d", 12)______12 (6 spaces in front)
    • System.out.printf("%8.2f", 12.4)___12.40 (3 spaces in front)
  • Thousand separator flag specifies the number with separator:
    • System.out.printf("%,.2f", 12345.5678)12,345.57

Accepting User Input:

import java.util.Scanner;

public class Demo{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        System.out.print("Enter an integer: ");
        int myInt = input.nextInt();
        System.out.printf("You entered: %d.%n%n", myInt);
        System.out.printf("Enter a double: ");
        double myDouble = input.nextDouble();
        System.out.printf("You entered: %.2f.%n%n", myDouble);
        System.out.print("Enter a string: ");
        input.nextLine(); // consume nextline character since nextDouble() does not consume it
        String myString = input.nextLine();
        System.out.printf("You entered: \"%s.%n%n", myString);
    }
}


  • Each method expects to read in value of correct type. If user does not enter value of correct data type, the methods will try to convert it into correct one, otherwise an error will occur.
    • nextDouble(20) → convert 20 to double
    • nextDouble("hello") → error generated

Object Oriented Programming

  • Object-oriented programming is an approach to programming that breaks a programming problem into objects that interact with each other.
  • Object is created from blueprint/template known as Class.
  • Types of Modifier:
    • Public - accessed by any class in the program
    • Package-private (default) - accessible to other classes within same package
    • Private - accessible to all files in the same package
    • Protected - accessible within the class in which it is declared, any class that is derived from it and any class that is in the same package
  • Unlike variable naming (Camel-casing), class naming is Pascal-casing.
  • Method Overloading - two methods of same name with different signatures
  • Getter and Setter - allow other classes to access private fields
    • Why not make variable public? Using getter and setter gives us control over what rights other classes have when assessing these private fields
  • Constructor - use to create/instantiate a new object from class
    • Does not return any value
    • Set up constructor is optional as default one will be created for us automatically
  • Encapsulation - hide data and behavior from other class that do not need to know about them
    • Advantage: easier for us to change our code without affecting other classes
  • Inheritance - create new class from an existing class so that we can effectively reuse existing code
    • All classes in Java are inherited from a pre-written base class called Object class.
    • Derived class, also known as child class or subclass, inherits from the class from which they are derived from, also known as parent class, base class or superclass.
    • extends is used to indicate that one class is inherited from another class
    • When one class is inherited from another, it inherits all the public and protected fields and methods from parent class (no need to redeclare again).
    • When we write the child class constructor, we need to make it call parent class constructor first using super(), otherwise, Java will call the parameterless parent constructor for us.
    • Method Overriding - annotate @Override(case-sensitive) to override a method, it is optional but you are strongly encouraged to do so to prevent compilation error
  • Polymorphism - refer to a program's ability to use the correct method for an object based on its run-time type
    • To put it in layman's term, all the objects are declared to be a parent object type, the program knows which method to use based on the runtime type of the element.
  • **Abstract Class **- special type of class that is created strictly to be a base class for other classes to derive from
    • Abstract class cannot be instantiated
  • Abstract Method - method that have no body and must be implemented in derived class
    • Abstract method can only exist in abstract class
  • Interface - like abstract class, it cannot be instantiated.
    • It must be implemented by classes or extended by other interfaces.
    • When a class implements an interface, it has to implement all the abstract methods in that interface.
    • Interface can only contain abstract methods(methods with no bodies) and constants (fields declared as final)
    • All methods are implicitly public while all constant values are implicitly public, static and final.
    • No need to use abstract keyword as the method is abstract by default.
    • In Java 8, Java added support for default and static methods in interface. (binary compatibility - when interface is changed, no need to make any changes to the classes that implement it)
    • Key difference between abstract class and interface:
      • Class can only extend one abstract class, but can implement multiple interfaces
      • Interface can only contain abstract methods (up until Java 7) while an abstract class can contain non-abstract methods.

Collections:

  • Java Collections Framework is a set of pre-written classes and interfaces that Java provides for us to organize and manipulate groups of objects
  • Wrapper Classes - provide us with a convenient way to convert primitive types into objects and vice versa.
    • boolean (Boolean), char (Character), byte (Byte), short (Short), int (Integer), long (Long) and double (Double)
    • Integer intObj = new Integer(100);
    • int intVal = intObj.intValue();
  • Autoboxing - automatic conversion for int value to Integer constructor
    • Integer intObj = 100;
  • Unboxing - automatic conversion for Integer object to int value

ArrayList:

  • ArrayList is implemented as a resizable array (size increased dynamically when more elements are added)
  • When adding new element to the middle of the ArrayList, all elements after it have to be shifted.
  • Can only be used to store objects (ex: Integer not int), implements List interface
  • Need to import java.util.ArrayList
  • ArrayList<T> arrList = new ArrayList<>();
  • Can also do List<T> arrList = new ArrayList<>(); since List is the superinterface of ArrayList (polymorphism), but remember to import java.util.List.
  • ArrayList Methods:
    • add(num)
      • arrList.add(2) → insert 2 at the end of list
    • add(index, num)
      • arrList.add(2, 51) → insert 51 at index 2
    • set(index, num)
      • arrList.set(2, 49) → set index 2 value 49
    • remove(index)
      • arrList.remove(2) → item in index 2 is removed
    • get(index)
      • arrList.get(2) → retrieve element in index 2
    • size()
      • arrList.size()
    • contains(num)
      • arrList.contains(55)true (found) / false (not found)
    • indexOf(num)
      • arrList.indexOf(49) → return the first found index 2
      • arrList.indexOf(100) → get -1 (not found)
    • toArray()
      • Object[] myArr = arrList.toArray() (Object is the parent class of all classes)
      • Integer[] intArr = arrList.toArray(new Integer[0]) (we pass Integer array of size 0 to the toArray() method to return an Integer array)
    • clear()
      • arrList.clear() → remove all elements in the list
  • More ArrayList methods at Oracle Documentation.

LinkedList:

  • Similar to ArrayList (both implemented List), except no need to expand size or shift elements when adding or removing elements.
  • What is being changed or updated is the pointing address. For example, when an element is removed, the next pointer of previous element will point to the next element of current element and the next element of current element will have its previous pointer pointing to the element before current element.
  • LinkedList implements Queue and Deque interfaces in which LinkedList supportsmethods such as offer(), poll(), getFirst(), getLast() and etc.
  • Advantage:
    • good for add or remove element frequently (no shifting or expanding needed)
  • Disadvantage:
    • higher memory consumption as it needs to store addresses of previous and next elements
    • time-consuming to find a specific element as have to lookup at the first element in the list and follow the reference until you get that item.
  • Use methods from Queue or Deque interface:
    • declare variable as LinkedList type instead of List
    • LinkedList<Integer> myLinkedList = new LinkedList<>();
    • List<Integer> myLinkedList = new LinkedList<>(); (cannot use offer(), poll() and etc.)
  • LinkedList Methods:
    • Contains all methods from List, plus:
    • poll() - return the first element and remove it from the list
      • myLinkedList: 40→53→51→53
      • myLinkedList.poll()40 (return null if list is empty)
    • peek() - return the first element only
      • myLinkedList.peek()53 (return null if list is empty)
    • getFirst() - identical to peek(), except it gives NoSuchElementException when list is empty
    • getLast() - return last element, gives NoSUchElementException when list is empty
  • More LinkedList methods at Oracle Documentation.

File Handling:

  • Java provides us with a number of classes and methods to work with files.
  • Needs to import java.io.* to use classes like File, BufferedReader, FileReader, BufferedWriter, FileWriter and so on.
  • File Reader - read file as a stream of characters at one character at a time
    • More efficient to wrap BufferedReader around FileReader as BufferedReader reads larger block at a time instead of characters by characters.
    • BufferedReader reader = new BufferedReader(new FileReader("myFile.txt"));
    • Create while loop and read line by reader.readLine() until it returns null
    • Note: remember to escape \\ in filepath is not the same as directory
    • Normally wrap them in try catch finally execution block. Catch error when error occurs, and in finally block, the reader.close() is called to avoid memory leak
    • Newer method of reading a file (for Java 7 and above):
      • try-with-resources statement
      • `try(BufferedReader reader = new BufferedReader(new FileReader("myFile.txt")))
      • Do not need to explicitly close the reader object.
  • File Writer - similar to reading file, replace all Reader with Writer
    • writer.write(text) to write text and writer.newLine() to write new line
    • Overwrite a file by instantiating with false parameter - new FileWriter("myFile.txt", false) or simply without second parameter
    • Append a file by instantiating with true parameter - new FileWriter("myFile.txt", true)
  • Rename file by doing so:
    • File f = new File("myFile.txt");
    • File nf = new File("myNewFile.txt");
    • f.renameTo(nf);
    • nf.delete();

Generics:

  • Generics allow us to create classes (such as ArrayList), interfaces and methods in which the type of the data that they operate on is specified as a parameter in angle bracket.
  • class MyGenericsClass<T> where T is known as type parameter for specifying the type of data that the class will be operate on. (convention to use uppercase T to represent type parameter)
  • Advantage:
    • Allow us to create single class, interface, or method that automatically works with different types of data.
    • Allows for type-checking and specify which data type we want the object to work with:
      • MyGenericsClass<Integer> g = new MyGenericsClass();
      • g.setMyVar(10.2); → type incompatible error!
  • Generics does not work with primitive types!
public class GenericDemo{
    public static void main(String[] args){
        MyGenericsClass<T> g = new MyGenericsClass();
    }
}

class MyGenericsClass<T>{
    private T myVar;
    void setMyVar(T i){ myVar = i;}
    void printVar(){ System.out.println("The value of myVar is " + myVar);}
}
  • Bounded Types - limit the data type that can be passed to a type parameter by using extends clause
    • <T extends A> as T can only accept data types that are subtypes of A
    • <T extends Number> accepts numeric data types, such as Integer, Double and etc.

Functional Interfaces and Lambda Expressions:

  • An interface that contains one and only one abstract method.
  • It can contain other static and default methods, but there must be one and only one abstract method.
@FunctionalInterface
interface MyNumber{
    double getValue();
}
  • NOTE: no need to specify abstract as it is on by default.
  • Work along with lambda expression: (parameter list) -> lambda body
double getValue(){
    return 2 + 3;
}
// lambda expression
() -> 2 +3;

double getValue(){
    int cnt = 1;
    int sum = 0;
    while(cnt < 5){
        sum += cnt++;
    }
    return sum;
}
// lambda expression
() -> {
    int cnt = 1;
    int sum = 0;
    while(cnt < 5){
        sum += cnt++;
    }
    return sum;
};
  • To invoke these methods, we need to declare a reference to each of the functional interface by writing MyNumber num1; MyNumberParam num2;
@FunctionalInterface
interface MyNumber{
    double getValue();
}

@FunctionalInterface
interface MyNumberParam{
    double getValue2(int n, int m);
}

public static void main (String [] args){
    MyNumber num1;
    num1 = () -> 12.3;
    System.out.println("The value is " + num1.getValue());
    
    MyNumberParam num2;
    num2 = (n,m) -> {
        if(n > 10) return m;
        else return m + 1;
    }
    System.out.println("The value is " + num2.getValue(3,4));
}


That's all for now, hope this summary might be able brush up your Java skills. Adios, my friend!

Post was published on , last updated on .

Like the content? Support the author by paypal.me!