Skip to content

10x-Backend-Engineer/learn-java

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

Learn Java

Welcome to the comprehensive Java course. Java is a versatile, object-oriented programming language.

Table of contents

What is Java?

Java is a high-level, class-based, object-oriented programming language designed to have as few implementation dependencies as possible.

Key Characteristics

  • Platform Independent: "Write Once, Run Anywhere"
  • Object-Oriented: Everything is an object
  • Strongly Typed: Compile-time type checking
  • Garbage Collection: Automatic memory management
  • Multithreaded: Built-in support for concurrent programming
  • Secure: No pointer arithmetic

Why learn Java?

1. Enterprise Applications

Java is the language of choice for enterprise software.

2. Android Development

Java and Kotlin are primary languages for Android.

3. Web Applications

Spring framework powers millions of applications.

4. Big Data

Hadoop and Spark are built with Java.

5. Career Opportunities

High demand in job market.

Installation and Setup

JDK Installation

Download from oracle.com or use Adoptium:

java --version
javac --version

IDE Options

  • IntelliJ IDEA - Most popular
  • Eclipse - Feature-rich
  • VS Code - Lightweight with extensions
  • NetBeans - Free and open source

Creating a Project

mkdir MyProject && cd MyProject
mkdir -p src/main/java/com/example

Running Java

javac MyClass.java
java MyClass

Maven/Gradle

<!-- pom.xml (Maven) -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

Hello World

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

Modern Java (14+) multiline strings:

String message = """
    This is a
    multiline
    string
    """;

Variables and Data Types

Primitive Types

// Integers
byte b = 127;              // 8-bit
short s = 32767;          // 16-bit
int i = 2147483647;       // 32-bit
long l = 9223372036854775807L;  // 64-bit

// Floating point
float f = 3.14f;          // 32-bit (suffix f)
double d = 3.14159;       // 64-bit

// Characters
char c = 'A';

// Booleans
boolean flag = true;

Reference Types

String name = "John";
Integer wrapped = 42;
Object obj = new Object();

Type Inference (var)

var name = "John";        // Compiler infers String
var age = 30;             // Compiler infers int
var list = new ArrayList<String>();

Constants

final double PI = 3.14159;
final int MAX_SIZE = 100;

Default Values

int i = 0;                // 0
boolean b = false;        // false
char c = '\u0000';        // null character
double d = 0.0;           // 0.0
String s = null;          // null

Operators

Arithmetic

int a = 10, b = 3;

System.out.println(a + b);   // 13
System.out.println(a - b);   // 7
System.out.println(a * b);   // 30
System.out.println(a / b);   // 3 (integer division)
System.out.println(a % b);    // 1 (modulus)

Comparison

System.out.println(5 == 5);   // true
System.out.println(5 != 3);   // true
System.out.println(5 > 3);    // true
System.out.println(5 >= 5);   // true
System.out.println(5 < 3);    // false
System.out.println(5 <= 5);   // true

Logical

System.out.println(true && false);  // false
System.out.println(true || false);  // true
System.out.println(!true);          // false

Bitwise

System.out.println(5 & 3);   // 1
System.out.println(5 | 3);   // 7
System.out.println(5 ^ 3);   // 6
System.out.println(~5);      // -6
System.out.println(4 << 1);  // 8
System.out.println(4 >> 1);  // 2
System.out.println(4 >>> 1); // 2

Ternary

int age = 20;
String status = age >= 18 ? "Adult" : "Minor";

Flow Control

If/Else

int score = 85;

if (score >= 90) {
    System.out.println("A grade");
} else if (score >= 80) {
    System.out.println("B grade");
} else if (score >= 70) {
    System.out.println("C grade");
} else {
    System.out.println("Need improvement");
}

Switch

String day = "Monday";

switch (day) {
    case "Monday":
    case "Tuesday":
    case "Wednesday":
    case "Thursday":
    case "Friday":
        System.out.println("Weekday");
        break;
    case "Saturday":
    case "Sunday":
        System.out.println("Weekend");
        break;
    default:
        System.out.println("Invalid day");
}

