Study Guide 2023+

java

Warning: These notes are partial, ongoing, incomplete, and may contain typos/inaccuracies. (They are kept factually accurate, time permitting.)

They are being united from many disparate notes created in the past and the layout/organization will gradually improve with time!

Please view them on a computer as they are not optimized for mobile (although you can still view them on Mobile along with the Flashcards at your own risk)!

Topics and code examples are lazy-loaded and may require two-clicks from the TOC to correctly calculate the updated x,y coordinates (after rendering). Thanks!

Java: General Concepts

  1. Java Virtual Machine - run Java on any machine or underlying environment.
    • Abstracts the Java runtime environment so Java can be executed uniformly anywhere.
  2. Java Heap, Stack, and Garbage Collecting
    • Heap - shared memory allocated for use by the JVM and applications running within it.
    • Garbage Collecting - the automatic or manually configured/triggered periodic removal of items in memory.
  3. Write Time, Compile Time, and Runtime
    • Checked Exceptions and Static methods are handled/checked at Write Time, Compile Time
    • Unchecked Exceptions and Non-Static methods are handled/created/checked at Runtime
  4. .java files, compiled Byte Code, and .class files
  5. Impure Object Oriented Design - Primitive Data Types don't inherit from the top-level Object Class.
  6. Reference Types - wrappers for the Primitive Data Types that inherit from the Object Class and therefore can take null values, .stringify(), etc.
  7. Statically Typed - Types are strictly enforced in Parameters, Arguments, Method Signatures, return Types. Limited Auto-boxing.

Top Java 8 Features

  1. Lambdas and Functional Interfaces
  2. CompletableFuture
  3. Stream API

Top Features Since Java 8

  1. sealed keyword
  2. Records
  3. Virtual Threads
  4. Better Heap and JVM memory management.

Java: Comparisons

  1. Primitive Comparison (==) - used to compare the equivalence of two Primitive Data Types.
    • Referential comparison.
  2. Object Comparison (equals()) - used to compare the equivalence of two Objects.
    • Compares by Value and Reference (although this is sometimes overridden - e.g. with Strings).
String a = "abc";
String b = "abc";

(a == b); //true - both point to the same reference
a.equals(b); //true - both are the same object values and reference (since the Strings point to the same).

Type Checking

Applies to descendants of the Object Class:

Person p = new Person();
System.out.println(p instanceof Person); // true

Comparators

Recall that comparisons typically return:

  1. -1 - some A shoud precede some B
  2. 0 - there's no reason for A not to precede some B
  3. 1 - some B should precede some A

In the example below, a Comparator is implemented as a Lambda to sort Products per the following:

  1. Sort by Availability (boolean) descending
  2. If tied, sort by DiscountedPrice (Double) ascending
  3. If still tied, sort by Id (Long) ascending
List<Product> products = new ArrayList<Product>();

products.sort((a, b) -> {
    boolean A = a.getAvailability();
    boolean B = b.getAvailability();
    if (A && !B) return -1;
    if (B && !A) return 1;

    Double AA = a.getDiscountedPrice();
    Double BB = b.getDiscountedPrice();
    if (AA < BB) return -1;
    else if (BB < AA) return 1;

    Long AAA = a.getId();
    Long BBB = b.getId();
    if (AAA < BBB) return -1;
    else if (BBB < AAA) return 1;
    return 0;
});

Operator Order of Precedence

In order of greatest precedence from top to bottom:

  1. Parentheses: (, )
  2. Arithmetic: +, -
  3. Not: !
  4. Comparison (Relational) Operators: <, >, <=, >=
  5. Equality: ==, !=
  6. Logical: &&, ||

Many sites omit some of the above or are inaccurate: https://examples.javacodegeeks.com/java-operator-precedence-example/

  1. https://examples.javacodegeeks.com/java-operator-precedence-example/

Java: References

  1. Shallow Copying in Java: set a value without using the new keyword for anything that's not a Primitive Data Type.
  2. While Java supports Referential Comparison (and/or Comparison by Value), Java has no concept like Pass by Reference (unlike JavaScript) but there are still some quirks.

Pass by Reference(-ish)

Given:

class ReferenceTest {
    int num;

    ReferenceTest(int x) {
        num = x;
    }

    ReferenceTest() {
        num = 0;
    }
}

public class ReferenceExamples {

    // Remember that Java scope can run counter-intuitively against the expected value.
    public static void examples() {
        ReferenceTest rt = new ReferenceTest(20);
        updateNewReference(rt);
        System.out.println("I'm the outer scope: " + rt.num); // 20 - returns the supplied value above, not 50
        update(rt);
    }

    public static void updateNewReference(ReferenceTest rt) {
        // Restricted by scope, the new value is set within update()
        rt = new ReferenceTest();
        rt.num = 50;
        System.out.println("I'm the inner scope - new reference: " + rt.num);
    }

    public static void update(ReferenceTest rt) {
        rt.num = 50;
        System.out.println("I'm the inner scope - same reference: " + rt.num);
    }
}

Calling examples() will produce the following:

I'm the inner scope - new reference: 50
I'm the outer scope: 20
I'm the inner scope - same reference: 50

Remember to:

  1. Don't create a new reference in memory (via the new keyword) if you just want to modify the value of something you've passed.
  2. Return the exact item you want to return if you intend on reusing a variable.

Container Types

  1. Container Types (Lists, Arrays, etc.) don't Pass by Reference either.
  2. They Pass by Value but changes are copied to the same Pointer allowing changes to persist or modify the Variable outside the scope of an operation.
  3. This is sometimes confused as Pass by Reference since is functions in a fairly similar manner (and per the above is Pass by Reference-ish quirk of Java).

Class Fields

Java only supports Pass by Value but one can still refer to Class Variables/Fields as a way of persisting some state, change, or Value outside the scope of a Method:

public class MyClass {
  private static String myString = "Original";
  
  private static void myMethod() {
      myString = "Updated!";
  }
    
  public static void main(String args[]) {
        System.out.println(myString);
        myMethod();
        System.out.println(myString);
  }
}
Original
Updated!
  1. https://www.interviewbit.com/java-interview-questions/#does-java-pass-by-value-or-pass-by-reference

Java: Beans

Beans are Encapsulated, reuseable, resources that are created and typically initialized as Singletons in an Application Context.

Some specialized Beans (like the Java EE Message Driven Bean) are not Singletons and respond to triggering messages instead:

  1. They don't maintain a Synchronized or common state throughout the Application.
  2. Today, Message Driven Beans have been widely replaced by other Publish-Subscribe, Event Listening, or Streaming alternatives.

They can then be used anywhere within the Application provided they are correctly configured to do so.

Lifecycle

Within Spring, (customized) Beans are configured using the @Bean annotation within a @Configuration Configuration Class. In Java EE, Beans were traditionally defined using an XML file (and are often defined today using annotations similar to the way that Servlets once were nearly universally defined using XML files and are now often defined programmatically using annotations).

They are then Injected into a Service (@Service) or Component (@Component) typically using the @Autowired annotation (Decorator). Spring Components are Beans themselves (and Services are a kind of Component). Spring knows to look for Components automatically from the @SpringBootApplication or @EnableWebMvc annotation.

  1. Beans are then Initialized at Run Time.
  2. Services that use them as a dependency can modify their state, make calls using their methods, etc.
  3. They are destroyed when the Application Context is shut down or destroyed.

Java: Object Oriented Design

Java uses a top-level Object Class that all non-primitive Types inherit from.

Object Oriented Concepts

Java uses:

  1. Classes (templates, types, or kinds of things that Objects are or that Objects instantiate)
  2. Objects (specific instances, copies, or particular instantiations of Classes)
public class Example {
    private String id;

    // non-parameterized constructor
    public Example() {}

    // parameterized constructor
    public Example(String id) {
        setId(id);
    }

