Java: General Concepts
- Java Virtual Machine - run Java on any machine or underlying environment.
- Abstracts the Java runtime environment so Java can be executed uniformly anywhere.
- 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.
- 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
.javafiles, compiled Byte Code, and.classfiles- Impure Object Oriented Design - Primitive Data Types don't inherit from the top-level Object Class.
- Reference Types - wrappers for the Primitive Data Types that inherit from the Object Class and therefore can take
nullvalues,.stringify(), etc. - Statically Typed - Types are strictly enforced in Parameters, Arguments, Method Signatures, return Types. Limited Auto-boxing.
Top Java 8 Features
- Lambdas and Functional Interfaces
CompletableFuture- Stream API
Top Features Since Java 8
sealedkeyword- Records
- Virtual Threads
- Better Heap and JVM memory management.
Java: Comparisons
- Primitive Comparison (
==) - used to compare the equivalence of two Primitive Data Types.- Referential comparison.
- 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- some A shoud precede some B0- there's no reason for A not to precede some B1- some B should precede some A
In the example below, a Comparator is implemented as a Lambda to sort Products per the following:
- Sort by
Availability(boolean) descending - If tied, sort by
DiscountedPrice(Double) ascending - 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:
- Parentheses:
(,) - Arithmetic:
+,- - Not:
! - Comparison (Relational) Operators:
<,>,<=,>= - Equality:
==,!= - Logical:
&&,||
Many sites omit some of the above or are inaccurate: https://examples.javacodegeeks.com/java-operator-precedence-example/
Resources and Links
Java: References
- Shallow Copying in Java: set a value without using the
newkeyword for anything that's not a Primitive Data Type. - 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:
- Don't create a new reference in memory (via the
newkeyword) if you just want to modify the value of something you've passed. - Return the exact item you want to return if you intend on reusing a variable.
Container Types
- Container Types (Lists, Arrays, etc.) don't Pass by Reference either.
- 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.
- 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!
Resources and Links
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:
- They don't maintain a Synchronized or common state throughout the Application.
- 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.
- Beans are then Initialized at Run Time.
- Services that use them as a dependency can modify their state, make calls using their methods, etc.
- 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:
- Classes (templates, types, or kinds of things that Objects are or that Objects instantiate)
- 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
Inheritance
Inheritance:
- Classes can be subclassed (e.g. - kinds, kinds of a kind).
- The attributes available on parent Classes or prototypes are available on their children.
- Inheritance occurs via the
extendskeyword. 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:
- Use the
superkeyword to access Superclass properties. - Call
super()to invoke the Superclass constructor (which can be parametized). - Or, use
superto invoke a parent Class method like soCollection.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) {}
- Automatically generates Getters and initializes field values.
- Automatically generates the AllArgs Constructor.
- Can define instance methods and custom Constructors.
- Records cannot use an explicit
extendskeyword:- All Record Classes are
final, so we can’textendit. - All Record Classes implicitly
extendjava.lang.RecordClass.
- All Record Classes are
- All the fields specified in the
recorddeclaration arefinal.
Resources and Links
- https://www.toptal.com/java/interview-questions
- https://www.javatpoint.com/static-nested-class
- https://www.geeksforgeeks.org/association-composition-aggregation-java/
- https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
- https://www.digitalocean.com/community/tutorials/java-records-class
Code samples:
- https://github.com/Thoughtscript/java-refresh-notes/tree/master/src/io/thoughtscript/refresh/ood
- https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/Main.java
- 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:
- Fields
- Methods
- Constructors
within Enums.
As such one can also implement Singletons.
Resources and Links
Code samples:
Java: Dynamic Proxying
Java Proxy Classes (Java Proxies):
- Are encouraged in Clean Code.
- Can be thought of as a Facade (a Wrapper with additional functionality to simplify use).
- Often target some range of Interface implemenations.
- Used to invoke or execute some additonal operation or imbue an operation with extra functionalities. (Additional logging, intercepting a method (via
InvocationHandler), etc.)
Resources and Links
Java: Abstraction
- Interfaces and Abstract Classes allow for the general structure of Implementing Classes to be planned out and further specified in those implementations.
- Interfaces are lighter-weight and impose fewer suppositions on implementing Classes than Subclasses of Abstract Classes.
- Abstract Classes typically contain fully-defined Methods that are then Overridden whereas Interfaces only contain Method signatures.
- Both Interfaces and Abstract Classes can have fields defined within them that are borne by their Implementing or Subclassing Classes.
Interface
- Interfaces support Multiple Inheritance (whereas Classes don't).
- Methods defined in Interfaces are Public and Abstract by default. Typically, only their signature is defined.
- Are Implemented or Extended with the
implementsorextendskeywords, respectively. - Fields defined in an Interface are
public static finalby 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"));
}
}
@FunctionalInterfacemust 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
- Abstract Classes are not themselves instantiated (although they can contain a Constructor) - they are Subclassed and instantiated thereby.
- Methods belonging to an Abstract Class can be Abstract and they can be Overridden.
- Abstract Classes are Subclassed using the
extendskeyword and their methods are Overridden using the@Overrideannotation.
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;
}
}
Resources and Links
Code samples:
Java: Visibility and Access Modifiers
Access Modifiers
public- Everywhere within the Application, all Subclasses.protected- Same Package, Subclasses regardless of Package.package/none/default - Same Package, Subclasses in same Package.private- Class and Object only, no Subclasses.
Static vs Nonstatic
static- belongs to the Class within which it resides.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
newand are invoked directly from that created Object.
Final
- The
finalkeyword specifies that a variable is immutable, a constant. - The
finalkeyword specifies that a method cannot be Overridden. - The
finalkeyword 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.
An optional and potentially intermediate access visibility modifier-like keyword.
Specifies the exact Subclasses that can Subclass. (Even the Default/
Packagecan be unduly permissive – consider Classes that have encryption hashes/ciphers/salts.)Or, Classes that can
implementan Interface.sealedClass constraints:- Permitted Subclasses must belong to the same module as the
sealedClass. - Every permitted Subclass must explicitly extend the
sealedClass. - Every permitted Subclass must define a modifier:
final,sealed, ornon-sealed.
- Permitted Subclasses must belong to the same module as the
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
finalconcrete Classes or arenon-sealed. - If a leaf element is
non-sealed, it can be either a Class or an Interface.
- The remainder of the hierarchy can contain Classes or Interfaces, provided all leaf nodes of the hierarchy are either
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
- https://blogs.oracle.com/javamagazine/post/java-comments-reduce-technical-debt
- https://google.github.io/styleguide/javaguide.html#s3-source-file-structure
Resources and Links
- https://blogs.oracle.com/javamagazine/post/java-comments-reduce-technical-debt
- https://google.github.io/styleguide/javaguide.html#s3-source-file-structure
- https://blogs.oracle.com/javamagazine/post/java-sealed-types-subtypes-final
- https://blogs.oracle.com/javamagazine/post/java-quiz-sealed-type-records
- https://www.baeldung.com/java-sealed-classes-interfaces
Code samples:
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:
ArrayIndexOutOfBoundsExceptionis Unchecked.NullPointerExceptionis Unchecked.- 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 "";
}
}
}
- One might be tempted to think the compiler refuses to compile since
FuelExceptionisn't caught. However, the presence of thefinallyclause overrules that typical requirement. - One might also be tempted to think that
"BadBattery"is returned orFuelExceptionis thrown fromstart(). Again, the presence of thefinallyclause overrules that incorrect but informed intution. (Regardless of the implementation ofcheckBattery()andcheckFuel()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
Resources and Links
Code samples:
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);
Resources and Links
- https://www.tutorialkart.com/java/java-array/java-concatenate-arrays/
- https://dev.to/khmarbaise/stream-concat-vs-new-arraylist-performance-within-a-stream-4ial
- https://www.geeksforgeeks.org/serial-sort-vs-parallel-sort-java/
- https://www.baeldung.com/java-arrays-sort-vs-parallelsort
- https://www.baeldung.com/java-collection-toarray-methods
Code samples:
Java: Collections
- 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");
indexOf()is aListmethod not available on Arrays (without conversion).- Use
LinkedListfor 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:
- https://www.baeldung.com/java-immutable-list
- https://github.com/Thoughtscript/java-refresh-notes/blob/master/src/io/thoughtscript/refresh/lists/ListExamples.java
- 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
- Java Collections
HashMapis a basic implementation ofMap. - 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 thecapacity(not to be confused with the number of Keys or Values). - It accepts
nullas a Key and isn't Thread Safe. - Keep the Key range small to avoid unnecessarily large buckets in-memory.
- 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
HashSethas Objects as Values that are hashed into Keys using a backingHashMap. This guarantees uniqueness/deduplication.
Resources and Links
- https://www.baeldung.com/category/java/java-collections
- https://www.baeldung.com/java-hashmap
- https://www.baeldung.com/java-immutable-list
- https://blogs.oracle.com/javamagazine/post/java-lists-view-unmodifiable-immutable
Code samples:
Java: Streams
Streams are:
Immutable
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:
- Doing so does not modify the outcome or result of the computation.
- 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:
- https://docs.oracle.com/javase/10/docs/api/java/util/stream/Stream.html
- https://blogs.oracle.com/javamagazine/post/java-quiz-stream-api-side-effects
Resources and Links
- https://www.baeldung.com/java-when-to-use-parallel-stream
- https://howtodoinjava.com/java/stream/java-streams-by-examples/
- https://www.geeksforgeeks.org/arrays-stream-method-in-java/
- https://www.baeldung.com/java-collection-stream-foreach
- https://blogs.oracle.com/javamagazine/post/java-quiz-generics-primitives-autoboxing
- https://docs.oracle.com/javase/10/docs/api/java/util/stream/Stream.html
- https://blogs.oracle.com/javamagazine/post/java-quiz-stream-api-side-effects
Code samples:
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:
Stringsare essentially Reference Types withcharas their corresponding Primitive Type. Note further:charhasCharacteras 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
intcan't support precise fractional division without rounding, using aString, or some LCD algo (Least Common Denominator).
Java: Strings, StringBuffer, StringBuilder
- Java Strings use the String Pool, are immutable, and are Primitive Data Types.
StringBuilderdoes not use Java's String Pool, isn't Thread Safe, and is better (performance and memory-wise) for concatenating complex and lengthy Strings. (StringBuilderis used automatically under the hood now for simple String concatenations likeString c = a + b + ":".)StringBufferis the Thread Safe version ofStringBuilder.
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
-Xand-XXaffixes 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:
- Inefficient from a time-complexity standpoint.
- The underlying implementation (automatic conversion between
+andStringBuilder) is imperfectly performant for large cases. - 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
Resources and Links
Java: Important Keywords
final- can't be changed as a variable, can't be Overridden as a method, and can't be subclassed as a Class.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.) staticblock allows for multiline initializations ofstaticClass Variables.
sealed- specifies that only certain Classes can inherit from orimplementfrom thesealedClass or Interface.abstract- on a Class: canextendbut not instantiate, can Override methods of the inherited Abstract Class.synchronized- enforce thread safety within the specified Object or Class.transient- ignore value, set a default value, and save or read from a serialized file.record- syntactic sugar to specify an immutable POJO / DTO.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.)
Resources and Links
- https://blogs.oracle.com/javamagazine/post/java-record-instance-method
- https://blogs.oracle.com/javamagazine/post/java-quiz-sealed-type-records
- https://www.baeldung.com/java-sealed-classes-interfaces
- https://www.digitalocean.com/community/tutorials/java-records-class
- https://blogs.oracle.com/javamagazine/post/java-sealed-types-subtypes-final
- https://www.baeldung.com/java-static
- https://www.baeldung.com/java-volatile
Code Samples:
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
- https://owasp.org/www-project-dependency-check/
- https://snyk.io/lp/java-snyk-code-checker/
- https://www.azul.com/
Resources and Links
Java: Generics
Generics abstract or generalize a method so that the specific details of the argument types are not required.
- Where Types or Classes are Parameters and/or Variables.
- Used to represent relationships between Classes and Subclasses that must hold (Type constraint).
- Used to express general relationships between Classes and Subclasses.
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);
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
Resources and Links
- https://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html
- https://www.geeksforgeeks.org/java-net-urlconnection-class-in-java/
- https://www.digitalocean.com/community/tutorials/javamail-example-send-mail-in-java-smtp
- https://www.baeldung.com/java-slicing-arrays
- https://www.geeksforgeeks.org/java-comparator-interface/
Java: Asynchronous Programming
Java Threads
- Java Threading is mapped to underlying System Threads by default (logical or physical CPU cores).
- Java Threads can be pooled to help ensure that the application's needs don't overwhelm the available physical resources.
- Java Thread Pooling relies heavily on the
ExecutorsandRunnableimplementations:Runnable- implementations ofRunnablecan be passed intoExecutorsto 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
Futures- Blocking.
- Can't combine results from more than one Thread.
CompletableFutures- Added in Java 8 and significantly improved in Java 9.
- Chainable methods allow for JavaScript Promise-like
resolve(),reject(), andpromiseAll()behavior. - Can combine results from multiple Threads.
- Non-blocking.
Asynchronous Promises
- 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
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.
- Atomic Objects have inherently Synchronized values.
- Refer to the article on Thread-Safe Singletons.
- Refer to the article on Computer Science Processes and Threads.
- Java provides
SemaphoresandLocks:ReentrantLocksallow a single Thread to (re)access a resource at a time.Semaphoresallow a specified number of Threads to share access to a resource at any given time.
Wait()vsSleep():Wait()- belongs toObject, Non-Static, should only be called from aSynchronizedcontext.Sleep()- belongs toThread, Static,
Resources and Links
Java: SOAP
Producer
- Generates Classes from an
.xsdfile. - Provides Web Services via the
@EnableWsconfiguration annotation and@Endpointhandler annotation. - 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
- Generates Classes client-side by accessing the hosted WSDL.
- 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>
Resources and Links
- https://spring.io/guides/gs/producing-web-service/
- https://spring.io/guides/gs/consuming-web-service/
- https://github.com/spring-guides/gs-consuming-web-service
- https://www.baeldung.com/spring-boot-soap-web-service
- https://www.baeldung.com/jaxb
Code samples:
Java: Text Editors
Troubleshooting Major-Minor Versions
- Set the correct SDK
- File > Project Structure > Project Settings > Project > SDK
- File > Project Structure > Project Settings > Project > Language Level
- Check the Platform Settings
- File > Project Structure > Platform Settings > SDKs
- Check the
pom.xml<properties><maven.compiler.source><maven.compiler.target>
- Check the Run and Debug Configurations
- In the Upper-Right Corner
- Select the Run/Debug Configurations dropdown > Edit Configurations... > Build and run