1. Java Data Types and Variables
Introduction:
Java is a strongly typed, object-oriented, platform-independent language.
Every variable must be declared with a specific data type, which defines the size, range, and type of value it can store.
Java has primitive and non-primitive data types, along with multiple categories of variables based on their scope.
Types of Variables
- Local Variables: Declared inside a method or block, must be initialized before use.
- Instance Variables: Declared in a class but outside methods; each object gets its own copy.
- Static Variables: Declared using
static; shared among all objects of a class.
class Example {
int instanceVar = 10; // instance variable
static int staticVar = 20; // static variable
void show() {
int localVar = 5; // local variable
System.out.println(localVar);
}
}
Primitive Data Types
Primitive types are the most basic data types provided by Java. They store simple values and are stored in stack memory (for local variables).
| Type | Size | Range / Notes |
| byte | 1 byte | -128 to 127 |
| short | 2 bytes | -32,768 to 32,767 |
| int | 4 bytes | ~ ±2.1 billion |
| long | 8 bytes | Use L suffix (e.g., 100L) |
| float | 4 bytes | Single precision; use f |
| double | 8 bytes | Double precision; default for decimals |
| char | 2 bytes | Unicode (0 – 65,535) |
| boolean | 1 bit | true / false |
Non-Primitive Data Types
- String — sequence of characters
- Arrays — collection of fixed-size elements
- Classes & Objects
- Interfaces
String city = "Bhubaneswar";
int[] numbers = {1, 2, 3, 4};
Memory Allocation of Variables (Diagram)
+-------------------------+
| Stack Memory |
|-------------------------|
| Local Variables |
| Method Calls |
+-------------------------+
+-------------------------+
| Heap Memory |
|-------------------------|
| Objects |
| Instance Variables |
| Arrays, Strings, etc. |
+-------------------------+
Type Casting in Java
1. Widening (Automatic) — smaller → larger
int x = 10;
double y = x; // widening
2. Narrowing (Manual) — larger → smaller
double d = 9.8;
int i = (int) d; // narrowing (results in 9)
Wrapper Classes (for Primitive → Object)
Java provides wrapper classes such as Integer, Double, Character, Boolean etc., allowing primitives to be used as objects.
int a = 10;
Integer obj = Integer.valueOf(a); // Boxing
int b = obj; // Unboxing
More Examples
// Declaring various variables
byte age = 25;
float height = 5.9f;
char grade = 'A';
boolean isPass = true;
long population = 7800000000L;
System.out.println(\"Grade: \" + grade);
System.out.println(\"Passed? \" + isPass);
2. Arrays and Operators in Java
Arrays:
An array in Java is a fixed-size, indexed, homogeneous data structure used to store multiple elements
of the same type. Arrays are stored in heap memory and their index starts from 0.
Array Declaration & Initialization
You can declare arrays in multiple ways:
// 1. Declaration
int[] marks;
int numbers[];
// 2. Allocation
marks = new int[5]; // creates 5 integer slots
// 3. Declaration + Allocation
int[] arr = new int[3];
// 4. Initialization with values
int[] nums = {10, 20, 30};
// 5. Multidimensional Arrays
int[][] matrix = {
{1, 2, 3},
{4, 5, 6}
};
Array Memory Representation (Diagram)
Index: 0 1 2 3 4
Array: [5] [8] [3] [9] [1]
2D Array Diagram:
Col0 Col1 Col2
Row0 [ 1 2 3 ]
Row1 [ 4 5 6 ]
Useful Array Utility Methods
import java.util.Arrays;
int[] arr = {5, 3, 1, 4, 2};
Arrays.sort(arr); // Sort ascending
Arrays.toString(arr); // Convert array to string
Arrays.binarySearch(arr, 4); // Search element
Arrays.fill(arr, 10); // Replace all values with 10
Arrays.copyOf(arr, 3); // Copy first 3 elements
Looping Through Arrays
int[] nums = {10, 20, 30};
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
for (int n : nums) {
System.out.println(n);
}
Java Operators
Operators are symbols that perform operations on variables and values.
1. Arithmetic Operators
+ addition
- subtraction
* multiplication
/ division
% modulus (remainder)
int a = 10, b = 3;
System.out.println(a / b); // 3
System.out.println(a % b); // 1
2. Relational Operators
a > b, a < b, a == b, a != b, a >= b, a <= b
3. Logical Operators
&& (AND), || (OR), ! (NOT)
4. Unary Operators
++a; // pre-increment
a++; // post-increment
--a; // pre-decrement
a--; // post-decrement
5. Bitwise Operators
& (AND), | (OR), ^ (XOR), ~ (NOT), << , >> , >>>
6. Assignment Operators
a += 5; // same as a = a + 5;
a -= 3;
a *= 2;
7. Ternary Operator
String result = (age >= 18) ? "Adult" : "Minor";
Advanced Examples
Example 1: Reverse an Array
int[] arr = {1, 2, 3, 4, 5};
for(int i = arr.length - 1; i >= 0; i--) {
System.out.print(arr[i] + \" \");
}
Example 2: Find Largest Element
int max = arr[0];
for (int n : arr) {
if (n > max) max = n;
}
System.out.println(\"Largest = \" + max);
Example 3: Matrix Traversal
int[][] m = {{1,2},{3,4}};
for(int i = 0; i < m.length; i++) {
for(int j = 0; j < m[i].length; j++) {
System.out.print(m[i][j] + \" \");
}
System.out.println();
}
3. Control Statements and Decision Making Constructs
Control statements allow Java programs to make decisions, repeat tasks, and change the execution flow based on conditions.
They include decision-making statements, looping statements, and jump statements.
A. Decision-Making Statements
These statements execute different blocks of code based on conditions.
1. if Statement
if (age >= 18) {
System.out.println("Eligible to vote");
}
2. if-else Statement
if (marks >= 40) {
System.out.println("Pass");
} else {
System.out.println("Fail");
}
3. else-if Ladder
if (score >= 90) grade = "A";
else if (score >= 75) grade = "B";
else if (score >= 60) grade = "C";
else grade = "D";
4. switch-case Statement
int day = 3;
switch(day) {
case 1: System.out.println("Monday"); break;
case 2: System.out.println("Tuesday"); break;
case 3: System.out.println("Wednesday"); break;
default: System.out.println("Invalid Day");
}
Switch Flow Diagram:
+-----------+
| switch |
+-----+-----+
|
+---------+---------+
| | |
case 1 case 2 case 3
| | |
break break break
|
default
B. Looping Constructs
Loops help automate repetitive tasks by executing a block multiple times.
1. for Loop
for (int i = 1; i <= 5; i++) {
System.out.println(i);
}
2. while Loop
int i = 1;
while (i <= 5) {
System.out.println(i);
i++;
}
3. do-while Loop
int i = 1;
do {
System.out.println(i);
i++;
} while (i <= 5);
4. for-each Loop (Enhanced Loop)
int[] arr = {10, 20, 30};
for (int num : arr) {
System.out.println(num);
}
Nested Loops Example
for(int i = 1; i <= 3; i++) {
for(int j = 1; j <= 3; j++) {
System.out.print("(" + i + "," + j + ") ");
}
System.out.println();
}
C. Jump Statements
Jump statements transfer control to another part of the program.
1. break Statement
for (int i = 1; i <= 10; i++) {
if (i == 5) break;
System.out.println(i);
}
2. continue Statement
for (int i = 1; i <= 5; i++) {
if (i == 3) continue;
System.out.println(i);
}
3. return Statement
int add(int a, int b) {
return a + b; // exits method
}
Advanced Example: Using break with Labels
outer:
for(int i = 1; i <= 3; i++) {
for(int j = 1; j <= 3; j++) {
if (j == 2) break outer; // breaks outer loop
System.out.println(i + "," + j);
}
}
4. Java Classes and Objects
A class is a blueprint or template that defines the properties (variables) and behaviors (methods) of an object.
An object is an instance of a class, created using the new keyword.
Java is entirely based on the concept of classes and objects.
A. Structure of a Java Class
class ClassName {
// 1. Fields / Variables
int id;
String name;
// 2. Methods
void display() {
System.out.println(id + " " + name);
}
}
Real Example
class Student {
String name;
int age;
void study() {
System.out.println(name + " is studying");
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student(); // creating object
s.name = "Amit";
s.age = 21;
s.study();
}
}
Object in Memory (Diagram)
Heap Memory
+---------------------------+
| Student Object (s) |
| --------------------- |
| name = "Amit" |
| age = 21 |
+---------------------------+
B. Constructors
A constructor is a special method with the same name as the class.
It is used to initialize objects. It is automatically called when an object is created.
1. Default Constructor
class Student {
Student() {
System.out.println("Default Constructor Called");
}
}
2. Parameterized Constructor
Student(String n, int a) {
name = n;
age = a;
}
3. Constructor Overloading
class Student {
String name;
int age;
Student() {} // default
Student(String n) {
name = n;
}
Student(String n, int a) { // overloading
name = n;
age = a;
}
}
C. The this Keyword
this refers to the current class object. Used when variable names clash or to call other constructors.
class Car {
String model;
Car(String model) {
this.model = model; // referring to instance variable
}
}
Calling Constructor Using this()
Car() {
this("Default Model"); // calling parameterized constructor
}
D. The static Keyword
static members belong to the class rather than objects.
They are loaded once and shared among all instances.
class Counter {
static int count = 0;
Counter() {
count++;
}
}
Counter c1 = new Counter();
Counter c2 = new Counter();
System.out.println(Counter.count); // prints 2
E. Access Modifiers
| Modifier | Within Class | Within Package | Subclass | World |
| public | ✔ | ✔ | ✔ | ✔ |
| protected | ✔ | ✔ | ✔ | ✖ |
| default | ✔ | ✔ | ✖ | ✖ |
| private | ✔ | ✖ | ✖ | ✖ |
F. Complete Example Program
class Employee {
String name;
int salary;
static String company = "WebTechIO";
Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
void display() {
System.out.println(name + " : " + salary + " : " + company);
}
}
public class Main {
public static void main(String[] args) {
Employee e1 = new Employee("Sourav", 75000);
Employee e2 = new Employee("Amit", 42000);
e1.display();
e2.display();
}
}
5. Methods and Lambda Expressions
Methods in Java define reusable blocks of code that perform specific tasks.
They improve modularity, readability, and reusability.
Java 8 introduced Lambda Expressions, enabling functional-style programming.
A. Method Structure
returnType methodName(parameters) {
// body
}
Example
void greet() {
System.out.println("Hello Java!");
}
B. Types of Methods
- Predefined Methods – from Java API (e.g.,
Math.sqrt())
- User-defined Methods – created by programmers
- Static Methods – accessed without objects
- Instance Methods – require object to call
Static Method Example
static void display() {
System.out.println("Static Method Called");
}
display(); // calling without object
Instance Method Example
class Demo {
void show() {
System.out.println("Instance Method");
}
}
Demo d = new Demo();
d.show();
C. Method Overloading
Java allows multiple methods with the same name but different parameters.
(Different number of parameters / data types / order)
void add(int a, int b) { ... }
void add(double a, double b) { ... }
void add(int a, int b, int c) { ... }
D. Passing Parameters (Call by Value)
Java passes all arguments by value. This means copies of variables are passed to methods, not the original ones.
void change(int x) {
x = x + 10;
}
int a = 5;
change(a);
System.out.println(a); // still 5
E. Lambda Expressions (Java 8)
Lambda expressions allow writing concise, functional-style code.
They are used with functional interfaces (interfaces with only one abstract method).
General Syntax
(parameters) -> { expression or statements }
1. Lambda Example with Runnable
Runnable r = () -> System.out.println("Running in Lambda");
r.run();
2. Lambda with Parameters
interface Calculator {
int add(int a, int b);
}
Calculator c = (a, b) -> a + b;
System.out.println(c.add(5, 7));
3. Lambda for ForEach Loop
List list = List.of("Java", "Python", "C++");
list.forEach(item -> System.out.println(item));
4. Lambda with Multiple Statements
(a, b) -> {
int sum = a + b;
return sum;
};
F. Functional Interfaces
Any interface with a single abstract method is a functional interface.
@FunctionalInterface
interface Greeting {
void sayHello();
}
Greeting g = () -> System.out.println("Hello from Lambda!");
g.sayHello();
G. Complete Program Example
class MathOps {
int square(int n) {
return n * n;
}
static void welcome() {
System.out.println("Welcome to Java");
}
public static void main(String[] args) {
MathOps m = new MathOps();
System.out.println(m.square(6)); // instance method
MathOps.welcome(); // static method
// Lambda Expression
Calculator calc = (a, b) -> a * b;
System.out.println(calc.add(5, 4));
}
}
6. Inheritance and Interface Implementation
Inheritance allows one class to acquire properties and methods of another class using the
extends keyword.
It supports the IS-A relationship and promotes code reusability.
Interfaces, defined using the interface keyword, allow Java to achieve
multiple inheritance of type.
A. Types of Inheritance in Java
- Single Inheritance – one parent, one child
- Multilevel Inheritance – parent → child → grandchild
- Hierarchical Inheritance – one parent, multiple children
Note: Java does NOT support multiple inheritance using classes, but supports it using interfaces.
Example of Multilevel Inheritance
class Animal {
void eat() { System.out.println("Eating..."); }
}
class Dog extends Animal {
void bark() { System.out.println("Barking..."); }
}
class Puppy extends Dog {
void weep() { System.out.println("Weeping..."); }
}
Puppy p = new Puppy();
p.eat();
p.bark();
p.weep();
Inheritance Hierarchy Diagram
Animal
|
---> Dog
|
---> Puppy
B. Method Overriding
When a subclass provides a specific implementation of a method already defined in the parent class,
it is called method overriding.
class Animal {
void sound() { System.out.println("Animal makes sound"); }
}
class Dog extends Animal {
@Override
void sound() { System.out.println("Dog barks"); }
}
Using super Keyword
class Animal {
void sound() { System.out.println("Generic Animal Sound"); }
}
class Cat extends Animal {
void sound() {
super.sound(); // call parent version
System.out.println("Cat meows");
}
}
C. Interfaces in Java
An interface is a blueprint of a class containing abstract methods.
A class uses implements to implement an interface.
One class can implement multiple interfaces.
Basic Interface Example
interface Vehicle {
void start();
}
class Car implements Vehicle {
public void start() {
System.out.println("Car Started");
}
}
Multiple Interface Implementation
interface A {
void show();
}
interface B {
void display();
}
class Test implements A, B {
public void show() { System.out.println("A show"); }
public void display() { System.out.println("B display"); }
}
D. Default & Static Methods in Interfaces (Java 8)
interface Calculator {
void add(int a, int b);
default void message() {
System.out.println("Default Method in Interface");
}
static void info() {
System.out.println("Static Method in Interface");
}
}
E. Complete Program Example
interface Printable {
void print();
}
class Document implements Printable {
public void print() {
System.out.println("Printing Document...");
}
}
class Demo {
public static void main(String[] args) {
Document d = new Document();
d.print();
}
}
7. Packages and Access Modifiers
Packages organize classes; access modifiers (public, protected, default, private) control visibility.
Package Example
package mypkg;
public class MyClass { public void show() {} }
// Use: import mypkg.MyClass;
Access Modifier Table
| Modifier | Class | Package | Subclass | World |
| public | ✔ | ✔ | ✔ | ✔ |
| protected | ✔ | ✔ | ✔ | ✖ |
| default | ✔ | ✔ | ✖ | ✖ |
| private | ✔ | ✖ | ✖ | ✖ |
8. Exception Handling and Custom Exceptions
Exceptions are runtime errors that disrupt the normal flow of a program.
Java provides a powerful Exception Handling Mechanism using:
try, catch, finally, throw, and throws.
A. Types of Exceptions
- Checked Exceptions – must be handled (IOException, SQLException)
- Unchecked Exceptions – Runtime exceptions (ArithmeticException, NullPointerException)
- Errors – Not recoverable (OutOfMemoryError)
Exception Hierarchy (Diagram)
Throwable
|---- Exception
| |---- RuntimeException
| |---- IOException
|
|---- Error
B. try-catch Block
Used to catch and handle exceptions gracefully.
try {
int a = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
} finally {
System.out.println("Finally always executes");
}
Multiple Catch Blocks
try {
String s = null;
System.out.println(s.length());
} catch (NullPointerException e) {
System.out.println("Null Reference Found");
} catch (Exception e) {
System.out.println("General Exception");
}
Nested try Block
try {
try {
int[] arr = new int[2];
arr[3] = 10;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Index error");
}
} catch (Exception e) {
System.out.println("Outer Exception");
}
C. throw and throws
1. throw: explicitly throw exception
void validate(int age) {
if (age < 18)
throw new ArithmeticException("Not Eligible");
}
2. throws: declare exception in method signature
void readFile() throws IOException {
FileInputStream f = new FileInputStream("data.txt");
}
D. Custom Exceptions
You can create your own exceptions by extending Exception or RuntimeException.
class AgeException extends Exception {
AgeException(String msg) {
super(msg);
}
}
void checkAge(int age) throws AgeException {
if (age < 18)
throw new AgeException("Age must be 18+");
}
Using the Custom Exception
try {
checkAge(16);
} catch (AgeException e) {
System.out.println("Caught: " + e.getMessage());
}
E. try-with-resources (Auto Closing)
try (FileInputStream f = new FileInputStream("data.txt")) {
System.out.println("File opened");
} catch (IOException e) {
System.out.println(e);
}
This automatically closes the resource, no need for finally.
F. Complete Program Example
class Bank {
void withdraw(int amount) throws Exception {
if (amount > 5000)
throw new Exception("Limit Exceeded");
else
System.out.println("Withdrawn: " + amount);
}
}
public class Main {
public static void main(String[] args) {
Bank b = new Bank();
try {
b.withdraw(7000);
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
9. String Handling and StringBuffer / StringBuilder
Strings in Java are one of the most commonly used data types.
The String class is immutable, meaning once created, it cannot be modified.
For modifying strings frequently, Java provides StringBuffer and StringBuilder,
which are mutable.
A. String Class (Immutable)
When you modify a String, Java actually creates a new object in memory,
because Strings are stored in the String Constant Pool.
String s = "Java";
s = s + " World";
// Creates a new String object -> old one becomes unused
String Memory Diagram
String s1 = "Java";
String s2 = "Java";
// Both point to same memory in String Pool
Important String Methods
String s = "Hello Java";
s.length();
s.toUpperCase();
s.toLowerCase();
s.charAt(2);
s.substring(0, 5);
s.contains("Java");
s.startsWith("He");
s.endsWith("va");
s.replace("Java", "World");
B. StringBuffer (Mutable & Thread-Safe)
StringBuffer is synchronized (thread-safe), making it safe for multithreaded applications.
StringBuffer sb = new StringBuffer("Hello");
sb.append(" Java");
sb.insert(0, "Hi ");
sb.reverse();
System.out.println(sb);
Useful Methods
sb.append("text");
sb.insert(3, "XYZ");
sb.delete(2, 5);
sb.replace(1, 3, "AA");
sb.reverse();
C. StringBuilder (Mutable & Faster, Not Thread-Safe)
StringBuilder gives better performance because it is not synchronized.
StringBuilder sb = new StringBuilder("Welcome");
sb.append(" User");
sb.deleteCharAt(2);
sb.replace(0, 3, "Hi");
Useful Methods
sb.append("...");
sb.capacity();
sb.ensureCapacity(50);
sb.charAt(1);
sb.setCharAt(0, 'W');
D. Comparison
| Class | Mutable? | Thread-safe? | Speed |
| String | No | Yes | Slow |
| StringBuffer | Yes | Yes | Medium |
| StringBuilder | Yes | No | Fast |
E. When to Use What?
- Use String → When the value won't change (best for constants, messages).
- Use StringBuffer → When working with multithreading where safety is needed.
- Use StringBuilder → When modifying strings frequently in a single thread (fastest).
F. Complete Example
class Demo {
public static void main(String[] args) {
// String Example
String s = "Java";
s = s.concat(" Programming");
System.out.println(s);
// StringBuffer Example
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World!");
System.out.println(sb);
// StringBuilder Example
StringBuilder sb2 = new StringBuilder("Fast");
sb2.append(" Builder");
System.out.println(sb2);
}
}
10. Introduction to Java Collections Framework
The Java Collections Framework (JCF) is a unified architecture to store, retrieve, manipulate,
and process groups of objects.
It provides ready-made data structures like List, Set, Queue, Map and utility classes like
Collections and Arrays.
A. Why Collections?
- Dynamic size (unlike arrays)
- Ready-made algorithms (sorting, searching)
- Easy insertion/deletion
- Different data storage behaviors (ordered, sorted, unique values)
B. Collections Framework Hierarchy (Diagram)
Iterable
|
----------------
| |
Collection Map (separate)
|
--------------------------------
| | |
List Set Queue
C. List Interface (Ordered, Allows Duplicates)
Common Implementations: ArrayList, LinkedList, Vector
List names = new ArrayList<>();
names.add("Sourav");
names.add("Amit");
names.add("Sourav"); // duplicates allowed
System.out.println(names.get(0));
D. Set Interface (Unique Values Only)
No duplicates. Common Implementations: HashSet, LinkedHashSet, TreeSet
Set values = new HashSet<>();
values.add(10);
values.add(20);
values.add(10); // ignored, no duplicates
E. Queue Interface (FIFO)
Used in scheduling, messaging, order processing. Common: PriorityQueue, LinkedList.
Queue q = new LinkedList<>();
q.add("Task1");
q.add("Task2");
System.out.println(q.poll()); // retrieves & removes
F. Map Interface (Key–Value Pairs)
Keys are unique; values may duplicate. Common: HashMap, LinkedHashMap, TreeMap.
Map map = new HashMap<>();
map.put(1, "Sourav");
map.put(2, "Amit");
map.put(1, "Updated"); // overwrites key 1
System.out.println(map.get(1));
G. Iteration Techniques
1. For-each Loop
for (String s : names) {
System.out.println(s);
}
2. Iterator
Iterator it = values.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
3. Lambda Style Iteration
names.forEach(n -> System.out.println(n));
H. Collections Utility Class
Collections.sort(names);
Collections.reverse(names);
Collections.shuffle(names);
Collections.min(values);
Collections.max(values);
I. Complete Program Example
import java.util.*;
class Demo {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add("Java");
list.add("Python");
Set set = new HashSet<>();
set.add(20);
set.add(40);
Map map = new HashMap<>();
map.put(1, "Sourav");
map.put(2, "Amit");
System.out.println(list);
System.out.println(set);
System.out.println(map);
}
}
11. Stream API and Functional Programming in Java
The Stream API (introduced in Java 8) allows processing of collections in a
declarative, functional, and pipeline-based style.
It supports operations like filtering, mapping, reducing, collecting, and iteration —
all without modifying the original data source.
A. Functional Programming in Java
Java 8 introduced features to support functional programming:
- Lambda Expressions
- Method References
- Functional Interfaces (Predicate, Function, Supplier, Consumer)
- Stream API
- Immutable Data Processing
Example of Method Reference
List list = List.of("A", "B", "C");
list.forEach(System.out::println);
B. Stream Pipeline Architecture
A stream pipeline contains three stages:
- Source: collection, array, file, generator
- Intermediate operations (lazy): filter(), map(), sorted(), limit()
- Terminal operations (eager): forEach(), collect(), reduce(), count()
Basic Stream Pipeline Example
List nums = Arrays.asList(1,2,3,4,5);
nums.stream() // source
.filter(n -> n % 2 == 0) // intermediate
.map(n -> n * n) // intermediate
.forEach(System.out::println); // terminal
C. Intermediate Operations
- filter() – filters data
- map() – transforms data
- sorted() – sorts stream
- distinct() – removes duplicates
- limit() / skip() – slicing
Example
List names = List.of("Amit", "Sourav", "Amit");
names.stream()
.distinct()
.sorted()
.forEach(System.out::println);
D. Terminal Operations
- forEach()
- collect()
- reduce()
- count()
- anyMatch(), allMatch(), noneMatch()
Using reduce()
int sum = nums.stream().reduce(0, (a,b) -> a + b);
System.out.println(sum);
E. Collectors in Depth
1. Collect to List
List evens = nums.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
2. Convert to Set
Set unique = nums.stream().collect(Collectors.toSet());
3. Joining Strings
String combined = names.stream()
.collect(Collectors.joining(", "));
4. Grouping Elements
Map> grouped =
nums.stream().collect(Collectors.groupingBy(n -> n % 2));
F. Optional in Streams
Optional max = nums.stream().max(Integer::compareTo);
if (max.isPresent()) {
System.out.println("Max: " + max.get());
}
G. Parallel Streams
Parallel streams allow dividing tasks across multiple CPU cores.
nums.parallelStream()
.map(n -> n * 2)
.forEach(System.out::println);
H. Complete Stream Program Example
import java.util.*;
import java.util.stream.*;
class Demo {
public static void main(String[] args) {
List nums = Arrays.asList(1,2,3,4,5,6);
// Pipeline: even -> square -> collect
List squares =
nums.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println(squares);
// Reduce
int sum = nums.stream()
.reduce(0, Integer::sum);
System.out.println("Sum = " + sum);
// Method Reference
nums.forEach(System.out::println);
}
}
Conclusion
This combined chapter covered all essential Java programming concepts with detailed explanations
and examples. You can now move to advanced topics like Generics, Multithreading, JDBC,
and Design Patterns.