    // getters and setters
    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
Example x = new Example();
Example x = new Example("fsfsf");

Encapsulation

Encapsulation refers to enclosing all the functionalities of an object within that object so that the object’s internal workings (its methods and properties) are hidden from the rest of the application.

Getters and Setters, Access Modifiers, and Packages are some of the primary ways Encapsulation is achieved in Java.

Encapsulation: boundaries, visibility, and access are restricted.

Aggregation

Aggregation refers to one Class having another Class as a field or as belonging to another Class as nested Classes.

Classes can be defined and combined within Classes, a kind of nesting.

Instantiating the Inner Class results in the Outer Class also being instantiated.

public class A {
    //...
}

public class B {
    A a;
}

A nested Class may need to be Static in order to effectively outlive the wrapping Outer Class. Failing to do so can introduce memory leaks.

public interface WidgetParser {
    Widget parse(String str);
}
        
public class WidgetParserFactory {
    public WidgetParserFactory(ParseConfig config) {
        //...
    }
        
    public WidgetParser create() {
        new WidgetParserImpl(//...);
    }
        
    private class WidgetParserImpl implements WidgetParser {
        //...
                
        @Override 
        public Widget parse(String str) {
            //...
        }
    }
}

Since WidgetParserImpl isn't Static, if WidgetParserFactory is discarded after WidgetParser is created, memory leaks can ensue. Using the static keyword here implies that no instances of WidgetParserImpl need to be instantiated at all (and hence, can avoid the issue of lingering nested Objects).

From: https://www.toptal.com/java/interview-questions and https://www.javatpoint.com/static-nested-class

Note that Composition is a specific, stronger, variant of Aggregation where both the Outer and Inner Classes are tightly coupled: they are created and destroyed together.

From: https://www.geeksforgeeks.org/association-composition-aggregation-java/

Inner and Outer Class Initialization

public class A {
    public class B {
        public String runMe() {
            //...
        }
    }
}
A outerObject = new A();
A.B b = outerObject.new B();
System.out.println(b.runMe());

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

Refer to: https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/Main.java

Inheritance

Inheritance:

  1. Classes can be subclassed (e.g. - kinds, kinds of a kind).
  2. The attributes available on parent Classes or prototypes are available on their children.
  3. Inheritance occurs via the extends keyword. Java does not support multiple inheritance in Classes (but it does for Interfaces).

Remember that basic initialization obeys the following general schema:

[Superclass] x = new [Type Inheritor of Superclass]();

super:

  1. Use the super keyword to access Superclass properties.
  2. Call super() to invoke the Superclass constructor (which can be parametized).
  3. Or, use super to invoke a parent Class method like so Collection.super.stream().skip(1);

Polymorphism

Polymorphism: an Object may belong to multiple Classes or exhibit multiple kinds.

Since Java does not directly support Multiple Inheritance in Classes, Polymorphism with respect to Class Inheritance is only accomplished by extending a Class and implementing one or more Interfaces, implementing two or more Interfaces, or by extending a Class that is also extending many other Classes.

Thus, a Class that implements multiple Interfaces is said to exhibit Polymorphism.

public interface Mammal extends Animal, Biologic {
    //...
}

public class Adam extends Human implements Mammal, Developer {
    //...
}

Records

Records - specified by the record keyword - syntactic sugar to specify an immutable POJO / DTO.

Example:

record Car(int seats, String color) {}
  1. Automatically generates Getters and initializes field values.
  2. Automatically generates the AllArgs Constructor.
  3. Can define instance methods and custom Constructors.
  4. Records cannot use an explicit extends keyword:
    • All Record Classes are final, so we can’t extend it.
    • All Record Classes implicitly extend java.lang.Record Class.
  5. All the fields specified in the record declaration are final.
  1. https://www.toptal.com/java/interview-questions
  2. https://www.javatpoint.com/static-nested-class
  3. https://www.geeksforgeeks.org/association-composition-aggregation-java/
  4. https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
  5. https://www.digitalocean.com/community/tutorials/java-records-class

Code samples:

  1. https://github.com/Thoughtscript/java-refresh-notes/tree/master/src/io/thoughtscript/refresh/ood
  2. https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/Main.java
  3. https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/records/RunRecordExample.java

Java: Enums

Basic Example

Given:

public class Pet {

    public enum PetType {DRAGON, DOG, CAT, BULL, JARBUL}

    private PetType type;


    public long getPet_id() {
        return pet_id;
    }

    public void setPet_id(long pet_id) {
        this.pet_id = pet_id;
    }

    //...
}
Pet pet = new Pet();
pet.setType(Pet.PetType.DRAGON);

Advanced Topics

Remember that you can define:

  1. Fields
  2. Methods
  3. Constructors

within Enums.

As such one can also implement Singletons.

  1. https://www.baeldung.com/a-guide-to-java-enums

Code samples:

  1. https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/sealed/SealedExample.java

Java: Dynamic Proxying

Java Proxy Classes (Java Proxies):

  1. Are encouraged in Clean Code.
  2. Can be thought of as a Facade (a Wrapper with additional functionality to simplify use).
  3. Often target some range of Interface implemenations.
  4. Used to invoke or execute some additonal operation or imbue an operation with extra functionalities. (Additional logging, intercepting a method (via InvocationHandler), etc.)
  1. https://www.baeldung.com/java-dynamic-proxies
  2. https://www.logicbig.com/tutorials/core-java-tutorial/java-dynamic-proxies/method-interceptors.html
  3. https://opencredo.com/blogs/dynamic-proxies-java-part-2/
  4. https://codegym.cc/groups/posts/208-dynamic-proxies

Java: Abstraction

  1. Interfaces and Abstract Classes allow for the general structure of Implementing Classes to be planned out and further specified in those implementations.
  2. Interfaces are lighter-weight and impose fewer suppositions on implementing Classes than Subclasses of Abstract Classes.
  3. Abstract Classes typically contain fully-defined Methods that are then Overridden whereas Interfaces only contain Method signatures.
  4. Both Interfaces and Abstract Classes can have fields defined within them that are borne by their Implementing or Subclassing Classes.

Interface