Switch Expression (Java 14+)

String result = switch (day) {
    case "Saturday", "Sunday" -> "Weekend";
    case "Monday" -> "Start of work week";
    default -> "Weekday";
};

For Loop

for (int i = 0; i < 5; i++) {
    System.out.println(i);
}

// Enhanced for loop
String[] fruits = {"Apple", "Banana", "Cherry"};
for (String fruit : fruits) {
    System.out.println(fruit);
}

While Loop

int count = 0;
while (count < 5) {
    System.out.println(count);
    count++;
}

// Do-while
int i = 0;
do {
    System.out.println(i);
    i++;
} while (i < 5);

Loop Control

for (int i = 0; i < 10; i++) {
    if (i == 5)
        break;       // Exit loop
    if (i == 2)
        continue;    // Skip iteration
    System.out.println(i);
}

Methods

Basic Method

public static String greet(String name) {
    return "Hello, " + name + "!";
}

Parameters

// Variable arguments
public static int sum(int... numbers) {
    int total = 0;
    for (int n : numbers) {
        total += n;
    }
    return total;
}

// Method overloading
public static int add(int a, int b) {
    return a + b;
}

public static double add(double a, double b) {
    return a + b;
}

Return Types

public static boolean isEven(int n) {
    return n % 2 == 0;
}

public static void printMessage(String msg) {
    System.out.println(msg);
}

Recursion

public static int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

Static vs Instance

public class MathHelper {
    public static int add(int a, int b) {  // Static
        return a + b;
    }
    
    public int multiply(int a, int b) {    // Instance
        return a * b;
    }
}

// Usage
int sum = MathHelper.add(1, 2);
MathHelper helper = new MathHelper();
int product = helper.multiply(3, 4);

Strings

Creating Strings

String s1 = "Hello";
String s2 = new String("Hello");
String s3 = """
    Multi-line
    string
    """;

String Methods

String s = "  Hello, World!  ";

s.trim()                 // "Hello, World!"
s.strip()                // "Hello, World!" (Unicode aware)
s.toUpperCase()          // "  HELLO, WORLD!  "
s.toLowerCase()          // "  hello, world!  "
s.replace("World", "Java")
s.replaceAll("\\s+", " ") // Regex replace
s.split(",")             // ["  Hello", " World!  "]
s.contains("Hello")       // true
s.startsWith("  H")      // true
s.endsWith("!  ")        // true
s.indexOf("World")       // 9
s.substring(2, 7)       // "Hello"
s.charAt(0)              // ' '
s.length()               // 16

StringBuilder

StringBuilder sb = new StringBuilder();

sb.append("Hello");
sb.append(" World");
sb.insert(5, " there");
sb.delete(5, 11);
sb.replace(0, 5, "Hi");
sb.reverse();
sb.setLength(0);

String result = sb.toString();

String Formatting

String name = "John";
int age = 30;

// printf
System.out.printf("Name: %s, Age: %d%n", name, age);

// formatted
String s = String.format("Name: %s, Age: %d", name, age);

// Text blocks (Java 15+)
String json = """
    {
        "name": "John",
        "age": 30
    }
    """;

String Pool

String s1 = "Hello";        // Uses string pool
String s2 = "Hello";        // Same reference
String s3 = new String("Hello");  // New object

System.out.println(s1 == s2);   // true
System.out.println(s1 == s3);   // false
System.out.println(s1.equals(s3));  // true

Arrays

Creating Arrays

int[] numbers = {1, 2, 3, 4, 5};
int[] zeros = new int[5];      // All zeros
String[] names = new String[]{"John", "Jane"};

// Multi-dimensional
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6}
};

int[][][] cube = new int[2][3][4];

Array Methods

int[] arr = {5, 2, 8, 1, 9};

