til
til copied to clipboard
Java Programming
Objective: Understand Java Basics
A high-level programming language used to create complete applications that may run on a single computer or be distributed among servers and clients in a network. This key competency includes using common language features in Java, class hierarchies, design patterns, among others.
Key Competencies:
- Use common language features - Java comes with a clean and simple syntax, object-oriented language, is platform-independent, robust, distributed, portable, and risk known for high performance. This key competency helps explore the common features of Java.
- Class Hierarchies - Explore the hierarchical structure of Java. Java provides a universal superclass called Object that is defined to be the root of the entire class hierarchy. Every class that is defined in a Java program implicitly extends the class Object.
- Multiple classes - A Java program may contain any number of classes. Explore the different kinds of classes in Java. There are five kinds of classes: package-level, nested top-level, member, local, or anonymous.
- Common design patterns - In the context of Java, design patterns are divided into three categories – creational, structural, and behavioral patterns. Understand the usage of design patterns, their applications, and more.
Concepts
It is recommended to understand "Object Oriented"](https://github.com/codeanit/til/issues/212) before going through Java basics as the language is primarily build based on that concept.
The primitive types are defined to be the same on all machines and in all implementations, and are various sizes of two's-complement integers, IEEE 754 floating-point numbers, a boolean type, and a Unicode character char type. Values of the primitive types do not share state.
Reference types are the class types, the interface types, and the array types. The reference types are implemented by dynamically created objects that are either instances of classes or arrays. Many references to each object can exist. All objects (including arrays) support the methods of the class Object, which is the (single) root of the class hierarchy. A predefined String class supports Unicode character strings. Classes exist for wrapping primitive values inside of objects. In many cases, wrapping and unwrapping is performed automatically by the compiler (in which case, wrapping is called boxing, and unwrapping is called unboxing). Classes and interfaces may be generic, that is, they may be parameterized by reference types. Parameterized types of such classes and interfaces may then be invoked with specific type arguments.
Variables are typed storage locations. A variable of a primitive type holds a value of that exact primitive type. A variable of a class type can hold a null reference or a reference to an object that is an instance of the named class or any subclass of that class. A variable of an interface type can hold a null reference or a reference to an instance of any class that implements the named interface. A variable of an array type can hold a null reference or a reference to an array. A variable of class type Object can hold a null reference or a reference to any object, whether class instance or array.
Iterator Inteface
An iterator over a collection. Iterator takes the place of Enumeration in the Java Collections Framework. Iterators differ from enumerations in two ways:
- Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
- Method names have been improved.
Object Ordering, Comparable and Comparators
Comparable implementations provide a natural ordering for a class, which allows objects of that class to be sorted automatically. The following table summarizes some of the more important Java platform classes that implement Comparable.
| Class | Natural Ordering |
|---|---|
| Byte | Signed numerical |
| Character | Unsigned numerical |
| Long | Signed numerical |
| Integer | Signed numerical |
| Short | Signed numerical |
| Double | Signed numerical |
| Float | Signed numerical |
| BigInteger | Signed numerical |
| BigDecimal | Signed numerical |
| Boolean | Boolean.FALSE < Boolean.TRUE |
| File | System-dependent lexicographic on path name |
| String | Lexicographic |
| Date | Chronological |
| CollationKey | Locale-specific lexicographic |
| Data Type | Size | Description |
|---|---|---|
| byte | 1 byte | Stores whole numbers from -128 to 127 |
| short | 2 bytes | Stores whole numbers from -32,768 to 32,767 |
| int | 4 bytes | Stores whole numbers from -2,147,483,648 to 2,147,483,647 |
| long | 8 bytes | Stores whole numbers from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
| float | 4 bytes | Stores fractional numbers. Sufficient for storing 6 to 7 decimal digits |
| double | 8 bytes | Stores fractional numbers. Sufficient for storing 15 decimal digits |
| boolean | 1 bit | Stores true or false values |
| char | 2 bytes | Stores a single character/letter or ASCII values |
What if you want to sort some objects in an order other than their natural ordering? Or what if you want to sort some objects that don't implement Comparable? To do either of these things, you'll need to provide a Comparator — an object that encapsulates an ordering. Like the Comparable interface, the Comparator interface consists of a single method.
public interface Comparator<T> { int compare(T o1, T o2); }
The compare method compares its two arguments, returning a negative integer, 0, or a positive integer depending on whether the first argument is less than, equal to, or greater than the second. If either of the arguments has an inappropriate type for the Comparator, the compare method throws a ClassCastException.
Much of what was said about Comparable applies to Comparator as well. Writing a compare method is nearly identical to writing a compareTo method, except that the former gets both objects passed in as arguments. The compare method has to obey the same four technical restrictions as Comparable's compareTo method for the same reason — a Comparator must induce a total order on the objects it compares.
Autoboxing, Unboxing
Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes. For example, converting an int to an Integer, a double to a Double, and so on. If the conversion goes the other way, this is called Unboxing.
Example from primitive to object conversion of integer type: https://mkyong.com/Java/java-convert-int-to-integer-example
Resource
- https://introcs.cs.princeton.edu/java/11cheatsheet
- https://google.github.io/styleguide/javaguide.html
- https://trello.com/c/pkMvOBLq/727-must-know-for-java-dev
- https://introcs.cs.princeton.edu/java
- https://docs.oracle.com/javase/tutorial/java
- https://docs.oracle.com/javase/tutorial/tutorialLearningPaths.html
- https://www.informit.com/articles/article.aspx?p=2180072
- https://github.com/google/error-prone
Variables
A data type is a set of values and a set of operations defined on those values. The primitive data types that you have been using are supplemented in Java by extensive libraries of reference types that are tailored for a large variety of applications
The Java programming language uses both "fields" and "variables" as part of its terminology. Instance variables (non-static fields) are unique to each instance of a class. Class variables (static fields) are fields declared with the static modifier; there is exactly one copy of a class variable, regardless of how many times the class has been instantiated. Local variables store temporary state inside a method. Parameters are variables that provide extra information to a method; both local variables and parameters are always classified as "variables" (not "fields"). When naming your fields or variables, there are rules and conventions that you should (or must) follow.
The Java programming language defines the following kinds of variables:
- Instance Variables (Non-Static Fields) Technically speaking, objects store their individual states in "non-static fields", that is, fields declared without the
statickeyword. Non-static fields are also known as instance variables because their values are unique to each instance of a class (to each object, in other words); the currentSpeed of one bicycle is independent from the currentSpeed of another. - Class Variables (Static Fields) A class variable is any field declared with the static modifier; this tells the compiler that there is exactly one copy of this variable in existence, regardless of how many times the class has been instantiated. A field defining the number of gears for a particular kind of bicycle could be marked as static since conceptually the same number of gears will apply to all instances. The code static int numGears = 6; would create such a static field. Additionally, the keyword final could be added to indicate that the number of gears will never change.
- Local Variables Similar to how an object stores its state in fields, a method will often store its temporary state in local variables. The syntax for declaring a local variable is similar to declaring a field (for example, int count = 0;). There is no special keyword designating a variable as local; that determination comes entirely from the location in which the variable is declared — which is between the opening and closing braces of a method. As such, local variables are only visible to the methods in which they are declared; they are not accessible from the rest of the class.
- Parameters You've already seen examples of parameters, both in the Bicycle class and in the main method of the "Hello World!" application. Recall that the signature for the main method is public static void main(String[] args). Here, the args variable is the parameter to this method. The important thing to remember is that parameters are always classified as "variables" not "fields". This applies to other parameter-accepting constructs as well (such as constructors and exception handlers) that you'll learn about later in the tutorial.
The Java programming language is statically-typed, which means that all variables must first be declared before they can be used. This involves stating the variable's type and name.
int gear = 1; //This tells program that a field named "gear" exists, holds numerical data, and has an initial value of "1"
A primitive type is predefined by the language and is named by a reserved keyword. Primitive types are special data types built into the language; they are not objects created from a class. The new keyword isn't used when initializing a variable of a primitive type. Primitive values do not share state with other primitive values. The eight primitive data types are: byte, short, int, long, float, double, boolean, and char. The java.lang.String class represents character strings. The compiler will assign a reasonable default value for fields of the above types; for local variables, a default value is never assigned. float and double data types should never be used for precise values, such as currency, the java.math.BigDecimal class should be used instead.
Literals
A literal is the source code representation of a fixed value; literals are represented directly in your code without requiring computation. Binary, Decimal, and Hexadecimal systems are represented in source code. As shown below, it's possible to assign a literal to a variable of a primitive type:
boolean result = true;
char capitalC = 'C';
byte b = 100;
short s = 10000;
int i = 100000;
In addition to the eight primitive data types listed above, the Java programming language also provides special support for character strings via the java.lang.String class. Enclosing your character string within double quotes will automatically create a new String object; for example, String s = "this is a string";. String objects are immutable, which means that once created, their values cannot be changed. The String class is not technically a primitive data type, but considering the special support given to it by the language, you'll probably tend to think of it as such.
Array
An array is a container object that holds a fixed number of values of a single type. The length of an array is established when the array is created. After creation, its length is fixed. Multidimensional array(or array of arrays) can also be declared.
// Declares an array of primitive data types
int[] anArrayOfIntegers;
byte[] anArrayOfBytes;
short[] anArrayOfShorts;
long[] anArrayOfLongs;
float[] anArrayOfFloats;
double[] anArrayOfDoubles;
boolean[] anArrayOfBooleans;
char[] anArrayOfChars;
String[] anArrayOfStrings;
// Allocates memory for 10 integers
anArrayOfIntegers = new int[10];
// Alternate shortcut syntax to create and initialize an array of integers
int[] anArrayOfIntegers = {
100, 200, 300,
400, 500, 600,
700, 800, 900, 1000
};
// Multi-dimensional array of integers
int[][] multiDArrInt;
multiDArrInt = new int[3][3];
// Shortcut
int[][] multiDArrInt = {
{ 1, 2 ,3 },
{ 4, 5, 6 }
};
Java SE provides several methods for performing array manipulations (common tasks, such as copying, sorting and searching arrays) in the java.util.Arrays class. Some other useful operations provided by methods in the java.util.Arrays class, are:
- Searching an array for a specific value to get the index at which it is placed (the binarySearch method).
- Comparing two arrays to determine if they are equal or not (the equals method).
- Filling an array to place a specific value at each index (the fill method).
- Sorting an array into ascending order. This can be done either sequentially, using the sort method, or concurrently, using the
parallelSortmethod introduced in Java SE 8. Parallel sorting of large arrays on multiprocessor systems is faster than sequential array sorting.
2D Array

3D Array

An enum type is a special data type that enables for a variable to be a set of predefined constants.
Null Value
NULL means the variable references do have value. The value can be tested against NULL by equality operators. When we print the null value, it will print the null. In Java, null is case sensitive and it must be in all small letters as “null”.
public class Test
{
public static void main (String[] args) throws java.lang.Exception
{
System.out.println("Null is: " + null);
}
}
Null is: null
Operators
| Operators | Precedence |
|---|---|
| postfix | expr++ expr-- |
| unary | ++expr --expr +expr -expr ~ ! |
| multiplicative | * / % |
| additive | + - |
| shift | << >> >>> |
| relational | < > <= >= instanceof |
| equality | == != |
| bitwise AND | & |
| bitwise exclusive OR | ^ |
| bitwise inclusive OR | | |
| logical AND | && |
| logical OR | || |
| ternary | ? : |
| assignment | = += -= *= /= %= &= ^= |= <<= >>= >>>= |
Simple Assignment Operator
= Simple assignment operator
Arithmetic Operators
-
Additive operator (also used for String concatenation)
-
Subtraction operator
-
Multiplication operator
/ Division operator % Remainder operator
Unary Operators
-
Unary plus operator; indicates positive value (numbers are positive without this, however)
-
Unary minus operator; negates an expression
++ Increment operator; increments a value by 1 -- Decrement operator; decrements a value by 1 ! Logical complement operator; inverts the value of a boolean
Equality and Relational Operators
== Equal to != Not equal to
Greater than= Greater than or equal to < Less than <= Less than or equal to
Conditional Operators
&& Conditional-AND || Conditional-OR ?: Ternary (shorthand for if-then-else statement)
Type Comparison Operator
instanceof Compares an object to a specified type
Bitwise and Bit Shift Operators
~ Unary bitwise complement << Signed left shift
Signed right shift
Unsigned right shift & Bitwise AND ^ Bitwise exclusive OR | Bitwise inclusive OR
Control Flow Statements
The if-then statement is the most basic of all the control flow statements. It tells your program to execute a certain section of code only if a particular test evaluates to true. The if-then-else statement provides a secondary path of execution when an "if" clause evaluates to false. Unlike if-then and if-then-else, the switch statement allows for any number of possible execution paths. The while and do-while statements continually execute a block of statements while a particular condition is true. The difference between do-while and while is that do-while evaluates its expression at the bottom of the loop instead of the top. Therefore, the statements within the do block are always executed at least once. The for statement provides a compact way to iterate over a range of values. It has two forms, one of which was designed for looping through collections and arrays.
The break Statement
The break statement has two forms: labeled and unlabeled. Unlabeled break as used in switch statement in general but it can also be used to terminate a for, while, or do-while loop. An unlabeled break statement terminates the innermost switch, for, while, or do-while statement.
A labeled break terminates an outer statement. The break statement terminates the labeled statement; it does not transfer the flow of control to the label. Control flow is transferred to the statement immediately following the labeled (terminated) statement.
// Example of labeled `break` statement
class BreakWithLabelDemo {
public static void main(String[] args) {
int searchfor = 12; // Search int
int[][] arrayOfInts = {
{ 32, 87, 3, 589 },
{ 12, 1076, 2000, 8 },
{ 622, 127, 77, 955 }
};
int i;
int j = 0;
boolean foundIt = false;
search:
for (i = 0; i < arrayOfInts.length; i++) {
for (j = 0; j < arrayOfInts[i].length;
j++) {
if (arrayOfInts[i][j] == searchfor) {
foundIt = true;
break search; // Control flow goes to `if` statement
}
}
}
if (foundIt) {
System.out.println("Found " + searchfor + " at " + i + ", " + j);
} else {
System.out.println(searchfor + " not in the array");
}
}
}
// OUTPUT: Found 12 at 1, 0
The continue Statement
The continue statement skips the current iteration of a for, while , or do-while loop. The unlabeled form skips to the end of the innermost loop's body and evaluates the boolean expression that controls the loop, whereas a labeled continue statement skips the current iteration of an outer loop marked with the given label.
// The following example program, ContinueWithLabelDemo, uses nested loops to search for a substring within another string. Two nested loops are required: one to iterate over the substring and one to iterate over the string being searched. It uses the labeled form of continue to skip an iteration in the outer loop.
class ContinueWithLabelDemo {
public static void main(String[] args) {
String searchMe = "Look for a substring in me";
String substring = "sub";
boolean foundIt = false;
int max = searchMe.length() -
substring.length();
test:
for (int i = 0; i <= max; i++) {
int n = substring.length();
int j = i;
int k = 0;
while (n-- != 0) {
if (searchMe.charAt(j++) != substring.charAt(k++)) {
continue test;
}
}
foundIt = true;
break test;
}
System.out.println(foundIt ? "Found it" : "Didn't find it");
}
}
// OUTPUT: "Found it"
Number Class
There are, however, reasons to use objects in place of primitives, and the Java platform provides wrapper classes for each of the primitive data types. These classes "wrap" the primitive in an object. Often, the wrapping is done by the compiler—if you use a primitive where an object is expected, the compiler boxes the primitive in its wrapper class for you. Similarly, if you use a number object when a primitive is expected, the compiler unboxes the object.
The Number class and it's subclasses ( Byte, Integer, Double, Float, Long, and Short) that wrap primitive numeric types are provided by the java.lang package.

BigDecimal and BigInteger are used for high-precision calculations. AtomicInteger and AtomicLong are used for multi-threaded applications.
There are three reasons that you might use a Number object rather than a primitive:
- As an argument of a method that expects an object (often used when manipulating collections of numbers).
- To use constants defined by the class, such as MIN_VALUE and MAX_VALUE, that provide the upper and lower bounds of the data type.
- To use class methods for converting values to and from other primitive types, for converting to and from strings, and for converting between number systems (decimal, octal, hexadecimal, binary).
You use one of the wrapper classes – Byte, Double, Float, Integer, Long, or Short – to wrap a number of primitive type in an object. The Java compiler automatically wraps (boxes) primitives for you when necessary and unboxes them, again when necessary.
The Number classes include constants and useful class methods. The MIN_VALUE and MAX_VALUE constants contain the smallest and largest values that can be contained by an object of that type. The byteValue, shortValue, and similar methods convert one numeric type to another. The valueOf method converts a string to a number, and the toString method converts a number to a string.
To format a string containing numbers for output, you can use the printf() or format() methods in the PrintStream class. Alternatively, you can use the NumberFormat class to customize numerical formats using patterns.
Number subclasses includes a class method, toString(), that will convert its primitive type to a string.
The Math class contains a variety of class methods for performing mathematical functions, including exponential, logarithmic, and trigonometric methods. Math also includes basic arithmetic functions, such as absolute value and rounding, and a method, random(), for generating random numbers.
Characters
The Character class is immutable, so that once it is created, a Character object cannot be changed.
Most of the time, if you are using a single character value, you will use the primitive char type. For example:
char ch = 'a'; // Unicode for uppercase Greek omega character char uniChar = '\u03A9'; // an array of chars char[] charArray = { 'a', 'b', 'c', 'd', 'e' };
There are times, however, when you need to use a char as an object—for example, as a method argument where an object is expected. The Java programming language provides a wrapper class that "wraps" the char in a Character object for this purpose. An object of type Character contains a single field, whose type is char. This Character class also offers a number of useful class (i.e., static) methods for manipulating characters.
You can create a Character object with the Character constructor:
Character ch = new Character('a');
The Java compiler will also create a Character object for you under some circumstances. For example, if you pass a primitive char into a method that expects an object, the compiler automatically converts the char to a Character for you. This feature is called autoboxing or unboxing, if the conversion goes the other way.
Strings
Strings are a sequence of characters and are objects. String class to create and manipulate strings. The String class has over 60 methods and 13 constructors.

// String creation
String greeting = "Hello world!";
// or
char[] helloArray = { 'h', 'e', 'l', 'l', 'o', '.' };
String helloString = new String(helloArray);
Converting Strings to Numbers, and Opposite Each of the Number subclasses that wrap primitive numeric types also provides a
parseXXXX()method (for example,parseFloat()) that can be used to convert strings to primitive numbers. Since a primitive type is returned instead of an object, theparseFloat()method is more direct than thevalueOf().
StringBuilder Class
StringBuilder objects are like String objects, except that they can be modified. Internally, these objects are treated like variable-length arrays that contain a sequence of characters. At any point, the length and content of the sequence can be changed through method invocations. The principal operations on a StringBuilder that are not available in String are the append() and insert() methods, which are overloaded so as to accept data of any type. Other good function offered by StringBuilder is reverse().
In general, however, the String class has a wider variety of methods and Strings should always be used unless string builders offer an advantage in terms of simpler code or better performance. For example, if you need to concatenate a large number of strings, appending to a StringBuilder object is more efficient.
There is also a StringBuffer class that is exactly the same as the StringBuilder class, except that it is thread-safe by virtue of having its methods synchronized. Threads will be discussed in the lesson on concurrency.
A string can be converted to a string builder using a StringBuilder constructor. A string builder can be converted to a string with the toString() method.
Annotations
Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate. Annotations have a number of uses, among them:
- Information for the compiler — Annotations can be used by the compiler to detect errors or suppress warnings.
- Compile-time and deployment-time processing — Software tools can process annotation information to generate code, XML files, and so forth.
- Runtime processing — Some annotations are available to be examined at runtime.
Where Annotations Can Be Used Annotations can be applied to declarations: declarations of classes, fields, methods, and other program elements. When used on a declaration, each annotation often appears, by convention, on its own line. As of the Java SE 8 release, annotations can also be applied to the use of types. Here are some examples:
- Class instance creation expression:
new @Interned MyObject(); - Type cast:
myString = (@NonNull String) str; - implements clause:
class UnmodifiableList<T> implements @Readonly List<@Readonly T> {...} - Thrown exception declaration:
void monitorTemperature() throws @Critical TemperatureException {...}
To make the information in @ClassPreamble appear in Javadoc-generated documentation, you must annotate the @ClassPreamble definition with the @Documented annotation.
@Documented
@ClassPreamble (
author = "John Doe",
date = "3/17/2002",
currentRevision = 6,
lastModified = "4/12/2004",
lastModifiedBy = "Jane Doe",
// Note array notation
reviewers = {"Alice", "Bob", "Cindy"}
)
public class Generation3List extends Generation2List {...}
The predefined annotation types defined in java.lang are @Deprecated, @Override, and @SuppressWarnings.
Usage
Type annotations were created to support improved analysis of Java programs way of ensuring stronger type checking. The Java SE 8 release does not provide a type checking framework, but it allows you to write (or download) a type checking framework that is implemented as one or more pluggable modules that are used in conjunction with the Java compiler.
For example, you want to ensure that a particular variable in your program is never assigned to null; you want to avoid triggering a NullPointerException. You can write a custom plug-in to check for this. You would then modify your code to annotate that particular variable, indicating that it is never assigned to null. The variable declaration might look like this:
@NonNull String str;
When you compile the code, including the NonNull module at the command line, the compiler prints a warning if it detects a potential problem, allowing you to modify the code to avoid the error. After you correct the code to remove all warnings, this particular error will not occur when the program runs.
You can use multiple type-checking modules where each module checks for a different kind of error. In this way, you can build on top of the Java type system, adding specific checks when and where you want them.
With the judicious use of type annotations and the presence of pluggable type checkers, you can write code that is stronger and less prone to error.
In many cases, you do not have to write your own type checking modules. There are third parties who have done the work for you. For example, you might want to take advantage of the Checker Framework created by the University of Washington. This framework includes a NonNull module, as well as a regular expression module, and a mutex lock module. For more information, see the Checker Framework.
Generics
In any nontrivial software project, bugs are simply a fact of life. Careful planning, programming, and testing can help reduce their pervasiveness, but somehow, somewhere, they'll always find a way to creep into your code. This becomes especially apparent as new features are introduced and your code base grows in size and complexity.
Fortunately, some bugs are easier to detect than others. Compile-time bugs, for example, can be detected early on; you can use the compiler's error messages to figure out what the problem is and fix it, right then and there. Runtime bugs, however, can be much more problematic; they don't always surface immediately, and when they do, it may be at a point in the program that is far removed from the actual cause of the problem.
Generics add stability to your code by making more of your bugs detectable at compile time. Code that uses generics has many benefits over non-generic code:
-
Stronger type checks at compile time. A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.
-
Elimination of casts. The following code snippet without generics requires casting:
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
- When re-written to use generics, the code does not require casting:
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
- Enabling programmers to implement generic algorithms. By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.
https://docs.oracle.com/javase/tutorial/java/generics/index.html
Collections Framework
A collection — sometimes called a container — is simply an object that groups multiple elements into a single unit. Collections are used to store, retrieve, manipulate, and communicate aggregate data
A collections framework is a unified architecture for representing and manipulating collections. All collections frameworks contain the following:
Interfaces: These are abstract data types that represent collections. Interfaces allow collections to be manipulated independently of the details of their representation. In object-oriented languages, interfaces generally form a hierarchy.Implementations: These are the concrete implementations of the collection interfaces. In essence, they are reusable data structures.Algorithms: These are the methods that perform useful computations, such as searching and sorting, on objects that implement collection interfaces. The algorithms are said to be polymorphic: that is, the same method can be used on many different implementations of the appropriate collection interface. In essence, algorithms are reusable functionality.

The following list describes the core collection interfaces:
Collection
Collection is the root of the collection hierarchy. A collection represents a group of objects known as its elements. The Collection interface is the least common denominator that all collections implement and is used to pass collections around and to manipulate them when maximum generality is desired. Some types of collections allow duplicate elements, and others do not. Some are ordered and others are unordered. The Java platform doesn't provide any direct implementations of this interface but provides implementations of more specific subinterfaces, such as Set and List.
Set
Set is a collection that cannot contain duplicate elements. The Java platform contains three general-purpose Set implementations: HashSet, TreeSet, and LinkedHashSet.
- HashSet, which stores its elements in a hash table, is the best-performing implementation; however it makes no guarantees concerning the order of iteration.
- TreeSet, which stores its elements in a red-black tree, orders its elements based on their values; it is substantially slower than HashSet.
- LinkedHashSet, which is implemented as a hash table with a linked list running through it, orders its elements based on the order in which they were inserted into the set (insertion-order). It spares its clients from the unspecified, generally chaotic ordering provided by HashSet at a cost that is only slightly higher.
Collection<Type> noDups = new HashSet<Type>(c); // Remove duplicates from existing collection c.
List
List an ordered collection (sometimes called a sequence). Lists can contain duplicate elements. The user of a List generally has precise control over where in the list each element is inserted and can access elements by their integer index (position).
The List interface includes operations for the following:
Positional access- manipulates elements based on their numerical position in the list. This includes methods such as get, set, add, addAll, and remove.Search- searches for a specified object in the list and returns its numerical position. Search methods include indexOf and lastIndexOf.Iteration- extends Iterator semantics to take advantage of the list's sequential nature. The listIterator methods provide this behavior.Range-view- The sublist method performs arbitrary range operations on the list. The Java platform contains two general-purpose List implementations. ArrayList, which is usually the better-performing implementation, and LinkedList which offers better performance under certain circumstances.
Summary of algorithms applied in List sort — sorts a List using a merge sort algorithm, which provides a fast, stable sort. (A stable sort is one that does not reorder equal elements.) shuffle — randomly permutes the elements in a List. reverse — reverses the order of the elements in a List. rotate — rotates all the elements in a List by a specified distance. swap — swaps the elements at specified positions in a List. replaceAll — replaces all occurrences of one specified value with another. fill — overwrites every element in a List with the specified value. copy — copies the source List into the destination List. binarySearch — searches for an element in an ordered List using the binary search algorithm. indexOfSubList — returns the index of the first sublist of one List that is equal to another. lastIndexOfSubList — returns the index of the last sublist of one List that is equal to another.
Queue
Queue a collection used to hold multiple elements prior to processing. Besides basic Collection operations, a Queue provides additional insertion, extraction, and inspection operations.
| Type of Operation | Throws exception | Returns special value |
|---|---|---|
| Insert | add(e) | offer(e) |
| Remove | remove() | poll() |
| Examine | element() | peek() |
Deque
Usually pronounced as deck, a deque is a double-ended-queue. A double-ended-queue is a linear collection of elements that supports the insertion and removal of elements at both end points. The Deque interface is a richer abstract data type than both Stack and Queue because it implements both stacks and queues at the same time. The Deque interface, defines methods to access the elements at both ends of the Deque instance. Methods are provided to insert, remove, and examine the elements. Predefined classes like ArrayDeque and LinkedList implement the Deque interface. Note that the Deque interface can be used both as last-in-first-out stacks and first-in-first-out queues.
| Type of Operation | First Element (Beginning of the Deque instance) | Last Element (End of the Deque instance) |
|---|---|---|
| Insert | addFirst(e)offerFirst(e) | addLast(e)offerLast(e) |
| Remove | removeFirst()pollFirst() | removeLast()pollLast() |
| Examine | getFirst()peekFirst() | getLast()peekLast() |
Map
A Map is an object that maps keys to values. A map cannot contain duplicate keys: Each key can map to at most one value. It models the mathematical function abstraction. The Map interface includes methods for basic operations (such as put, get, remove, containsKey, containsValue, size, and empty), bulk operations (such as putAll and clear), and collection views (such as keySet, entrySet, and values).
- SortedSet — a Set that maintains its elements in ascending order. Several additional operations are provided to take advantage of the ordering. Sorted sets are used for naturally ordered sets, such as word lists and membership rolls.
- SortedMap — a Map that maintains its mappings in ascending key order. This is the Map analog of SortedSet. Sorted maps are used for naturally ordered collections of key/value pairs, such as dictionaries and telephone directories.
The Java platform contains three general-purpose Map implementations: HashMap, TreeMap, and LinkedHashMap. Their behavior and performance are precisely analogous to HashSet, TreeSet, and LinkedHashSet, as described in The Set Interface section. The Collection view methods allow a Map to be viewed as a Collection in these three ways:
keySet— the Set of keys contained in the Map.values— The Collection of values contained in the Map. This Collection is not a Set, because multiple keys can map to the same value.entrySet— the Set of key-value pairs contained in the Map. The Map interface provides a small nested interface called Map.Entry, the type of the elements in this Set.
The Collection views provide the only means to iterate over a Map. The basic operations of Map (put, get, containsKey, containsValue, size, and isEmpty) behave exactly like their counterparts in Hashtable.

SortedSet
A SortedSet is a Set that maintains its elements in ascending order, sorted according to the elements' natural ordering or according to a Comparator provided at SortedSet creation time. In addition to the normal Set operations, the SortedSet interface provides operations for the following:
- Range view — allows arbitrary range operations on the sorted set
- Endpoints — returns the first or last element in the sorted set
- Comparator access — returns the Comparator
The operations that SortedSet inherits from Set behave identically on sorted sets and normal sets with two exceptions:
- The Iterator returned by the iterator operation traverses the sorted set in order.
- The array returned by toArray contains the sorted set's elements in order. Although the interface doesn't guarantee it, the toString method of the Java platform's SortedSet implementations returns a string containing all the elements of the sorted set, in order.
SortedMap
A SortedMap is a Map that maintains its entries in ascending order, sorted according to the keys' natural ordering, or according to a Comparator provided at the time of the SortedMap creation. Natural ordering and Comparators are discussed in the Object Ordering section. The SortedMap interface provides operations for normal Map operations and for the following:
- Range view — performs arbitrary range operations on the sorted map
- Endpoints — returns the first or the last key in the sorted map
- Comparator access — returns the Comparator, if any, used to sort the map
The operations SortedMap inherits from Map behave identically on sorted maps and normal maps with two exceptions:
-
The Iterator returned by the iterator operation on any of the sorted map's Collection views traverse the collections in order.
-
The arrays returned by the Collection views' toArray operations contain the keys, values, or entries in order. Although it isn't guaranteed by the interface, the toString method of the Collection views in all the Java platform's SortedMap implementations returns a string containing all the elements of the view, in order.
-
https://docs.oracle.com/javase/tutorial/collections/index.html
-
https://docs.oracle.com/javase/tutorial/collections/custom-implementations/index.html
-
https://docs.oracle.com/javase/tutorial/collections/streams/index.html
Exception Handling
Algorithms
https://docs.oracle.com/javase/tutorial/collections/algorithms/index.html
Java8 Streams https://faisalmorensya.dev/java-8-stream-foreach-filter-map-and-reduce
https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
Inner Class
public class A {
private class B {}
public class C {}
public C getC() {
return new C();
}
public B getB() {
return new B();
}
}
public class Tryout {
public static void main(String[] args) {
A a = new A();
A.B b = a.getB(); //cannot compile
A.C c = a.getC(); //compiles perfectly
}
}
- [ ] https://stackoverflow.com/questions/6264657/why-make-private-inner-class-member-public-in-java