  1. Interfaces support Multiple Inheritance (whereas Classes don't).
  2. Methods defined in Interfaces are Public and Abstract by default. Typically, only their signature is defined.
  3. Are Implemented or Extended with the implements or extends keywords, respectively.
  4. Fields defined in an Interface are public static final by default.
public interface ExampleA {
    public void methodA();
    void methodB();
}
public interface ExampleB extends ExampleA {
    void methodC();
}
public class ExampleBImpl implements ExampleB {
    public void methodA() {
        System.out.println("I'm methodA");
    }

    public void methodB() {
        System.out.println("I'm methodB");
    }

    public void methodC() {
        System.out.println("I'm methodC");
    }
}

Functional Interfaces

Lambdas can also be used with Functional Interfaces (which provide the most amount of customization when using lambda expressions):

public class HelloWorld{
    
    @FunctionalInterface
    interface CheckStringInterface {
        boolean checkStringLambda(String s);
    }
    
    private static boolean checkString(String s) { 
        return ((s != null) && (s != "" ) && (Character.isUpperCase(s.charAt(0))));    
    }
    
    private static CheckStringInterface checkStringInstance = 
        (String s) -> ((s != null) && (s != "" ) && (Character.isUpperCase(s.charAt(0))));
    
    public static void main(String []args){
        System.out.println(checkStringInstance.checkStringLambda("Test"));
        System.out.println(checkStringInstance.checkStringLambda("Alpha"));
        System.out.println(checkString("test"));
    }
}

We observe how the Lambda expression allows us to implement the checkStringLambda() method as we see fit. The same parameters must be retained in a specific implementation but we can go wild with whatever we want right of the arrow:

public class HelloWorld{
    
    @FunctionalInterface
    interface CheckStringInterface {
        boolean checkStringLambda(String s);
    }
        
    private static CheckStringInterface checkStringInstanceOne = 
        (String s) -> ((s != null) && (s != "" ) && (Character.isUpperCase(s.charAt(0))));

    private static CheckStringInterface checkStringInstanceTwo = 
        (String s) -> (s != null);
    
    public static void main(String []args){
        System.out.println(checkStringInstanceOne.checkStringLambda("Test"));
        System.out.println(checkStringInstanceTwo.checkStringLambda("Alpha"));
    }
}

@FunctionalInterface must only be used on an Interface with one Method. A Functional Interface is an Interface with a single method to implement and allows Java to have a degree of Functional Programming in what is otherwise resolutely Object Oriented.

Abstract Classes

  1. Abstract Classes are not themselves instantiated (although they can contain a Constructor) - they are Subclassed and instantiated thereby.
  2. Methods belonging to an Abstract Class can be Abstract and they can be Overridden.
  3. Abstract Classes are Subclassed using the extends keyword and their methods are Overridden using the @Override annotation.
public abstract class ExampleA {

    public void methodA() {
        System.out.println("I'm methodA from within ExampleA");
    }

    abstract void methodB();
}
public class ExampleB extends ExampleA {

    @Override
    public void methodA() {
        System.out.println("I'm methodA from within ExampleB");
    }

    public void methodB() {
        System.out.println("I'm methodB");
    }
}

Java: Singletons

A Singleton is a Class that's instantiated once and reused everywhere as that, single, copy.

Not Thread Safe

// Sloppy not thread safe - HackerRank
class Singleton{
   private static final Singleton instance = new Singleton();
   public static String str;
 
   private Singleton() {}
 
   public static Singleton getSingleInstance() {
     return instance;
   }
}

Thread Safe Implementations

import java.util.concurrent.Semaphore;

// Refer to: https://www.digitalocean.com/community/tutorials/thread-safety-in-java-singleton-classes
public class ThreadSafeSingleton {

   // Requires the CPU not to reorder when the variable is read using volatile.
   // Avoids a scenario where prior to initialization the variable might
   // be null in a secondary Thread.
   private static volatile ThreadSafeSingleton instance;

   // Private constructor for Singleton
   private ThreadSafeSingleton() {}

   public static ThreadSafeSingleton getOrCreateInstance() {
     // Separate out the volatile variable into another copy so no
     // copies are read by different threads here.
     ThreadSafeSingleton result = instance;

     if (result == null) {
           // synchronized
           synchronized (ThreadSafeSingleton.class) {
             result = instance;
             if (result == null) {
                 instance = result = new ThreadSafeSingleton();
             }
         }
     }
     return result;
   }

   // Mutex - initialize beforehand in a static context
   // Obviously, since a Singleton is only a single instance don't put Mutex's in a Main method or above as a field:
   // e.g. - private final Semaphore mutex = new Semaphore(1);
   public static ThreadSafeSingleton getOrCreateInstanceWithSemaphore(Semaphore mutex) throws InterruptedException {
     // Separate out the volatile variable into another copy so no
     // copies are read by different threads here.
     ThreadSafeSingleton result = instance;

     if (result == null) {
         if (mutex.availablePermits() > 0) {
             mutex.acquire();
             result = instance;
             if (result == null) {
                 instance = result = new ThreadSafeSingleton();
             }
             mutex.release();
         }
     }
     return result;
   }
}

Code samples:

  1. https://github.com/Thoughtscript/java-refresh-notes/tree/master/src/io/thoughtscript/refresh/patterns

Java: Visibility and Access Modifiers

Access Modifiers

  1. public - Everywhere within the Application, all Subclasses.
  2. protected - Same Package, Subclasses regardless of Package.
  3. package/none/default - Same Package, Subclasses in same Package.
  4. private - Class and Object only, no Subclasses.

Static vs Nonstatic

  1. static - belongs to the Class within which it resides.

  2. non-static - belongs to the Object/instance and is checked at runtime.

    A Non-static method belongs to the specific Object/instantiation of a particular Class. Non-static methods thus require an Object created via the constructor keyword new and are invoked directly from that created Object.

Final

  1. The final keyword specifies that a variable is immutable, a constant.
  2. The final keyword specifies that a method cannot be Overridden.
  3. The final keyword specifies that a class cannot be Extended / Subclassed.

Sealed

Specifies that only certain Classes can inherit from or implement from the sealed Class or Interface.

  1. An optional and potentially intermediate access visibility modifier-like keyword.

  2. Specifies the exact Subclasses that can Subclass. (Even the Default/Package can be unduly permissive – consider Classes that have encryption hashes/ciphers/salts.)

  3. Or, Classes that can implement an Interface.

  4. sealed Class constraints:

    • Permitted Subclasses must belong to the same module as the sealed Class.
    • Every permitted Subclass must explicitly extend the sealed Class.
    • Every permitted Subclass must define a modifier: final, sealed, or non-sealed.
  5. Generally, a sealed-type hierarchy can have a Class or an Interface as its root.

    • The remainder of the hierarchy can contain Classes or Interfaces, provided all leaf nodes of the hierarchy are either final concrete Classes or are non-sealed.
    • If a leaf element is non-sealed, it can be either a Class or an Interface.
  6. Example hierarchy from https://blogs.oracle.com/javamagazine/post/java-sealed-types-subtypes-final:

    sealed interface Top permits A, B, C {}
    non-sealed class A implements Top {}
    record B(Top s) implements Top {}
    enum C implements Top { SUB_A{}, SUB_B{} }
    

Style Guides

  1. https://blogs.oracle.com/javamagazine/post/java-comments-reduce-technical-debt
  2. https://google.github.io/styleguide/javaguide.html#s3-source-file-structure
  1. https://blogs.oracle.com/javamagazine/post/java-comments-reduce-technical-debt
  2. https://google.github.io/styleguide/javaguide.html#s3-source-file-structure
  3. https://blogs.oracle.com/javamagazine/post/java-sealed-types-subtypes-final
  4. https://blogs.oracle.com/javamagazine/post/java-quiz-sealed-type-records
  5. https://www.baeldung.com/java-sealed-classes-interfaces

Code samples:

  1. https://github.com/Thoughtscript/java-refresh-notes/tree/master/src/io/thoughtscript/refresh/visibility
  2. https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/sealed/SealedExample.java

Java: Checked and Unchecked Exceptions

Some Java Exceptions are Checked - they require a throws keyword or a try-catch block at Write Time, Compile Time.

Others aren't. They are Unchecked - handled and Thrown at Run Time.

Examples:

  1. ArrayIndexOutOfBoundsException is Unchecked.
  2. NullPointerException is Unchecked.
  3. Parsing format exceptions are typically Checked. e.g. - ParseException

Handling

Interesting scenario:

class BatteryException extends Exception { }
class FuelException extends Exception { }
public class Car {
  public String checkBattery() throws BatteryException {
    // implementation
  }
  public String checkFuel() throws FuelException {
    // implementation
  }
  public String start() {
    try {
      checkBattery();
      checkFuel();
    } catch (BatteryException be) {
      return "BadBattery";
    } finally {
      return "";
    }
  }
}
  1. One might be tempted to think the compiler refuses to compile since FuelException isn't caught. However, the presence of the finally clause overrules that typical requirement.
  2. One might also be tempted to think that "BadBattery" is returned or FuelException is thrown from start(). Again, the presence of the finally clause overrules that incorrect but informed intution. (Regardless of the implementation of checkBattery() and checkFuel() the end result will always be the same.)

In the above scenario: start() will always return a "".

From: https://blogs.oracle.com/javamagazine/post/java-quiz-try-catch-finally-exception

  1. https://blogs.oracle.com/javamagazine/post/java-quiz-try-catch-finally-exception

Code samples:

  1. https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/finallyblock/FinallyExample.java

Java: Errors

Fatal Errors at Runtime will terminate an Application killing the Process.

Exceptions, by contrast, are undesired or predicted defects in some code that are Thrown, Caught, and Handled at Compile Time and Run Time.

Finally

A finally block may be reached and executed when a fatal system Error occurs or if the Process is killed early (deliberately).

// JavaScript
process.exit()
// Java
System.exit(0);

Java: Arrays

Use length to access the size of the Array.

Java Arrays are fixed in their size after initialization.

Initialization

// With dimensions/size using this syntax.
// The default way
int[] intArrA = new int[8];
int[] intArrB;

Array initialization with values:

int[] intArrA = {1,2,3,4000,707,707,3,3};

Reassignment

Note that an Array A that's been assigned a size a > b can be reassigned with an Array value of size b without limitation.

int[] A = {1,2,3,4,5,6,7,8};
int[] B = {5,5,5,5,5};
A = B;
      
for (int i = 0; i < A.length; i++) {
    System.out.println(A[i]);
}

/*
5
5
5
5
5
*/

Thus, initializing an Array like so:

int[] C;
C = A;

for (int i = 0; i < C.length; i++) {
    System.out.println(C[i]);
}

/*
5
5
5
5
5
*/

can help to reduce invalidly declared Arrays.

Reference Types

Remember that primitive Arrays aren't Autoboxed to their reference types. (Also, that the type of an Array is the type of each element.) (Each individual element can be in the right circumstances, however.)

Consequently, int[] won't be Autoboxed to Integer[] nor Object[] and so doesn't meet the constraints of either an Object[] o parameter nor the generic <T>, T[].

public static <T> void printArray(T[] o) {
    for (int i = 0; i < o.length; i++) {
        System.out.println(o[i]);
    }
}
    
public static void main(String[] args) {
    // Remember that int[] isn't autoboxed to Integer[] 
    // only each int[i]
        
    // Also Object[] requires that int[] would be autoboxed to Integer[] first
    // So, either set that explicitly or convert
    Integer[] intArr = {1, 2, 3};
    String[] strArr = {"Hello", "World"};
    printArray(intArr);
    printArray(strArr);
}

To and From ArrayLists, Lists

To ArrayList:

Integer[] array = {1, 2, 3};

List<Integer> listA = List.of(array);

List<Integer> listB = Arrays.asList(array);

ArrayList<Integer> listC = new ArrayList<Integer>(Arrays.asList(array));

And back again:

// Will create an Array of length equal to the Collection size
Integer[] arrA = listA.toArray();

// Faster zero-size Array
// Better for Casting and Generics
// Use this even over .toArray(new Integer[listB.size()])
Integer[] arrB = listB.toArray(new Integer[0]);

Refer to: https://www.baeldung.com/java-collection-toarray-methods

Concatenation

Solutions that work for both Object and Primitive Type Arrays:

int[] arrA = {1, 2, 3};
int[] arrB = {4, 5, 6};
int[] result = new int[arrA.length+arrB.length];

for(int i = 0; i < arrA.length; i++) {
    result[i] = arr1[i];
}

for(int i = 0;i < arrB.length; i++) {
    result[arrA.length + i] = arrB[i];
}

java.util.Arrays - copyOf():

import java.util.Arrays;

//....
int[] arrA = {1, 2, 3};
int[] arrB = {4, 5, 6};
int[] result = Arrays.copyOf(arrA, arrA.length + arrB.length);

System.arraycopy(arrB, 0, result, arrA.length, arrB.length);

org.apache.commons.lang.ArrayUtils - addAll():

import org.apache.commons.lang.ArrayUtils;

int[] arrA = {1, 2, 3};
int[] arrB = {4, 5, 6};

int[] result = ArrayUtils.addAll(arrA, arrB);

Sorting

Refer to the article on Comparisons.

int[] arrA = {5, 6, 3, 9, 4, 5, 6,1, 2, 3};

// Natural sort
Arrays.sort(arrA);

parallelSort() is performant at element sizes greater than 1,000,000.

Otherwise, it's likely less performant than a standard sort().

Arrays.parallelSort(arrA);
  1. https://www.tutorialkart.com/java/java-array/java-concatenate-arrays/
  2. https://dev.to/khmarbaise/stream-concat-vs-new-arraylist-performance-within-a-stream-4ial
  3. https://www.geeksforgeeks.org/serial-sort-vs-parallel-sort-java/
  4. https://www.baeldung.com/java-arrays-sort-vs-parallelsort
  5. https://www.baeldung.com/java-collection-toarray-methods

Code samples:

  1. https://github.com/Thoughtscript/java-refresh-notes/tree/master/src/io/thoughtscript/refresh/arrays
  2. https://github.com/Thoughtscript/java_algos/blob/main/src/main/java/io/thoughtscript/conversions/Conversions.java

Java: Collections

  1. Remember that Collections require Reference Types not Primitive Types: e.g. Set<Integer> vs. Set<int>.

List

List<String> list = new ArrayList<String>();
    list.add("A");
    list.add("B");
    list.add("C");
  1. indexOf() is a List method not available on Arrays (without conversion).
  2. Use LinkedList for more expedient modifications.
// Conversion between int array to List

// Reference type from primitive - either stream or use reference type
Integer[] intArrA = {1,2,3,4000,707,707,3,3};

// Must use reference type 
List<Integer> intList = Arrays.asList(intArrA);

// Or to ArrayList
ArrayList<Integer> listB = new ArrayList<Integer>(Arrays.asList(intArr));

UnmodifiableList

List<String> listC = new ArrayList<>(Arrays.asList("one", "two", "three"));
List<String> unmodifiableList = Collections.unmodifiableList(listC);
// unmodifiableList.add("four"); // unmodifiableList is immutable!

// (if listC is modified so will the view unmodifiableList - e.g:
// listC.add("four");)

For more:

  1. https://www.baeldung.com/java-immutable-list
  2. https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/lists/ListExamples.java
  3. https://blogs.oracle.com/javamagazine/post/java-lists-view-unmodifiable-immutable

Set

Set<Integer> setC = new HashSet<>();
    setC.add(0);
    setC.add(1);
    setC.add(2);
    setC.add(3);
    setC.add(4);

bool x = setC.contains(0);

Map

// ...<Key, Value>
Map<String, String> hmA = new HashMap<String, String>();
    hmA.put("0", "A");
    hmA.get("0"); // null or Value
    hmA.containsKey("0"); // true if Key is present, false otherwise

// Access and iterate through keys
for (String x : hmA.keySet()) {
    System.out.println(x);
}

HashMap

  1. Java Collections HashMap is a basic implementation of Map.
  2. It uses hashCode() to estimate the position of a Value and to create hashed Keys (using backing buckets to store hashes in a Hash Table). The number of buckets used is called the capacity (not to be confused with the number of Keys or Values).
  3. It accepts null as a Key and isn't Thread Safe.
  4. Keep the Key range small to avoid unnecessarily large buckets in-memory.
  5. Generally, Keys should be immutable. If a Key-Value pair requires alteration, evict and remove the previous Key and create a new entry.

Note that a HashSet has Objects as Values that are hashed into Keys using a backing HashMap. This guarantees uniqueness/deduplication.

  1. https://www.baeldung.com/category/java/java-collections
  2. https://www.baeldung.com/java-hashmap
  3. https://www.baeldung.com/java-immutable-list
  4. https://blogs.oracle.com/javamagazine/post/java-lists-view-unmodifiable-immutable

Code samples:

  1. https://github.com/Thoughtscript/java-refresh-notes/tree/master/src/io/thoughtscript/refresh/collections
  2. https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/lists/ListExamples.java

Java: Streams

Streams are:

  1. Immutable

  2. Used once.

    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    public class Example {
       public static void main(String args[]) {
          Stream<Integer> myStream = Stream.of(1,2,3,4,8,7,6,5,4);
          myStream.sorted((a, b) -> a - b);
          myStream.map(x -> x + 1).collect(Collectors.toList());
       }
    }
    
    Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
    //...
    

List

From List:

List<Integer> myList = new ArrayList<Integer>();

for(int i = 1; i< 10; i++){
    myList.add(i);
}

Stream<Integer> myStream = myList.stream();

To List:

Stream<Integer> myStream = //...

// Faster way to do this: myStream.collect(Collectors.toList());
List<Integer> myList = myStream.toList();

Array

From Array:

Integer[] myArr = {1, 2, 3, 4, 5};

Stream<Integer> myStream = Arrays.stream(myArr);

To Array:

Stream<Integer> myStream = //...

Integer[] myArr = myStream.toArray(Integer[]::new);

Examples

Sort using sorted to return the third lowest Example id - required to use a Stream.

Given:

public class Example {
    private int id;
    private String name;

    // Constructor
    //... Getters and Setters
}

Example One

Stream<Example> myStream = //...

// Implements a Comparator
Stream<Example> sorted = myStream.sorted((a, b) -> a.getId() - b.getId());

// toList() via Collector
List<Example> myList = sorted 
  .collect(Collectors.toList());

myList.get(3);

Example Two

From a List:

List<Example> myList = //...

// Don't modify myList in place
Integer[] myArr = myList.toArray(new Integer[0]);

Stream<Example> myStream = Arrays.stream(myArr);

// Implements a Comparator
Stream<Example> sorted = myStream.sorted((a, b) -> a.getId() - b.getId());

// toList() via Collector
List<Example> myList = sorted 
  .collect(Collectors.toList());

myList.get(3);

Example Three

From a List working with result Array:

List<Example> myList = //...

// Don't modify myList in place
Integer[] myArr = myList.toArray(new Integer[0]);

Stream<Example> myStream = Arrays.stream(myArr);

// Implements a Comparator
Stream<Example> sorted = myStream.sorted((a, b) -> a.getId() - b.getId());

Integer[] myArr = myStream.toArray(Integer[]::new);

myArr[3];

Parallel Streams

Use when order doesn't matter.

Leverages underlying worker pooling from the Common Worker Pool:

List<Integer> myList = Arrays.asList(1, 2, 3, 4);

myList.parallelStream().forEach(num ->
    System.out.println(myList + " " + Thread.currentThread().getName())
);

Common Operations

forEach

list.stream().forEach(consumer);
Stream<Example> myStream = //...
myStream.forEach(System.out::print);
myStream.forEach(x -> System.out.println(x));

map

list.stream().map(x -> x + 1);
Stream<Example> myStream = //...
myStream.map(x -> x + 1);

Reference Type to Primitive Type

Use IntStream, LongStream, or DoubleStream for any primitive numeric typed Stream.

Integer[] myArr = {1, 2, 3, 4, 5};

Stream<Integer> myStream = Arrays.stream(myArr);

IntStream is = s.mapToInt(i -> i);

Eliding

Streams will occasionally omit certain internal operations if:

  1. Doing so does not modify the outcome or result of the computation.
  2. The Stream is passed into some kind of dynamic processing where the size or count cannot be automatically determined beforehand.

Logging and output messages, in particular, will occasionally fail to display.

Refer to:

  1. https://docs.oracle.com/javase/10/docs/api/java/util/stream/Stream.html
  2. https://blogs.oracle.com/javamagazine/post/java-quiz-stream-api-side-effects
  1. https://www.baeldung.com/java-when-to-use-parallel-stream
  2. https://howtodoinjava.com/java/stream/java-streams-by-examples/
  3. https://www.geeksforgeeks.org/arrays-stream-method-in-java/
  4. https://www.baeldung.com/java-collection-stream-foreach
  5. https://blogs.oracle.com/javamagazine/post/java-quiz-generics-primitives-autoboxing
  6. https://docs.oracle.com/javase/10/docs/api/java/util/stream/Stream.html
  7. https://blogs.oracle.com/javamagazine/post/java-quiz-stream-api-side-effects

Code samples:

  1. https://github.com/Thoughtscript/java_algos/blob/main/src/main/java/io/thoughtscript/conversions/Conversions.java
  2. https://github.com/Thoughtscript/java-refresh-notes/tree/master/src/io/thoughtscript/refresh/streams

Java: Primitive Types

Each Primitive Type has a corresponding Reference Type which wraps the underlying Primitive Type with additional functionality. Furthermore, Reference Types allow null values where they wouldn't be typically allowed (e.g. an int has no null value under normal circumstances - its default value is 0).

Note: Strings are essentially Reference Types with char as their corresponding Primitive Type. Note further: char has Character as its correspond Reference Types.

int

int types must be instantiated with a value anywhere but a field in or on a Class itself:

public class Metrics {
    private static int total;
    
    public static void main(String args[]) {
        System.out.println(total);
    }
}

Otherwise, initialize the variable with a value:

public class Metrics {    
    public static void main(String args[]) {
        int total = 0;
        System.out.println(total);
    }
}

Note that int can't support precise fractional division without rounding, using a String, or some LCD algo (Least Common Denominator).

Java: Strings, StringBuffer, StringBuilder

  1. Java Strings use the String Pool, are immutable, and are Primitive Data Types.
  2. StringBuilder does not use Java's String Pool, isn't Thread Safe, and is better (performance and memory-wise) for concatenating complex and lengthy Strings. (StringBuilder is used automatically under the hood now for simple String concatenations like String c = a + b + ":".)
  3. StringBuffer is the Thread Safe version of StringBuilder.

String Pool

Java's String Pool points Strings with the same value to the same item in-memory.

This optimization feature is designed to offset some performance costs associated with the immutability of Java's Strings and is referred to as Interning.

Interning can be manually set via String.intern():

String x = new String("abc");
String y = x.intern();
// Will be the same
// Useful when using a String constructor

String Constructor

Using a Constructor will force two Strings with the same text to refer to different items in memory.

Caveat: unless -XX:+UseStringDeduplication is enforced at the JVM level (say, as an arg) or if intern() isn't called.

String a = "abc";
String b = new String("abc");
// Not the same memory address

String c = "abc";
// Strings a and c have the same text value and the same memory address

Comparison

Remember the following:

String x = "abc";
String y = "abc";
System.out.println(x == y); // true

String z = new String("abc");
System.out.println(x == z); // false

JVM Fine-Tuning

-XX:StringTableSize=4901

The maximum StringTableSize Java 11+ is now 65536.

Note: the -X and -XX affixes indicate non-standard and potentially unstable "power user" JVM parameters settings, respectively.

StringBuilder

Using + in a (large) loop will still (in Java 18) result in wonkiness:

  1. Inefficient from a time-complexity standpoint.
  2. The underlying implementation (automatic conversion between + and StringBuilder) is imperfectly performant for large cases.
  3. Will actually be indeterministic (as I found out). And interestingly in at least two ways:
    • By machine.
    • With identical code blocks being run sequentially.

Consider generating a String hash for comparing Sets of Arrays:

Set<int[]> exampleA = new HashSet<>();
exampleA.add(new int[]{1, 2});
exampleA.add(new int[]{3, 4});
exampleA.add(new int[]{5, 6, 7});

String stringHashA = "";

for (int[] entry : exampleA) {
    stringHashA += "{";
    for (int i = 0; i < entry.length; i++) {
        stringHashA += entry[i];
        if (i < entry.length - 1) stringHashA += ",";
    }
    stringHashA += "}";
}

Set<int[]> exampleB = new HashSet<>();
exampleB.add(new int[]{1, 2});
exampleB.add(new int[]{3, 4});
exampleB.add(new int[]{5, 6, 7});

String stringHashB = "";

for (int[] entry : exampleB) {
    stringHashB += "{";
    for (int i = 0; i < entry.length; i++) {
        stringHashB += entry[i];
        if (i < entry.length - 1) stringHashB += ",";
    }
    stringHashB += "}";
}

System.out.println(stringHashA);
System.out.println(stringHashB);
System.out.println(stringHashA.equals(stringHashB));
// stringHash will be indeterministic with respect to the two identical code blocks
/*
    {5,6,7}{3,4}{1,2} - this is deterministic and will always print this on same machine
    {5,6,7}{1,2}{3,4} - this is deterministic and will always print this on same machine
    false
*/
/*
    {3,4}{1,2}{5,6,7} - on a different machine
    {5,6,7}{1,2}{3,4} - on a different machine
    false
*/
Set<int[]> exampleA = new HashSet<>();
exampleA.add(new int[]{1, 2});
exampleA.add(new int[]{3, 4});
exampleA.add(new int[]{5, 6, 7});

StringBuilder stringHashA = new StringBuilder();
for (int[] entry : exampleA) {
    stringHashA.append("{");
    for (int i = 0; i < entry.length; i++) {
        stringHashA.append(entry[i]);
        if (i < entry.length - 1) stringHashA.append(",");
    }
    stringHashA.append("}");
}

Set<int[]> exampleB = new HashSet<>();
exampleB.add(new int[]{1, 2});
exampleB.add(new int[]{3, 4});
exampleB.add(new int[]{5, 6, 7});

StringBuilder stringHashB = new StringBuilder();
for (int[] entry : exampleB) {
    stringHashB.append("{");
    for (int i = 0; i < entry.length; i++) {
        stringHashB.append(entry[i]);
        if (i < entry.length - 1) stringHashB.append(",");
    }
    stringHashB.append("}");
}

System.out.println(stringHashA.toString());
System.out.println(stringHashB.toString());
System.out.println(stringHashA.toString().equals(stringHashB.toString()));
// stringHash will be indeterministic with respect to the two identical code blocks
/*
    {5,6,7}{3,4}{1,2} - this is deterministic and will always print this on same machine
    {3,4}{1,2}{5,6,7} - this is deterministic and will always print this on same machine
    false
*/
/* 
    {3,4}{1,2}{5,6,7} - on a different machine
    {1,2}{3,4}{5,6,7} - on a different machine
    false
*/

However:

Set<int[]> result = new HashSet<>();
result.add(new int[]{1, 2});
result.add(new int[]{3, 4});
result.add(new int[]{5, 6, 7});

StringBuilder stringHashResult = new StringBuilder();
for (int[] entry : result) {
    stringHashResult.append("{");
    for (int i = 0; i < entry.length; i++) {
        stringHashResult.append(entry[i]);
        if (i < entry.length - 1) stringHashResult.append(",");
    }
    stringHashResult.append("}");
}
       
System.out.println(resultStringHash.toString());
// stringHash will be deterministic on same machine but will generate different results otherwise

Refer to: https://stackoverflow.com/questions/11942368/why-use-stringbuilder-explicitly-if-the-compiler-converts-string-concatenation-t

  1. https://www.baeldung.com/java-string-pool
  2. https://stackoverflow.com/questions/11942368/why-use-stringbuilder-explicitly-if-the-compiler-converts-string-concatenation-t

Java: Important Keywords

  1. final - can't be changed as a variable, can't be Overridden as a method, and can't be subclassed as a Class.
  2. static
    • On a method: belongs to the Class not an instance or Object.
    • On a Class Field: the Value is shared between all Instances (akin to the @@ Class Variable in Ruby.)
    • static block allows for multiline initializations of static Class Variables.
  3. sealed - specifies that only certain Classes can inherit from or implement from the sealed Class or Interface.
  4. abstract - on a Class: can extend but not instantiate, can Override methods of the inherited Abstract Class.
  5. synchronized - enforce thread safety within the specified Object or Class.
  6. transient - ignore value, set a default value, and save or read from a serialized file.
  7. record - syntactic sugar to specify an immutable POJO / DTO.
  8. volatile - ignores CPU and memory caching and allows the actual CPU instruction order to be preserved. (Due to the nature of multi-threaded CPU's, instructions, values, etc. can be incorrectly handled by the CPU cache. In those circumstances it can be beneficial to side-step caching entirely.)
  1. https://blogs.oracle.com/javamagazine/post/java-record-instance-method
  2. https://blogs.oracle.com/javamagazine/post/java-quiz-sealed-type-records
  3. https://www.baeldung.com/java-sealed-classes-interfaces
  4. https://www.digitalocean.com/community/tutorials/java-records-class
  5. https://blogs.oracle.com/javamagazine/post/java-sealed-types-subtypes-final
  6. https://www.baeldung.com/java-static
  7. https://www.baeldung.com/java-volatile

Code Samples:

  1. https://github.com/Thoughtscript/java-refresh-notes
  2. https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/sealed/SealedExample.java
  3. https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/records/RunRecordExample.java

Java: Security

Java String over Character Array?

Strings remain in Heap for an unspecified amount of time in between Garbage Collecting. As such, using a Character Array can be a better choice since one can alter the contents of each index of the Array at any time between Garbage Collection events.

So, it can be a great choice for sensitive PII data that's in-memory.

Transient Serialization

When one uses the transient keyword, default values are Persisted and the original values are stored in a separate file. (This was often used for PII since it separates sensitive data into two parts that have to be reassembled.)

Scanners and Tools

  1. https://owasp.org/www-project-dependency-check/
  2. https://snyk.io/lp/java-snyk-code-checker/
  3. https://www.azul.com/
  1. https://www.interviewbit.com/java-interview-questions/
  2. https://www.benchresources.net/serializing-a-variable-with-transient-modifier-or-keyword/

Java: Generics

Generics abstract or generalize a method so that the specific details of the argument types are not required.

By convention:

/**
    Type Parameters:
    E - Element (used extensively by the Java Collections Framework)
    K - Key
    N - Number
    T - Type
    V - Value
    S,U,V etc. - 2nd, 3rd, 4th types
*/

Type Generics

public class KeyedTreeMap<T> implements Map<KeyedTreeMap<T>> {
    //...
}

Type Generics apply to Reference Types, not Primitive Types.

Bounded Type Parameters

We can require that a generic be constrained to being a certain type:

public static <X extends Integer> void exampleMethod(X[] genericArr) {
    //...
}
public interface Pair<K, V> {
    public K getKey();
    public V getValue();
}

public class ExamplePair<K, V> implements Pair<K, V> {
    private K key;
    private V value;

    public ExamplePair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey()    { return key; }
    public V getValue() { return value; }
}

//Instantiations of the ExamplePair class:
ExamplePair<String, Integer> p1 = new ExamplePair<String, Integer>("Even", 8);
ExamplePair<String, String>  p2 = new ExamplePair<String, String>("hello", "world");

Java: Techniques

Algo Quick Reference

Common operations specific to algorithm implementation:

// length, length(), size(), count()
myArray.length;
myString.length();
myList.size();
myStream.count();

// List
myListA.addAll(myListB); // Merge two Lists
myListA.add(0, myObject); // Prepend, unshift - adds an element to the beginning
myListA.add(myIdx, myObject); // Adds an element at index
myListA.pop(); // Pop - removes last element and returns
myListA.remove(myIdx); // Remove element at index
myListA.sort((a,b) -> b - a); // Custom sort with Lambda Comparator
myListA.equals(myListB); // Comparison

// Conversion
List<Integer> listA = List.of(myArray); // Convert Array to List
List<Integer> listB = Arrays.asList(myArray); // Convert Array to List
Integer[] arrA = listA.toArray(new Integer[0]); // Convert List to Array
Stream<Integer> myStream = myList.stream(); // Convert List to Stream
List<Integer> listA = myStream.toList(); // Convert Stream to List
Stream<Integer> myStream = Arrays.stream(myArr); // Convert Array to Stream
Integer[] myArr = myStream.toArray(Integer[]::new); // Convert Stream to Array

// Maps
myMap.put(myKey, myValue); // Add Key Value pair to Map
myMap.put(myKey, myMap.getOrDefault(myKey, 0) + 1); // initialize or increment counter
myMap.containsKey(myKey); // Check if Key exists in Map without traversal
myMap.get(myKey); // Get Value using Key - Null if not found
// Traverse keys
for (String x : myMap.keySet()) {
  //...
}

// Collections API
myList.add(myValue); // add to end of List
Integer x = myList.get(4); // return but don't remove entry at index 4

myStack.isEmpty(); // check if Stack has no elements
myStack.peek(); // look but don't return top of Stack
myStack.push(myValue); // add to end of Stack
myStack.pop(); // remove and return top of Stack
myStack.add(0, myValue); // add myValue to front of Stack

myQueue.isEmpty(); // check if Queue has no elements
myQueue.peek(); // return but don't remove front of Queue in order
myQueue.poll(); // remove and return front of Queue in order

// Chars
Character.isDigit(myChar); // Check if char is 0-9
Character.isLetter(myChar); // Check if char is letter
Character.isLetterOrDigit(myChar);  // Check if char is letter or 0-9
Character.isUpperCase(myChar); // Check if is uppercase
char myChar = myString.charAt(myIdx); // Get char at idx of String
String myStr = String.valueOf(myChar); // char to String
String myStr = new String(new char[]{'a', 'b', 'c'}); // chars to String

// Strings
String[] start = myString.split(""); // Split String
myString.substring(inclusiveIdx, exclusiveIdx); // Substring
myString.contains(otherString); // Substring match within

// Arrays
int[][] deepCopy = Arrays.copyOf(myArray, myArray.length); // Deep copy an Array
Arrays.sort(myArray); // Sort ascending
Arrays.sort(myArray, Collections.reverseOrder()); // Sort descending
Arrays.sort(myArray, (a, b) -> b - a); // Custom sort with Lambda Comparator

// Reference to Primitive Type
myInteger.intValue(); // Get int from Integer
myCharacter.charValue(); // Get char from Character

// int
int M = heap.size() / 2; // Same as int M = (int) (heap.size() / 2); which is the same as calling Math.floor(...) to drop decimals values.

// Comparators
Comparator.comparingInt(a -> a)
Comparator.comparing(Student::getName).thenComparing(Student::getAge)

URLConnection

Basic GET Request.

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

//...

try {
  URL u = new URL("https://jsonplaceholder.typicode.com/todos/1");
  URLConnection conn = u.openConnection();
  
  // Get the InputStream and enable reading from it
  InputStream stream = conn.getInputStream();
  // https://docs.oracle.com/javase/8/docs/api/java/io/InputStreamReader.html
  // "bridge from byte streams to character streams"
  InputStreamReader isr = new InputStreamReader(stream);
  // Convert the read data into a usable format.
  // https://docs.oracle.com/javase/8/docs/api/java/io/BufferedReader.html
  // Reads text from a character-input stream.
  BufferedReader in = new BufferedReader(isr);
            
  StringBuilder result = new StringBuilder();
  String inputLine;

  while ((inputLine = in.readLine()) != null) {
    result.append(inputLine);
  }

  System.out.println(result);
  in.close();
  stream.close();
  isr.close();
  inputLine = null;
  result = null;

} catch (Exception e) {
  //...
}
{  "userId": 1,  "id": 1,  "title": "delectus aut autem",  "completed": false}

https://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html and https://www.geeksforgeeks.org/java-net-urlconnection-class-in-java/

PrintWriter and FileInputStream

import java.io.*;
import java.util.*;

//...

public static void readFile() {
  FileInputStream fs = new FileInputStream("myfile.sufix");
  Scanner scn = new Scanner(fs);

  // Can now use Scanner to interact with file contents
  String exampleString = scn.nextLine();
  exampleString = scn.next();
  int exampleInt = scn.nextInt();
  double exampleDouble = (double) scn.nextFloat();

  while (scn.hasNextLine()) {
    System.out.println(scn.nextLine());
  }
  fs.close();
}

public static void writeFile() {
  FileOutputStream fs = new FileOutputStream("myfile.sufix");
  PrintWriter pw = new PrintWriter(fs);
  for (int i = 0; i < 10; i++) {
    pw.println(i);
  }
  pw.close();
  fs.close();
}

Scanner

java.util.Scanner is used extensively on Hacker Rank:

import java.util.*;

//...

public static void example() {
  // Receives typed inputs from User
  Scanner scn = new Scanner(System.in);

  String exampleString = scn.nextLine();
  exampleString = scn.next();
  int exampleInt = scn.nextInt();
  double exampleDouble = (double) scn.nextFloat();
}

String to Date

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date nextDate = formatter.parse("2024-01-25");

Date to Calendar

Useful to know this conversion since Calendar supports basic day and week addition operations.

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Date nextDate = formatter.parse("2024-01-25");
Calendar c = Calendar.getInstance();
c.setTime(nextDate);

char to int

Remember that merely casting a char to an int (recommended/encouraged by IntelliJ) will actually produce the wrong conversion:

String strNum = "12345";
char c = strNum.charAt(0);
int cc = (int) c;
int ccc = Character.getNumericValue(c);
System.out.println(cc == ccc); // false

Note that Integer.parseInt() will also accomplish the correct conversion along with Character.getNumericValue():

int ccc = Character.getNumericValue(c);
int cccc = Integer.parseInt(String.valueOf(c));
System.out.println(ccc == cccc); // true

length, size, and count

Check specific Character in String:

myArray.length;
myString.length();
myList.size();
myStream.count();

array slicing

String[] L = new String[] { "Python", "Java", "Kotlin", "Scala", "Ruby", "Go", "Rust" };
String[] R = Arrays.copyOfRange(L, 1, 4);

Refer to: https://www.baeldung.com/java-slicing-arrays

chars in String

Check specific Character in String:

char c = str.charAt(0);
String s = Character.toString(c);
boolean beginClosed = s.equals("[");

Sort an Array

2D:

int[][] intervals = [[1,2],[3,4],[5,6],[7,8]];

Arrays.sort(intervals, (a,b) -> {
    if (a[0] < b[0]) return -1;
    if (b[0] < a[0]) return 1;
    return 0;
});

1D:

int[] nums = [6,5,4,3,8,1];

Arrays.sort(nums);

Swap List Indicies

int l = 0;
int r = 5;
            
while (l < r) {
    Collections.swap(listInt, l, r);
    l++;
    r--;
}

Java Mail

To configure, install, and use Java Mail:

<!-- pom.xml -->
<!-- Java Email Dependencies -->
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.5.5</version>
</dependency>
# application.yml
spring:
  # Enable auth
  mail:
    host: smtp.gmail.com
    port: 587
    username: aaaaaaa
    password: aaaaaaa
    properties:
      mail:
        debug: true
        transport:
          protocol: smtp
        smtp:
          auth: true
          starttls:
            enable: true
package io.thoughtscript.example.services;

import io.thoughtscript.example.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class EmailService {

    @Autowired
    JavaMailSender javaMailSender;

    public void sendMagicEmail(String emailAddress, String token) {
        SimpleMailMessage email = new SimpleMailMessage();

        StringBuffer emailContent = new StringBuffer();
        emailContent.append(Constants.EMAIL_MAGIC_LINK_GREETING);
        emailContent.append(Constants.AUTH_LOGIN_ENDPOINT_FULLY_QUALIFIED);
        emailContent.append("?token=");
        emailContent.append(token);
        emailContent.append("&email=");
        emailContent.append(emailAddress);

        email.setFrom("testapp@test.com");
        email.setTo(emailAddress);
        email.setText(emailContent.toString());
        email.setSubject("test");

        log.info(email.getTo()[0]);
        log.info(email.getText());
        log.info(email.getSubject());

        javaMailSender.send(email);
    }
}

Refer to: https://www.digitalocean.com/community/tutorials/javamail-example-send-mail-in-java-smtp

Convert Time between TimeZones

import java.time.*;

//...
ZonedDateTime firstTime = ZonedDateTime.of(
  LocalDateTime.of(
    LocalDate.of(2000, 1, 26),
    LocalTime.of(19, 59)
  ),
  ZoneId.of("America/Halifax")
);

ZonedDateTime secondTime = firstTime.withZoneSameInstant(ZoneId.of("Asia/Makassar"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm");
String result = secondTime.format(formatter);

https://www.codewars.com/kata/605f7759c8a98c0023833718/train/java

Scientific Notation

double a = 5e-4;
System.out.println(a); //5.0E-4
                       //0.0005

double b = 5e4;
System.out.println(b); //50000.0

double c = 1.5e-5;
System.out.println(c); //1.5E-5
                       //0.000015

Decimal Precision

System.out.printf("%.3f", 9.1357);
//9.136
  1. https://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html
  2. https://www.geeksforgeeks.org/java-net-urlconnection-class-in-java/
  3. https://www.digitalocean.com/community/tutorials/javamail-example-send-mail-in-java-smtp
  4. https://www.baeldung.com/java-slicing-arrays
  5. https://www.geeksforgeeks.org/java-comparator-interface/

Java: Asynchronous Programming

Java Threads

  1. Java Threading is mapped to underlying System Threads by default (logical or physical CPU cores).
  2. Java Threads can be pooled to help ensure that the application's needs don't overwhelm the available physical resources.
  3. Java Thread Pooling relies heavily on the Executors and Runnable implementations:
    • Runnable - implementations of Runnable can be passed into Executors to be run automatically.
    • ExecutorService - provides factories for defining Thread Pool sizes on the fly or programmatically.
    • ThreadPoolExecutor - use for fine tuning a Thread Pool.
    • ScheduledExecutorService - for executing a task at a specific time.

Examples:

ExecutorService executor = Executors.newFixedThreadPool(10);
ExecutorService nonBlockingService = Executors.newSingleThreadExecutor();
nonBlockingService.execute(() -> {
    jmsClient.sendObject();
});
public class WorkerThread implements Runnable {
    @Override
    public void run() {//...}
}

ThreadPoolExecutor executorPool = new ThreadPoolExecutor(//...);
executorPool.execute(new WorkerThread());

Refer to: https://www.baeldung.com/java-executor-service-tutorial and https://www.javatpoint.com/executor-framework-java

Futures vs CompletableFutures

  1. Futures
    • Blocking.
    • Can't combine results from more than one Thread.
  2. CompletableFutures
    • Added in Java 8 and significantly improved in Java 9.
    • Chainable methods allow for JavaScript Promise-like resolve(), reject(), and promiseAll() behavior.
    • Can combine results from multiple Threads.
    • Non-blocking.

Asynchronous Promises

  1. Resolving and using an Asynchronous Objecct: CompletableFuture.supplyAsync(() -> { //... }).thenApplyAsync(result -> { //... })
if (openCsvService.validate(file)) {
    CsvTransfer csvTransfer = openCsvService.setPath(file);
    Instant start = TimeHelper.start(Constants.ALL);

    return CompletableFuture.supplyAsync(() -> {
        try {
            CompletableFuture<String> save = openCsvService.saveCsv(file);
            responseTransfer.setMessage(save.get());
        } catch (Exception e) {
            responseTransfer.setMessage(CSV_UPLOAD);
        }
            return responseTransfer;
        }).thenApplyAsync(result -> {
            try {
                CompletableFuture<List<String[]>> allPromise = openCsvService.readCsvAll(csvTransfer);
                result.setCsv(allPromise.get());
            } catch (Exception e) {
                responseTransfer.setMessage(GENERIC_EXCEPTION);
            }
            result.setPerformance(TimeHelper.stop(start));
             return result;
        });
    }

    responseTransfer.setMessage(CSV_VALIDATION_EXCEPTION);
    return CompletableFuture.completedFuture(responseTransfer);
}

Thread Safety

  1. synchronized - enforce thread safety within the contents of a Class or Object.
    • On a Static method, thread safety is enforced on the Class.
    • On a Non-Static method, thread safety is enforced on the Object.
  2. Atomic Objects have inherently Synchronized values.
  3. Refer to the article on Thread-Safe Singletons.
  4. Refer to the article on Computer Science Processes and Threads.
  5. Java provides Semaphores and Locks:
    • ReentrantLocks allow a single Thread to (re)access a resource at a time.
    • Semaphores allow a specified number of Threads to share access to a resource at any given time.
  6. Wait() vs Sleep():
    • Wait() - belongs to Object, Non-Static, should only be called from a Synchronized context.
    • Sleep() - belongs to Thread, Static,
  1. https://www.javatpoint.com/executor-framework-java
  2. https://www.baeldung.com/java-executor-service-tutorial
  3. https://blogs.oracle.com/javamagazine/post/java-concurrent-synchronized-threading
  4. https://www.geeksforgeeks.org/difference-between-wait-and-sleep-in-java/

Java: SOAP

Producer

  1. Generates Classes from an .xsd file.
  2. Provides Web Services via the @EnableWs configuration annotation and @Endpoint handler annotation.
  3. Makes a WSDL accessible to SOAP clients so relevant Classes can be generated client-side.
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="/jaxb/gen"
        xmlns:examples="/jaxb/gen"
        elementFormDefault="qualified">

    <element name="getComplexExampleRequest" type="examples:GetComplexExampleRequest"></element>
    <element name="getComplexExampleResponse" type="examples:GetComplexExampleResponse"></element>
    <element name="complexExample" type="examples:ComplexExample"></element>
    <element name="simpleStringEnumExample" type="examples:SimpleStringEnumExample"></element>

    <complexType name="GetComplexExampleRequest">
        <sequence>
            <element name="exampleId" type="int"/>
        </sequence>
    </complexType>

    <complexType name="GetComplexExampleResponse">
        <sequence>
            <element name="complexExample" type="examples:ComplexExample"/>
            <element name="name" type="string"/>
            <element name="gender" type="string"/>
            <element name="created" type="dateTime"/>
        </sequence>
    </complexType>

    <complexType name="ComplexExample">
        <sequence>
            <element name="exampleId" type="int"/>
            <element name="description" type="string"/>
            <element name="stringEnum" type="examples:SimpleStringEnumExample"/>
        </sequence>
    </complexType>

    <simpleType name="SimpleStringEnumExample">
        <restriction base="string">
            <enumeration value="HELLO"/>
            <enumeration value="SUCCESS"/>
            <enumeration value="FAIL"/>
        </restriction>
    </simpleType>
</schema>
@EnableWs
@Configuration
public class SoapConfig extends WsConfigurerAdapter {

    @Bean
    public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
        MessageDispatcherServlet servlet = new MessageDispatcherServlet();
        servlet.setApplicationContext(applicationContext);
        servlet.setTransformWsdlLocations(true);
        return new ServletRegistrationBean(servlet, "/ws/*");
    }

    @Bean(name = "complexExample")
    public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema exampleSchema) {
        DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
        wsdl11Definition.setPortTypeName("ComplexExamplePort");
        wsdl11Definition.setLocationUri("/ws");
        wsdl11Definition.setTargetNamespace(URI);
        wsdl11Definition.setSchema(exampleSchema);
        return wsdl11Definition;
    }

    @Bean
    public XsdSchema exampleSchema() {
        return new SimpleXsdSchema(new ClassPathResource(XSD));
    }
}
@Slf4j
@Endpoint
public class ComplexExampleEndpoint {

    @Autowired
    ComplexExampleRepository complexExampleRepository;

    @PayloadRoot(namespace = URI, localPart = "getComplexExampleRequest")
    @ResponsePayload
    public GetComplexExampleResponse getCountry(@RequestPayload GetComplexExampleRequest request) {
        GetComplexExampleResponse response = new GetComplexExampleResponse();
        response.setComplexExample(complexExampleRepository.findExample(request.getExampleId()));
        return response;
    }
}

Consumer

  1. Generates Classes client-side by accessing the hosted WSDL.
  2. Invokes calls against the Web Service using the specified WSDL Class schemas.
curl --header "content-type: text/xml" -d @curl-request.xml http://localhost:8080/ws
<!-- curl-request.xml -->
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:examples="https://github.com/Thoughtscript/java_soap_wsdl_2023">
   <soapenv:Header/>
   <soapenv:Body>
      <examples:getComplexExampleRequest>
         <examples:exampleId>1</examples:exampleId>
      </examples:getComplexExampleRequest>
   </soapenv:Body>
</soapenv:Envelope>
  1. https://spring.io/guides/gs/producing-web-service/
  2. https://spring.io/guides/gs/consuming-web-service/
  3. https://github.com/spring-guides/gs-consuming-web-service
  4. https://www.baeldung.com/spring-boot-soap-web-service
  5. https://www.baeldung.com/jaxb

Code samples:

  1. https://github.com/Thoughtscript/java_soap_wsdl_2023

Java: Text Editors

Troubleshooting Major-Minor Versions

  1. Set the correct SDK
    • File > Project Structure > Project Settings > Project > SDK
    • File > Project Structure > Project Settings > Project > Language Level
  2. Check the Platform Settings
    • File > Project Structure > Platform Settings > SDKs
  3. Check the pom.xml
    • <properties>
    • <maven.compiler.source>
    • <maven.compiler.target>
  4. Check the Run and Debug Configurations
    • In the Upper-Right Corner
    • Select the Run/Debug Configurations dropdown > Edit Configurations... > Build and run