Arrays.sort(arr);
Arrays.sort(arr, 1, 4);  // Partial sort
Arrays.fill(arr, 0);      // Fill all
Arrays.copyOf(arr, 10);   // Copy with new size
Arrays.equals(arr1, arr2);
Arrays.binarySearch(arr, 5);

int idx = Arrays.binarySearch(arr, 5);

Arrays Utility

import java.util.Arrays;

String[] names = {"Charlie", "Alice", "Bob"};
Arrays.sort(names);
Arrays.sort(names, Collections.reverseOrder());

int[][] matrix = new int[3][4];
Arrays.fill(matrix, 0);

ArrayList

Creating ArrayList

import java.util.ArrayList;

ArrayList<String> list = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>(20);
ArrayList<String> list3 = new ArrayList<>(Arrays.asList("A", "B", "C"));

ArrayList Methods

ArrayList<String> list = new ArrayList<>();

list.add("Apple");        // Add to end
list.add(0, "Banana");    // Insert at index
list.addAll(Arrays.asList("Cherry", "Date"));

list.set(0, "Blueberry"); // Update
String first = list.get(0);
list.remove(0);           // Remove at index
list.remove("Apple");     // Remove by value
list.clear();             // Remove all

boolean exists = list.contains("Date");
int idx = list.indexOf("Cherry");
int size = list.size();
boolean empty = list.isEmpty();

list.sort(Comparator.naturalOrder());
list.sort(Comparator.reverseOrder());

Converting

ArrayList<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));

// To array
String[] arr = list.toArray(new String[0]);
String[] arr2 = list.toArray(String[]::new);

// To collection
List<String> list2 = new ArrayList<>(list);

LinkedList

Creating LinkedList

import java.util.LinkedList;

LinkedList<String> list = new LinkedList<>();
LinkedList<Integer> numbers = new LinkedList<>();

LinkedList Methods

LinkedList<String> list = new LinkedList<>();

list.add("First");
list.addFirst("Start");
list.addLast("End");
list.offer("Offered");     // Add at end
list.push("Pushed");       // Add at front

String first = list.getFirst();
String last = list.getLast();
String removed = list.removeFirst();
String polled = list.poll();       // Remove and return null if empty
String peeked = list.peek();        // View without removing

ArrayList vs LinkedList

// ArrayList - Fast random access, slow insertions/removals
ArrayList<String> arrayList = new ArrayList<>();

// LinkedList - Fast insertions/removals, slow random access
LinkedList<String> linkedList = new LinkedList<>();

HashMap

Creating HashMap

import java.util.HashMap;

HashMap<String, Integer> map = new HashMap<>();
HashMap<String, Integer> map2 = new HashMap<>(16, 0.75f);
HashMap<String, Integer> map3 = new HashMap<>(Map.of("A", 1, "B", 2));

HashMap Methods

HashMap<String, Integer> map = new HashMap<>();

map.put("One", 1);
map.putIfAbsent("Two", 2);
map.putAll(Map.of("Three", 3, "Four", 4));

Integer value = map.get("One");
Integer valueOrDefault = map.getOrDefault("Five", 0);

map.remove("One");
map.clear();

boolean exists = map.containsKey("Two");
boolean hasValue = map.containsValue(2);
int size = map.size();
boolean empty = map.isEmpty();

map.replace("Two", 2, 3);  // Conditional replace

Iterating

HashMap<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);

// Keys
for (String key : map.keySet()) {
    System.out.println(key);
}

// Values
for (Integer val : map.values()) {
    System.out.println(val);
}

// Entries
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

// Lambda
map.forEach((k, v) -> System.out.println(k + ": " + v));

HashSet

Creating HashSet

import java.util.HashSet;

HashSet<String> set = new HashSet<>();
HashSet<Integer> numbers = new HashSet<>(Arrays.asList(1, 2, 3));

HashSet Methods

HashSet<String> set = new HashSet<>();

set.add("Apple");
set.addAll(Arrays.asList("Banana", "Cherry"));
set.remove("Apple");
set.clear();

boolean exists = set.contains("Banana");
int size = set.size();
boolean empty = set.isEmpty();

