Java is a high-level, class-based, object-oriented programming language that is designed to have as few implementation dependencies as possible. It is a general-purpose programming language intended to let application developers write once, run anywhere
(WORA), meaning that compiled Java code can run on all platforms that support Java without the need for recompilation.
Java is one of the most popular programming languages, widely used for:
To write, compile, and run Java programs, you need a **Java Development Kit (JDK)**. The JDK includes the Java Runtime Environment (JRE), a compiler (javac
), and other development tools.
You can download JDK from Oracle or OpenJDK distributions like Adoptium (Temurin).
After installation, you might need to set the `JAVA_HOME` environment variable and add Java's `bin` directory to your system's `PATH` variable.
# Open ~/.bashrc, ~/.zshrc, or ~/.profile
nano ~/.bashrc
# Add these lines (replace with your actual JDK path):
export JAVA_HOME="/usr/lib/jvm/java-17-openjdk-amd64" # Linux example
# export JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home" # macOS example
export PATH="$JAVA_HOME/bin:$PATH"
# Apply changes:
source ~/.bashrc # or ~/.zshrc, ~/.profile
Open your terminal/command prompt and run:
java -version
javac -version
You should see the installed JDK versions.
The classic first program.
Create a file named `HelloWorld.java` using any text editor.
// HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!"); // Prints "Hello, World!" to the console
}
}
Open your terminal/command prompt, navigate to the directory where you saved `HelloWorld.java`, and run the Java compiler:
javac HelloWorld.java
If compilation is successful, a `HelloWorld.class` file will be created in the same directory. This is the bytecode, which the JVM understands.
java HelloWorld
Expected Output:
Hello, World!
Used to explain code and make it more readable. Ignored by the compiler.
int x = 10; // This is a single-line comment
/*
* This is a multi-line comment.
* It can span across multiple lines.
*/
int y = 20;
/**
* This method calculates the sum of two numbers.
* @param a The first number.
* @param b The second number.
* @return The sum of a and b.
*/
public int add(int a, int b) {
return a + b;
}
Variables are containers for storing data values. Java is a strongly-typed language, meaning you must declare the type of a variable before using it.
Store simple values directly in memory.
int age = 30;
double price = 19.99;
boolean isActive = true;
char initial = 'J';
long population = 8000000000L; // 'L' suffix for long literal
float temperature = 98.6f; // 'f' suffix for float literal
Store references (memory addresses) to objects. Includes `String`, Arrays, Classes, Interfaces.
String name = "John Doe";
int[] numbers = {1, 2, 3}; // Array of integers
Date today = new Date(); // Object of Date class
int quantity; // Declaration
quantity = 100; // Initialization
String city = "New York"; // Declaration and Initialization
final double PI = 3.14159; // 'final' keyword makes a variable a constant (cannot be changed)
// PI = 3.14; // Error: Cannot assign a value to a final variable
Converting one data type to another.
int myInt = 9;
double myDouble = myInt; // myDouble is now 9.0
double myDouble = 9.78;
int myInt = (int) myDouble; // myInt is now 9 (decimal part is truncated)
Symbols that perform operations on variables and values.
int a = 10, b = 3;
System.out.println(a + b); // 13
System.out.println(a / b); // 3 (integer division)
System.out.println(a % b); // 1 (remainder)
a++; // a is now 11
int x = 5;
x += 3; // x is now 8 (equivalent to x = x + 3)
System.out.println(10 > 5); // true
System.out.println(7 == 7); // true
boolean isAdult = true;
boolean hasLicense = false;
System.out.println(isAdult && hasLicense); // false
System.out.println(isAdult || hasLicense); // true
System.out.println(!isAdult); // false
int score = 75;
String result = (score >= 60) ? "Pass" : "Fail";
System.out.println(result); // Pass
Control flow statements dictate the order in which instructions are executed.
int temperature = 25;
if (temperature > 30) {
System.out.println("It's hot!");
} else if (temperature > 20) { // Condition if first 'if' is false
System.out.println("It's warm.");
} else { // Executed if all preceding conditions are false
System.out.println("It's cool.");
}
String day = "Monday";
switch (day) {
case "Monday":
System.out.println("Start of the week.");
break; // Important! Exits the switch block
case "Friday":
System.out.println("Almost weekend!");
break;
default: // Optional, executed if no case matches
System.out.println("Mid-week.");
}
for (int i = 0; i < 5; i++) {
System.out.println("Count: " + i);
}
String[] fruits = {"apple", "banana", "cherry"};
for (String fruit : fruits) {
System.out.println("I like " + fruit);
}
int count = 0;
while (count < 3) {
System.out.println("Loop " + count);
count++;
}
int i = 0;
do {
System.out.println("Do-while loop: " + i);
i++;
} while (i < 2);
Methods are blocks of code that perform a specific task. They are defined within classes.
public static void main(String[] args) { ... } // Example: main method
public int addNumbers(int a, int b) { // Method named addNumbers, returns an int
return a + b;
}
public void printMessage(String message) { // Method named printMessage, returns nothing (void)
System.out.println(message);
}
public class MyCalculator {
public static void main(String[] args) {
MyCalculator calc = new MyCalculator(); // Create an object to call non-static methods
int sum = calc.addNumbers(10, 5); // Call addNumbers method
System.out.println("Sum: " + sum); // Output: Sum: 15
calc.printMessage("Hello from a method!"); // Call printMessage method
}
public int addNumbers(int a, int b) {
return a + b;
}
public void printMessage(String message) {
System.out.println(message);
}
}
Java is built on OOP principles: Encapsulation, Inheritance, Polymorphism, Abstraction.
// Define a class 'Car'
public class Car {
// Fields (attributes)
String make;
String model;
int year;
// Constructor: A special method called when an object is created
public Car(String make, String model, int year) {
this.make = make; // 'this' refers to the current object's instance variable
this.model = model;
this.year = year;
}
// Method (behavior)
public void start() {
System.out.println(make + " " + model + " starting...");
}
public void displayInfo() {
System.out.println("Make: " + make + ", Model: " + model + ", Year: " + year);
}
}
public class Main {
public static void main(String[] args) {
// Create objects (instances) of the Car class
Car myCar = new Car("Toyota", "Camry", 2020); // Calls the constructor
Car anotherCar = new Car("Honda", "Civic", 2022);
// Access fields and call methods on objects
myCar.start(); // Output: Toyota Camry starting...
myCar.displayInfo(); // Output: Make: Toyota, Model: Camry, Year: 2020
anotherCar.displayInfo(); // Output: Make: Honda, Model: Civic, Year: 2022
}
}
Bundling data (fields) and methods that operate on the data within a single unit (class), and restricting direct access to some of the component's internals (using access modifiers).
public class Student {
private String name; // private field
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
// Getter method
public String getName() {
return name;
}
// Setter method
public void setAge(int age) {
if (age > 0) { // Add validation
this.age = age;
} else {
System.out.println("Age cannot be negative.");
}
}
}
Arrays are fixed-size, ordered collections of elements of the same data type.
int[] numbers; // Declaration
numbers = new int[5]; // Initialization (creates an array of 5 integers, all initialized to 0)
String[] names = new String[3]; // Array of 3 Strings, initialized to null
// Declare, create, and initialize in one line:
int[] scores = {90, 85, 92, 78};
String[] colors = {"Red", "Green", "Blue"};
System.out.println(scores[0]); // Output: 90 (first element)
scores[3] = 80; // Change value of fourth element
System.out.println(scores.length); // Output: 4 (number of elements)
for (int i = 0; i < scores.length; i++) {
System.out.println("Score at index " + i + ": " + scores[i]);
}
// Using for-each loop (enhanced for loop):
for (int score : scores) {
System.out.println("Score: " + score);
}
int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
System.out.println(matrix[0][1]); // Output: 2 (element at row 0, column 1)
In Java, strings are objects (not primitive types) representing sequences of characters. They are immutable (cannot be changed after creation).
String greeting = "Hello";
String message = new String("World");
String s1 = "Java";
String s2 = "Programming";
String s3 = " Hello World ";
System.out.println(s1.length()); // 4
System.out.println(s1.concat(s2)); // JavaProgramming (or s1 + s2)
System.out.println(s1.equals("java")); // false (case-sensitive)
System.out.println(s1.equalsIgnoreCase("java")); // true
System.out.println(s1.substring(1)); // ava
System.out.println(s2.charAt(0)); // P
System.out.println(s3.trim()); // "Hello World" (removes leading/trailing whitespace)
System.out.println(s1.indexOf("a")); // 1 (first occurrence)
System.out.println(s1.contains("va")); // true
System.out.println(s1.replace("a", "o")); // Jova
String original = "abc";
String newString = original.concat("def");
System.out.println(original); // abc (original remains unchanged)
System.out.println(newString); // abcdef
StringBuilder sb = new StringBuilder("Start");
sb.append(" and ").append("End");
System.out.println(sb.toString()); // Start and End
sb.insert(5, "Middle ");
System.out.println(sb.toString()); // Start Middle and End
Allows a class (subclass/child) to inherit properties and methods from another class (superclass/parent).
class Animal { // Superclass
String name;
public Animal(String name) {
this.name = name;
}
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal { // Subclass
public Dog(String name) {
super(name); // Call parent class constructor
}
@Override // Annotation indicating method overrides a superclass method
public void makeSound() {
System.out.println(name + " barks!");
}
public void fetch() {
System.out.println(name + " is fetching.");
}
}
public class InheritanceDemo {
public static void main(String[] args) {
Animal myAnimal = new Animal("Generic");
Dog myDog = new Dog("Buddy");
myAnimal.makeSound(); // Output: Animal makes a sound
myDog.makeSound(); // Output: Buddy barks! (Overridden method)
myDog.fetch(); // Output: Buddy is fetching.
}
}
Means "many forms." It allows objects of different classes to be treated as objects of a common superclass. The actual method called depends on the object's runtime type.
class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " meows!");
}
}
public class PolymorphismDemo {
public static void main(String[] args) {
Animal myAnimal1 = new Dog("Lucy"); // Animal reference, Dog object
Animal myAnimal2 = new Cat("Whiskers"); // Animal reference, Cat object
Animal myAnimal3 = new Animal("Leo");
myAnimal1.makeSound(); // Output: Lucy barks! (Runtime polymorphism)
myAnimal2.makeSound(); // Output: Whiskers meows!
myAnimal3.makeSound(); // Output: Leo makes a sound
}
}
Hiding the complex implementation details and showing only the essential features of an object. Achieved using abstract classes and interfaces.
abstract class Shape { // Abstract class
String color;
public Shape(String color) {
this.color = color;
}
// Abstract method (no body)
public abstract double getArea();
// Concrete method
public String getColor() {
return color;
}
}
class Circle extends Shape {
double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() { // Implementation for abstract method
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
double length;
double width;
public Rectangle(String color, double length, double width) {
super(color);
this.length = length;
this.width = width;
}
@Override
public double getArea() { // Implementation for abstract method
return length * width;
}
}
public class AbstractionDemo {
public static void main(String[] args) {
Shape circle = new Circle("Red", 5.0);
Shape rectangle = new Rectangle("Blue", 4.0, 6.0);
System.out.println("Circle Area: " + circle.getArea()); // Output: Circle Area: 78.53...
System.out.println("Rectangle Area: " + rectangle.getArea()); // Output: Rectangle Area: 24.0
System.out.println("Circle Color: " + circle.getColor()); // Output: Circle Color: Red
}
}
A blueprint of a class. It defines a contract specifying methods that implementing classes must provide. A class can implement multiple interfaces.
interface Playable { // Interface
void play(); // Abstract method (implicitly public abstract)
void pause();
default void stop() { // Default method (Java 8+)
System.out.println("Stopped playback.");
}
}
class MusicPlayer implements Playable {
@Override
public void play() {
System.out.println("Playing music...");
}
@Override
public void pause() {
System.out.println("Music paused.");
}
}
class VideoPlayer implements Playable {
@Override
public void play() {
System.out.println("Playing video...");
}
@Override
public void pause() {
System.out.println("Video paused.");
}
}
public class InterfaceDemo {
public static void main(String[] args) {
Playable music = new MusicPlayer();
Playable video = new VideoPlayer();
music.play(); // Output: Playing music...
music.pause(); // Output: Music paused.
music.stop(); // Output: Stopped playback.
video.play(); // Output: Playing video...
video.stop(); // Output: Stopped playback.
}
}
A mechanism to handle runtime errors (exceptions) that might occur during program execution, preventing the program from crashing.
public class ExceptionHandlingDemo {
public static void main(String[] args) {
// Example 1: ArithmeticException
try {
int result = 10 / 0; // This will throw an ArithmeticException
System.out.println("Result: " + result); // This line will not execute
} catch (ArithmeticException e) {
System.err.println("Error: Cannot divide by zero. " + e.getMessage());
} finally {
System.out.println("Arithmetic operation attempted.");
}
// Example 2: NullPointerException
String str = null;
try {
System.out.println(str.length()); // This will throw a NullPointerException
} catch (NullPointerException e) {
System.err.println("Error: String is null. " + e.getMessage());
}
// Example 3: Custom Exception (throws keyword)
try {
validateAge(5); // This will throw an IllegalArgumentException
} catch (IllegalArgumentException e) {
System.err.println("Validation Error: " + e.getMessage());
}
}
// Method that declares it might throw an IllegalArgumentException
public static void validateAge(int age) throws IllegalArgumentException {
if (age < 18) {
throw new IllegalArgumentException("Age must be 18 or older.");
}
System.out.println("Age is valid.");
}
}
Checked vs. Unchecked Exceptions:
A set of interfaces and classes that provide a unified architecture for representing and manipulating collections of objects.
import java.util.ArrayList;
import java.util.List;
List<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Apple"); // Duplicates allowed
System.out.println(fruits); // [Apple, Banana, Apple]
System.out.println(fruits.get(1)); // Banana
fruits.remove("Apple"); // Removes first "Apple"
System.out.println(fruits); // [Banana, Apple]
import java.util.HashSet;
import java.util.Set;
Set<String> uniqueColors = new HashSet<>();
uniqueColors.add("Red");
uniqueColors.add("Green");
uniqueColors.add("Red"); // Duplicate, ignored
System.out.println(uniqueColors); // [Red, Green] (order not guaranteed)
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 30);
ages.put("Bob", 25);
ages.put("Alice", 31); // Overwrites previous value for "Alice"
System.out.println(ages.get("Alice")); // 31
System.out.println(ages.keySet()); // [Alice, Bob]
System.out.println(ages.values()); // [31, 25]
Reading from and writing to files.
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class FileWriteDemo {
public static void main(String[] args) {
String filename = "output.txt";
try (PrintWriter writer = new PrintWriter(new FileWriter(filename))) {
writer.println("This is the first line.");
writer.println("This is the second line.");
System.out.println("Data written to " + filename);
} catch (IOException e) {
System.err.println("Error writing to file: " + e.getMessage());
}
}
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class FileReadDemo {
public static void main(String[] args) {
String filename = "output.txt"; // Assuming output.txt exists from previous example
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
System.out.println("Reading from " + filename + ":");
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.err.println("Error reading from file: " + e.getMessage());
}
}
}
`try-with-resources` (Java 7+): The `try (resource-declaration)` statement automatically closes resources (like `writer` or `reader`) when the `try` block exits, even if an exception occurs. This is the recommended way.
Java supports multithreading, allowing multiple parts of a program to execute concurrently, improving performance for certain tasks.
class MyThread extends Thread {
public void run() { // Contains the code that will be executed in the new thread
for (int i = 0; i < 3; i++) {
System.out.println("Thread 1: " + i);
try { Thread.sleep(100); } catch (InterruptedException e) { }
}
}
}
class MyRunnable implements Runnable {
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Thread 2: " + i);
try { Thread.sleep(100); } catch (InterruptedException e) { }
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
// Start thread by extending Thread class
MyThread thread1 = new MyThread();
thread1.start(); // Calls the run() method in a new thread
// Start thread by implementing Runnable interface
Thread thread2 = new Thread(new MyRunnable());
thread2.start(); // Calls the run() method of MyRunnable in a new thread
System.out.println("Main thread finished.");
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// ... MyRunnable class ...
public class ThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2); // Create a thread pool of 2 threads
executor.submit(new MyRunnable()); // Submit tasks to the pool
executor.submit(new MyRunnable());
executor.shutdown(); // Shuts down the executor when tasks are complete
}
}
Generics enable you to write classes, interfaces, and methods that operate on types that are specified as parameters at creation time. This provides type safety and avoids type casting.
import java.util.ArrayList;
import java.util.List;
public class GenericsDemo {
public static void main(String[] args) {
// Using Generics with List (type-safe)
List<String> stringList = new ArrayList<>();
stringList.add("Hello");
stringList.add("World");
// stringList.add(123); // Compile-time error: cannot add an Integer to a List<String>
String s = stringList.get(0); // No casting needed
// Creating a custom generic class
Box<Integer> integerBox = new Box<>();
integerBox.set(123);
System.out.println("Integer in box: " + integerBox.get());
Box<String> stringBox = new Box<>();
stringBox.set("Generic String");
System.out.println("String in box: " + stringBox.get());
}
}
// Custom Generic Class
class Box<T> { // 'T' is a type parameter
private T t; // 't' is of type T
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
Introduced in Java 8, these features simplify writing functional-style code.
Provide a concise way to represent an anonymous function (a function without a name).
interface MyFunctionalInterface {
void performAction(String s);
}
public class LambdaDemo {
public static void main(String[] args) {
// Using an anonymous inner class (pre-Java 8)
MyFunctionalInterface oldWay = new MyFunctionalInterface() {
@Override
public void performAction(String s) {
System.out.println("Old way: " + s);
}
};
oldWay.performAction("Hello");
// Using a Lambda expression (Java 8+)
MyFunctionalInterface lambdaWay = (s) -> System.out.println("Lambda way: " + s);
lambdaWay.performAction("World");
// More complex lambda for a Comparator (used for sorting)
List<Integer> numbers = Arrays.asList(5, 2, 8, 1);
numbers.sort((a, b) -> a.compareTo(b)); // Sorts ascending
System.out.println("Sorted: " + numbers); // Output: Sorted: [1, 2, 5, 8]
}
}
A sequence of elements from a source that supports aggregate operations (map, filter, reduce, collect) that can be executed sequentially or in parallel.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamAPIDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Anna", "Charlie", "Andrew");
// Filter names starting with 'A' and convert to uppercase
List<String> filteredAndUppercaseNames = names.stream() // Create a stream
.filter(name -> name.startsWith("A")) // Filter elements
.map(String::toUpperCase) // Transform elements (method reference)
.collect(Collectors.toList()); // Collect results into a List
System.out.println(filteredAndUppercaseNames); // Output: [ALICE, ANNA, ANDREW]
// Count names with more than 4 letters
long count = names.stream()
.filter(name -> name.length() > 4)
.count();
System.out.println("Names longer than 4 letters: " + count); // Output: 3
// Find the first name starting with 'B'
names.stream()
.filter(name -> name.startsWith("B"))
.findFirst()
.ifPresent(name -> System.out.println("First 'B' name: " + name)); // Output: First 'B' name: Bob
}
}
Introduced in Java 9, the Java Platform Module System (JPMS), or Project Jigsaw, aims to make the Java platform more scalable, secure, and easier to maintain. It breaks down the monolithic JDK into a set of modules.
Project Structure:
myproject/
├── com.example.app/
│ ├── module-info.java
│ └── com/example/app/
│ └── Main.java
└── com.example.utils/
├── module-info.java
└── com/example/utils/
└── StringUtils.java
// com.example.utils/module-info.java
module com.example.utils {
exports com.example.utils; // Export the package
}
// com.example.utils/com/example/utils/StringUtils.java
package com.example.utils;
public class StringUtils {
public static String capitalize(String text) {
if (text == null || text.isEmpty()) {
return text;
}
return text.substring(0, 1).toUpperCase() + text.substring(1).toLowerCase();
}
}
// com.example.app/module-info.java
module com.example.app {
requires com.example.utils; // Declare dependency on utils module
}
// com.example.app/com/example/app/Main.java
package com.example.app;
import com.example.utils.StringUtils; // Import class from required module
public class Main {
public static void main(String[] args) {
String name = "java";
String capitalizedName = StringUtils.capitalize(name);
System.out.println("Capitalized name: " + capitalizedName); // Output: Capitalized name: Java
}
}
# Compile utils module
javac -d out/com.example.utils com.example.utils/module-info.java com.example.utils/com/example/utils/StringUtils.java
# Compile app module (requires utils module)
javac -d out/com.example.app --module-path out/com.example.utils com.example.app/module-info.java com.example.app/com/example/app/Main.java
# Run the application
java --module-path out/com.example.utils:out/com.example.app -m com.example.app/com.example.app.Main
For real-world Java projects, build automation tools are indispensable.
# pom.xml (example snippet)
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-java-app</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
# Common Maven commands:
mvn compile # Compile source code
mvn test # Run tests
mvn package # Compile, test, and package into JAR/WAR
mvn clean # Remove generated files
mvn install # Install package into local Maven repository
# build.gradle (example snippet for a Java project)
plugins {
id 'java'
}
group = 'com.example'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.0'
}
test {
useJUnitPlatform()
}
# Common Gradle commands:
gradle build # Build, test, and package
gradle test # Run tests
gradle clean # Clean build directory
This tutorial covers the fundamentals of Java programming. Java's ecosystem is vast, with numerous frameworks (Spring, Hibernate), testing tools, and deployment options. Mastering these core concepts will provide a strong foundation for building robust, scalable, and high-performance applications across various domains, from enterprise systems to Android mobile apps. The journey to becoming a proficient Java developer involves continuous learning and hands-on practice!