anitsh / til

Today I Learn (til) - Github `Issues` used as daily learning management system for taking notes and storing resource links.
https://anitshrestha.com.np
MIT License
77 stars 11 forks source link

Java Programming #210

Open anitsh opened 4 years ago

anitsh commented 4 years ago

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:

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 { 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

anitsh commented 4 years ago

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:

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:

2D Array image

3D Array image

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
anitsh commented 4 years ago

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

Unary Operators

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

anitsh commented 4 years ago

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"
anitsh commented 4 years ago

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.

image

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:

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.

anitsh commented 4 years ago

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.

anitsh commented 4 years ago

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.

image

// 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, the parseFloat() method is more direct than the valueOf().

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.

anitsh commented 4 years ago

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:

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:

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.

anitsh commented 4 years ago

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:

https://docs.oracle.com/javase/tutorial/java/generics/index.html

anitsh commented 4 years ago

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:

image

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.

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:

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).

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:

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.

image

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:

The operations that SortedSet inherits from Set behave identically on sorted sets and normal sets with two exceptions:

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:

The operations SortedMap inherits from Map behave identically on sorted maps and normal maps with two exceptions:

anitsh commented 4 years ago

Exception Handling

Algorithms

https://docs.oracle.com/javase/tutorial/collections/algorithms/index.html

anitsh commented 4 years ago

Java8 Streams https://faisalmorensya.dev/java-8-stream-foreach-filter-map-and-reduce

anitsh commented 4 years ago

https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

anitsh commented 3 years ago

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
    }
}