Set Operations

HashSet<Integer> a = new HashSet<>(Arrays.asList(1, 2, 3, 4));
HashSet<Integer> b = new HashSet<>(Arrays.asList(3, 4, 5, 6));

a.addAll(b);              // Union
a.retainAll(b);           // Intersection
a.removeAll(b);           // Difference

// New sets
Set<Integer> union = new HashSet<>(a);
union.addAll(b);

Set<Integer> intersection = new HashSet<>(a);
intersection.retainAll(b);

Set<Integer> difference = new HashSet<>(a);
difference.removeAll(b);

Classes and Objects

Basic Class

public class Person {
    // Fields
    private String name;
    private int age;
    
    // Constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // Getters and Setters
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    
    // Method
    public String greet() {
        return "Hello, I'm " + name;
    }
    
    // toString
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

// Usage
Person p = new Person("John", 30);
p.greet();

Records (Java 16+)

public record Person(String name, int age) {
    // Auto-generates:
    // - All fields
    // - Canonical constructor
    // - toString, equals, hashCode
    // - getter methods (name(), age())
    
    // Custom compact constructor
    public Person {
        if (age < 0) throw new IllegalArgumentException();
    }
}

// Usage
Person p = new Person("John", 30);
p.name();  // "John"
p.age();   // 30

Encapsulation

public class BankAccount {
    private double balance;
    
    public double getBalance() { return balance; }
    
    public void deposit(double amount) {
        if (amount > 0) balance += amount;
    }
    
    public boolean withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            return true;
        }
        return false;
    }
}

Static Members

public class MathUtils {
    public static final double PI = 3.14159;
    
    public static int add(int a, int b) {
        return a + b;
    }
    
    static {
        // Static initializer
    }
}

// Usage
int sum = MathUtils.add(1, 2);
double pi = MathUtils.PI;

Nested Classes

public class Outer {
    private String outerField = "Outer";
    
    public class Inner {
        private String innerField = "Inner";
        
        public void display() {
            System.out.println(outerField);  // Can access outer
        }
    }
    
    public static class StaticNested {
        // Cannot access outer instance
    }
}

Inheritance

Basic Inheritance

public class Animal {
    protected String name;
    
    public Animal(String name) {
        this.name = name;
    }
    
    public void speak() {
        System.out.println("...");
    }
}

public class Dog extends Animal {
    private String breed;
    
    public Dog(String name, String breed) {
        super(name);  // Call parent constructor
        this.breed = breed;
    }
    
    @Override
    public void speak() {
        System.out.println("Woof!");
    }
}

super Keyword

public class Child extends Parent {
    public Child() {
        super();           // Call parent constructor
    }
    
    public void method() {
        super.parentMethod();  // Call parent method
    }
}

Method Overriding

public class Parent {
    public void display() { }
}

public class Child extends Parent {
    @Override
    public void display() { }  // Must have same signature
    
    @Override
    public final void fixed() { }  // Cannot override
}

Sealed Classes (Java 17+)

public sealed class Shape permits Circle, Rectangle, Square {
}

public final class Circle extends Shape { }
public sealed class Rectangle extends Shape permits ColoredRectangle { }
public non-sealed class Square extends Shape { }

Interfaces

Basic Interface

public interface Drawable {
    void draw();  // Abstract method
    
    // Java 8+: Default method
    default void print() {
        System.out.println("Printing...");
    }
    
    // Java 8+: Static method
    static void reset() {
        System.out.println("Reset");
    }
}

Implementing Interface

public class Circle implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing circle");
    }
}

// Multiple interfaces
public class Button implements Clickable, Focusable {
    @Override
    public void click() { }
    
    @Override
    public void focus() { }
}

Functional Interface

@FunctionalInterface
public interface Converter<T, R> {
    R convert(T input);
    
    // Can have default methods
    default void log(String msg) {
        System.out.println(msg);
    }
}

// Usage with lambda
Converter<String, Integer> converter = Integer::parseInt;

Interface Inheritance

public interface A {
    void methodA();
}

public interface B extends A {
    void methodB();
}

Abstract Classes

Basic Abstract Class

public abstract class Shape {
    protected String color;
    
    public Shape(String color) {
        this.color = color;
    }
    
    // Abstract method - must be implemented
    public abstract double getArea();
    
    // Concrete method
    public String getColor() {
        return color;
    }
}

public class Circle extends Shape {
    private double radius;
    
    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }
    
    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

Abstract vs Interface

// Use abstract class when:
// - Sharing code/state between related classes
// - Need constructors
// - Non-static fields

// Use interface when:
// - Define capabilities/contracts
// - Multiple inheritance needed
// - Lambda expressions (functional interfaces)

Records

Basic Record

public record Person(String name, int age) { }

// Auto-generates:
// - private final fields
// - Canonical constructor
// - toString(), equals(), hashCode()
// - name(), age() getter methods

Person p = new Person("John", 30);
p.name();  // "John"
p.age();   // 30

Record with Validation

public record Person(String name, int age) {
    public Person {
        if (age < 0) throw new IllegalArgumentException();
        name = name.strip();
    }
}

Record with Methods

public record Range(int start, int end) {
    public Range {
        if (start > end) {
            throw new IllegalArgumentException();
        }
    }
    
    public int getSize() {
        return end - start;
    }
    
    public boolean contains(int value) {
        return value >= start && value <= end;
    }
}

Enums

Basic Enum

public enum Day {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}

// Usage
Day today = Day.MONDAY;
String name = today.name();
int ordinal = today.ordinal();

Enum with Values

public enum Status {
    SUCCESS(200, "Success"),
    ERROR(500, "Error"),
    NOT_FOUND(404, "Not Found");
    
    private final int code;
    private final String message;
    
    Status(int code, String message) {
        this.code = code;
        this.message = message;
    }
    
    public int getCode() { return code; }
    public String getMessage() { return message; }
    
    public static Status fromCode(int code) {
        for (Status s : values()) {
            if (s.code == code) return s;
        }
        return null;
    }
}

Enum Methods

enum Season {
    SPRING, SUMMER, AUTUMN, WINTER;
    
    public boolean isWarm() {
        return this == SUMMER || this == SPRING;
    }
}

Exception Handling

Try/Catch/Finally

try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("Cannot divide by zero: " + e.getMessage());
} catch (Exception e) {
    System.out.println("Error: " + e);
} finally {
    System.out.println("Always executes");
}

Try with Resources (Java 7+)

try (FileReader reader = new FileReader("file.txt");
     BufferedReader br = new BufferedReader(reader)) {
    
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}  // Auto-closes resources

Throwing Exceptions

public void validateAge(int age) throws IllegalArgumentException {
    if (age < 0) {
        throw new IllegalArgumentException("Age cannot be negative");
    }
}

Custom Exceptions

public class ValidationException extends Exception {
    private final String field;
    
    public ValidationException(String field, String message) {
        super(message);
        this.field = field;
    }
    
    public String getField() { return field; }
}

Exception Hierarchy

Throwable
├── Error (system errors)
│   ├── OutOfMemoryError
│   └── StackOverflowError
└── Exception
    ├── RuntimeException (unchecked)
    │   ├── NullPointerException
    │   ├── IllegalArgumentException
    │   └── IndexOutOfBoundsException
    └── IOException, SQLException (checked)

File Handling

Reading Files

import java.nio.file.*;
import java.io.*;

try (BufferedReader reader = Files.newBufferedReader(Paths.get("file.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
}

Writing Files

import java.nio.file.*;

String content = "Hello, World!";
Files.writeString(Paths.get("output.txt"), content);

List<String> lines = Arrays.asList("Line 1", "Line 2");
Files.write(Paths.get("output.txt"), lines);

File Operations

Path path = Paths.get("document.pdf");

boolean exists = Files.exists(path);
boolean isFile = Files.isRegularFile(path);
boolean isDir = Files.isDirectory(path);

long size = Files.size(path);
FileTime created = Files.getAttribute(path, "creationTime");
FileTime modified = Files.getLastModifiedTime(path);

Files.copy(from, to);
Files.move(from, to);
Files.delete(path);
Files.createDirectory(path);
Files.walk(path).forEach(System.out::println);

Lambda Expressions

Basic Syntax

// Traditional
Comparator<String> comp = new Comparator<>() {
    @Override
    public int compare(String a, String b) {
        return a.compareTo(b);
    }
};

// Lambda
Comparator<String> comp = (a, b) -> a.compareTo(b);

// Single parameter, can omit parentheses
Function<String, Integer> parser = s -> Integer.parseInt(s);

// Block body
Function<String, Integer> parser = s -> {
    int result = Integer.parseInt(s);
    return result;
};

Method Reference

// Static method
Function<String, Integer> parser = Integer::parseInt;

// Instance method
String str = "hello";
Supplier<Integer> len = str::length;

// Arbitrary instance method
Function<String, String> upper = String::toUpperCase;

// Constructor
Supplier<ArrayList<String>> listFactory = ArrayList::new;
Function<Integer, String[]> arrayFactory = String[]::new;

Common Functional Interfaces

Predicate<String> isEmpty = s -> s.isEmpty();
Function<String, Integer> length = String::length;
Consumer<String> printer = System.out::println;
Supplier<String> supplier = () -> "default";
UnaryOperator<String> upper = String::toUpperCase;
BinaryOperator<Integer> add = Integer::sum;

Streams API

Creating Streams

import java.util.stream.*;

// From collection
list.stream();
list.parallelStream();

// From array
Arrays.stream(array);

// From values
Stream.of("a", "b", "c");

// Infinite stream
Stream.iterate(0, n -> n + 2).limit(10);
Stream.generate(() -> Math.random()).limit(5);

Intermediate Operations

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

numbers.stream()
    .filter(n -> n % 2 == 0)      // Filter
    .map(n -> n * 2)              // Transform
    .distinct()                    // Remove duplicates
    .sorted()                      // Sort
    .sorted(Comparator.reverseOrder())
    .limit(3)                      // Take first n
    .skip(2)                       // Skip first n
    .peek(System.out::println)     // Debug

Terminal Operations

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

numbers.stream()
    .forEach(System.out::println)      // Execute for each
    .collect(Collectors.toList())       // To collection
    .toArray()                          // To array
    .reduce(0, Integer::sum)            // Reduce to single value
    .count()                             // Count elements
    .anyMatch(n -> n > 3)                // Any match
    .allMatch(n -> n > 0)                 // All match
    .noneMatch(n -> n < 0)                // None match
    .findFirst()                         // First element
    .findAny()                           // Any element
    .min(Comparator.naturalOrder())      // Minimum
    .max(Comparator.naturalOrder())      // Maximum

Collectors

.collect(Collectors.toList())
.collect(Collectors.toSet())
.collect(Collectors.toMap(k, v))
.collect(Collectors.toCollection(TreeSet::new))
.collect(Collectors.joining(", "))
.collect(Collectors.counting())
.collect(Collectors.summingInt(n -> n))
.collect(Collectors.averagingInt(n -> n))
.collect(Collectors.groupingBy(Function.identity()))
.collect(Collectors.partitioningBy(predicate))
.collect(Collectors.mapping(mapper, downstream))

Optional

Creating Optional

Optional<String> empty = Optional.empty();
Optional<String> of = Optional.of("value");
Optional<String> nullable = Optional.ofNullable(null);

Optional Methods

Optional<String> opt = Optional.of("hello");

opt.isPresent();                    // true
opt.isEmpty();                      // false
opt.get();                          // "hello"
opt.orElse("default");              // "hello"
opt.orElseGet(() -> "computed");    // Lazy default
opt.orElseThrow();                  // Throw NoSuchElementException

opt.ifPresent(System.out::println);
opt.ifPresentOrElse(
    System.out::println,
    () -> System.out.println("Empty")
);

// Transform
opt.map(String::toUpperCase);
opt.filter(s -> s.length() > 3);
opt.flatMap(opt -> Optional.of(opt.toLowerCase()));

Optional in Streams

list.stream()
    .filter(Objects::nonNull)
    .findFirst()
    .orElse("default");

Generics

Generic Class

public class Box<T> {
    private T content;
    
    public void set(T content) { this.content = content; }
    public T get() { return content; }
}

Box<Integer> intBox = new Box<>();
intBox.set(42);
Integer value = intBox.get();

Generic Method

public static <T> void printArray(T[] array) {
    for (T element : array) {
        System.out.println(element);
    }
}

Integer[] nums = {1, 2, 3};
String[] names = {"A", "B"};
printArray(nums);
printArray(names);

Generic Constraints

// Must be Comparable
public static <T extends Comparable<T>> T max(T a, T b) {
    return a.compareTo(b) > 0 ? a : b;
}

// Must be Number or subclass
public static double sum(List<? extends Number> list) {
    return list.stream()
        .mapToDouble(Number::doubleValue)
        .sum();
}

// Producer extends, consumer super (PECS)
public void addAll(List<? extends E> from, List<? super E> to) {
    to.addAll(from);
}

Wildcards

List<?> anyList = new ArrayList<String>();  // Unknown
List<? extends Number> numbers = new ArrayList<Integer>();  // Upper bound
List<? super Integer> integers = new ArrayList<Number>();  // Lower bound

Annotations

Built-in Annotations

@Override           // Override from superclass/interface
@Deprecated        // Mark as deprecated
@SuppressWarnings  // Suppress compiler warnings
@FunctionalInterface  // Must be single abstract method
@SafeVarargs       // Varargs are safe

Custom Annotation

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Author {
    String name();
    String date();
    String version() default "1.0";
}

@Author(name = "John", date = "2024-01-01")
public class MyClass { }

Reflection with Annotations

Method[] methods = MyClass.class.getMethods();
for (Method m : methods) {
    if (m.isAnnotationPresent(Author.class)) {
        Author author = m.getAnnotation(Author.class);
        System.out.println(author.name());
    }
}

Multithreading

Creating Threads

// Extend Thread
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Running in thread");
    }
}

MyThread t = new MyThread();
t.start();

// Implement Runnable
Runnable r = () -> System.out.println("Running via Runnable");
new Thread(r).start();

ExecutorService

ExecutorService executor = Executors.newFixedThreadPool(4);

Future<Integer> future = executor.submit(() -> {
    // Task
    return 42;
});

Integer result = future.get();  // Blocking
executor.shutdown();

Synchronization

// Synchronized method
public synchronized void increment() { count++; }

// Synchronized block
public void increment() {
    synchronized (this) {
        count++;
    }
}

// ReentrantLock
private final ReentrantLock lock = new ReentrantLock();
public void increment() {
    lock.lock();
    try {
        count++;
    } finally {
        lock.unlock();
    }
}

CompletableFuture

CompletableFuture<String> future = CompletableFuture
    .supplyAsync(() -> "Hello")
    .thenApply(s -> s + " World")
    .thenApply(String::toUpperCase);

String result = future.join();

Modules

Module Declaration

// module-info.java
module com.example.myapp {
    requires java.base;
    requires transitive org.apache.commons.lang3;
    
    exports com.example.myapp.api;
    exports com.example.myapp.model;
    
    opens com.example.myapp.internal to com.example.other;
}

Using Modules

module com.example.myapp {
    requires com.example.library;
    
    uses com.example.library.Service;  // Service lookup
}

Next Steps

Now that you know Java fundamentals:

  • Learn Spring Framework for web development
  • Explore Spring Boot for quick application setup
  • Build REST APIs with Spring MVC
  • Learn Hibernate for database operations
  • Explore microservices with Spring Cloud
  • Study design patterns

References

About

A Comprehensive Java course

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors