Introduction to Java
Welcome to the comprehensive Java tutorial! 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.
What is Java?
Java was originally developed by James Gosling at Sun Microsystems (now owned by Oracle) and released in 1995. It's one of the most popular programming languages in the world, widely used for:
- **Enterprise Applications:** Large-scale, mission-critical applications (e.g., using Spring, Java EE).
- **Android Mobile Development:** The primary language for native Android apps.
- **Web Applications:** Server-side development (e.g., Servlets, JSP, Spring Boot).
- **Big Data:** Technologies like Hadoop and Spark are built on Java.
- **Scientific Applications:** Powerful tools for scientific and research purposes.
- **Desktop Applications:** Using frameworks like Swing and JavaFX.
JVM, JRE, and JDK
- **JVM (Java Virtual Machine):** The core of the Java platform. It's a virtual machine that enables a computer to run Java programs. It converts Java bytecode into machine-specific code. This is what makes Java "write once, run anywhere."
- **JRE (Java Runtime Environment):** Contains the JVM and the necessary class libraries and other components to run Java applications. If you only want to run Java programs, you just need the JRE.
- **JDK (Java Development Kit):** Includes the JRE along with development tools (like the Java compiler `javac`, debugger `jdb`, etc.). If you want to *develop* Java applications, you need the JDK.
Setting Up Your Development Environment
To start coding in Java, you need to install the JDK and choose an Integrated Development Environment (IDE).
- **Download JDK:** Go to the official Oracle Java SE Downloads page or Adoptium (OpenJDK) and download the latest LTS version of the JDK for your operating system.
- **Installation:** Follow the installer instructions. Set up the `JAVA_HOME` environment variable and add the JDK's `bin` directory to your system's `PATH`.
- **Verify Installation:** Open your command prompt or terminal and type `java -version` and `javac -version`. You should see the installed Java version.
- **Choose an IDE:**
- **IntelliJ IDEA:** A powerful and popular IDE for Java development (Community Edition is free). Download from jetbrains.com/idea.
- **Eclipse:** Another widely used open-source IDE for Java. Download from eclipse.org/downloads.
- **VS Code:** With Java extensions, it can serve as a lightweight IDE.
Your First Java Program: "Hello, World!"
Let's write the classic "Hello, World!" program. Save this code as `HelloWorld.java`. To compile: `javac HelloWorld.java` To run: `java HelloWorld`
// This is a single-line comment in Java
/* This is a
multi-line comment */
public class HelloWorld { // Declares a public class named HelloWorld
public static void main(String[] args) { // The main method, entry point of the application
// Prints "Hello, World!" to the console
System.out.println("Hello, World!");
}
}
Explanation:
- `public class HelloWorld`: Every Java application must have at least one class, and the file name must match the public class name (e.g., `HelloWorld.java`). `public` means it's accessible from anywhere.
- `public static void main(String[] args)`: This is the main method, the entry point for Java applications.
- `public`: Accessible from anywhere.
- `static`: Can be called without creating an object of the class.
- `void`: The method does not return any value.
- `main`: The name of the method.
- `String[] args`: An array of strings to receive command-line arguments.
- `System.out.println("Hello, World!");`: This line prints the string "Hello, World!" to the console, followed by a new line. `System` is a built-in class, `out` is a static member of `System` of type `PrintStream`, and `println()` is a method of `PrintStream`.
Java Fundamentals
Variables and Data Types
Variables are containers for storing data values. In Java, variables are strongly typed, meaning you must declare their data type explicitly.
// Primitive Data Types
int age = 30; // Integer (whole numbers)
double price = 19.99; // Floating-point number (decimal numbers)
char initial = 'J'; // Character (single character)
boolean isActive = true; // Boolean (true or false)
long bigNumber = 123456789012345L; // Long integer
float temperature = 25.5f; // Single-precision floating-point
// Non-Primitive Data Types (Reference Types)
String name = "John Doe"; // String (sequence of characters, an object)
int[] numbers = {1, 2, 3}; // Array (an object)
System.out.println("Age: " + age);
System.out.println("Name: " + name);
System.out.println("First number in array: " + numbers[0]);
Java has two main categories of data types: **Primitive** (byte, short, int, long, float, double, boolean, char) and **Non-Primitive/Reference** (String, Arrays, Classes, Interfaces).
Operators
Operators are symbols that perform operations on variables and values.
- **Arithmetic Operators:** `+`, `-`, `*`, `/`, `%` (modulus), `++` (increment), `--` (decrement)
- **Assignment Operators:** `=`, `+=`, `-=`, `*=` etc.
- **Comparison Operators:** `==` (equal to), `!=` (not equal), `>`, `<`, `>=`, `<=`
- **Logical Operators:** `&&` (AND), `||` (OR), `!` (NOT)
- **Ternary Operator:** `condition ? exprIfTrue : exprIfFalse`
int a = 10;
int b = 5;
System.out.println(a + b); // Addition: 15
System.out.println(a - b); // Subtraction: 5
System.out.println(a * b); // Multiplication: 50
System.out.println(a / b); // Division: 2
System.out.println(a % b); // Modulus: 0
boolean isGreater = (a > b); // Comparison: true
boolean logicalAnd = (a > 0 && b > 0); // Logical AND: true
String status = (a > 10) ? "Greater" : "Not Greater";
System.out.println(status); // Output: Not Greater
Control Flow
Control flow statements allow you to execute different blocks of code based on conditions or to repeat code.
If-Elseif-Else Statements
int score = 75;
if (score >= 90) {
System.out.println("Grade: A");
} else if (score >= 80) {
System.out.println("Grade: B");
} else if (score >= 70) {
System.out.println("Grade: C");
} else {
System.out.println("Grade: D or F");
}
Switch Statements
int dayOfWeek = 3; // 1=Monday, 7=Sunday
switch (dayOfWeek) {
case 1:
System.out.println("Monday");
break;
case 5:
System.out.println("Friday");
break;
case 7:
System.out.println("Sunday");
break;
default:
System.out.println("Another weekday");
}
Loops (for, while, do-while, for-each)
// For loop
for (int i = 0; i < 5; i++) {
System.out.println("For loop iteration: " + i);
}
// While loop
int count = 0;
while (count < 3) {
System.out.println("While loop iteration: " + count);
count++;
}
// For-each loop (enhanced for loop for arrays and collections)
String[] fruits = {"Apple", "Banana", "Cherry"};
for (String fruit : fruits) {
System.out.println("Fruit: " + fruit);
}
Methods
Methods (also known as functions) are blocks of code that perform a specific task. They help organize code and promote reusability.
public class MyMath {
// Method that returns a value
public int add(int num1, int num2) {
return num1 + num2;
}
// Method that doesn't return a value (void)
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
public static void main(String[] args) {
MyMath calculator = new MyMath();
int sum = calculator.add(10, 20);
System.out.println("Sum: " + sum); // Output: Sum: 30
calculator.greet("Alice"); // Output: Hello, Alice!
}
}
Object-Oriented Programming (OOP) in Java
Java is a pure object-oriented programming language. OOP is a paradigm based on the concept of "objects," which can contain data and code. The four main pillars of OOP are Encapsulation, Inheritance, Polymorphism, and Abstraction.
Classes and Objects
A **class** is a blueprint or a template for creating objects. An **object** is an instance of a class.
public class Car {
// Properties (instance variables)
String model;
String color;
int year;
// Constructor (special method to initialize objects)
public Car(String model, String color, int year) {
this.model = model;
this.color = color;
this.year = year;
}
// Method (behavior)
public void drive() {
System.out.println(color + " " + model + " is driving.");
}
public static void main(String[] args) {
// Creating objects (instances of the Car class)
Car myCar = new Car("Toyota", "Blue", 2023);
System.out.println("My car is a " + myCar.color + " " + myCar.model + " from " + myCar.year + ".");
myCar.drive(); // Output: Blue Toyota is driving.
}
}
Inheritance
Inheritance allows a class (subclass/derived class) to inherit properties and methods from another class (superclass/base class). This promotes code reusability.
class Vehicle { // Superclass
String brand;
public Vehicle(String brand) {
this.brand = brand;
}
public void honk() {
System.out.println("Tuut, tuut!");
}
}
class Bicycle extends Vehicle { // Subclass inheriting from Vehicle
int numberOfGears;
public Bicycle(String brand, int gears) {
super(brand); // Call superclass constructor
this.numberOfGears = gears;
}
public static void main(String[] args) {
Bicycle myBicycle = new Bicycle("Giant", 21);
System.out.println("My bicycle is a " + myBicycle.brand + " with " + myBicycle.numberOfGears + " gears.");
myBicycle.honk(); // Inherited method
}
}
Polymorphism
Polymorphism means "many forms." It allows objects of different classes to be treated as objects of a common base class or interface. This is achieved through method overriding and method overloading.
class Animal {
public void makeSound() { // Method to be overridden
System.out.println("The animal makes a sound");
}
}
class Dog extends Animal {
@Override // Annotation indicating method overriding
public void makeSound() {
System.out.println("The dog barks");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("The cat meows");
}
}
public class PolyExample {
public static void main(String[] args) {
Animal myAnimal = new Animal(); // Animal object
Animal myDog = new Dog(); // Dog object treated as Animal
Animal myCat = new Cat(); // Cat object treated as Animal
myAnimal.makeSound(); // Output: The animal makes a sound
myDog.makeSound(); // Output: The dog barks
myCat.makeSound(); // Output: The cat meows
}
}
Encapsulation
Encapsulation is the bundling of data (attributes) and methods that operate on the data into a single unit (class), and restricting direct access to some of an object's components. This is achieved using access modifiers (`public`, `private`, `protected`, `default`).
public class BankAccount {
private double balance; // Private field, not directly accessible from outside
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
// Public method to modify balance (setter)
public void deposit(double amount) {
if (amount > 0) {
this.balance += amount;
System.out.println("Deposited: " + amount + ". New balance: " + this.balance);
} else {
System.out.println("Deposit amount must be positive.");
}
}
// Public method to access balance (getter)
public double getBalance() {
return balance;
}
public static void main(String[] args) {
BankAccount account = new BankAccount(1000);
account.deposit(500); // Access via public method
System.out.println("Current balance: " + account.getBalance());
// account.balance = 0; // This would cause a compile-time error due to private access
}
}
Abstraction
Abstraction means hiding the complex implementation details and showing only the essential features of the object. This can be achieved using abstract classes and interfaces.
// Abstract class
abstract class Shape {
// Abstract method (no body), must be implemented by concrete subclasses
public abstract double getArea();
// Regular method
public void display() {
System.out.println("This is a shape.");
}
}
// Concrete class inheriting from abstract class
class Circle extends Shape {
double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double getArea() { // Must implement the abstract method
return Math.PI * radius * radius;
}
public static void main(String[] args) {
Circle circle = new Circle(5);
System.out.println("Area of Circle: " + circle.getArea());
circle.display(); // Inherited method
// Shape s = new Shape(); // Cannot instantiate abstract class
}
}
Key Java Features
Exception Handling
Java provides a robust mechanism for handling runtime errors (exceptions) using `try-catch-finally` blocks.
public class ExceptionDemo {
public static void main(String[] args) {
try {
int[] numbers = {1, 2, 3};
System.out.println(numbers[10]); // This will cause an ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Error: Array index out of bounds!");
System.out.println("Message: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Error: Arithmetic operation failed!");
} finally {
System.out.println("The 'try catch' block is finished.");
}
try {
int result = 10 / 0; // This will cause an ArithmeticException
} catch (ArithmeticException e) {
System.out.println("Error: Division by zero!");
}
}
}
Java Collections Framework
The Java Collections Framework provides a unified architecture for representing and manipulating collections, allowing them to be manipulated independently of their implementation details.
- **Interfaces:** `List`, `Set`, `Map`, `Queue`
- **Classes:** `ArrayList`, `LinkedList`, `HashSet`, `TreeSet`, `HashMap`, `TreeMap`
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class CollectionsDemo {
public static void main(String[] args) {
// ArrayList (ordered, allows duplicates, dynamic array)
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Alice");
System.out.println("ArrayList: " + names); // Output: [Alice, Bob, Alice]
// HashSet (unordered, no duplicates)
Set<String> uniqueNames = new HashSet<>();
uniqueNames.add("Alice");
uniqueNames.add("Bob");
uniqueNames.add("Alice"); // Duplicate is ignored
System.out.println("HashSet: " + uniqueNames); // Output: [Alice, Bob] (order may vary)
// HashMap (key-value pairs, unordered)
Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 30);
ages.put("Bob", 25);
System.out.println("HashMap: " + ages); // Output: {Alice=30, Bob=25} (order may vary)
System.out.println("Bob's age: " + ages.get("Bob")); // Output: Bob's age: 25
}
}
Multithreading
Java provides built-in support for multithreading, allowing multiple parts of a program to run concurrently. This is crucial for building responsive and high-performance applications.
- **Extending `Thread` class:** Create a class that extends `java.lang.Thread` and override its `run()` method.
- **Implementing `Runnable` interface:** Create a class that implements `java.lang.Runnable` and override its `run()` method. This is generally preferred as it allows your class to extend other classes.
// Option 1: Extending Thread class
class MyThread extends Thread {
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Thread A: " + i);
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
}
}
// Option 2: Implementing Runnable interface (preferred)
class MyRunnable implements Runnable {
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Thread B: " + i);
try { Thread.sleep(150); } catch (InterruptedException e) {}
}
}
}
public class MultithreadingDemo {
public static void main(String[] args) {
// Create and start Thread A
MyThread threadA = new MyThread();
threadA.start(); // Calls run() method
// Create and start Thread B
Thread threadB = new Thread(new MyRunnable());
threadB.start(); // Calls run() method of MyRunnable instance
for (int i = 0; i < 3; i++) {
System.out.println("Main Thread: " + i);
try { Thread.sleep(120); } catch (InterruptedException e) {}
}
}
}
Lambda Expressions and Streams (Java 8+)
Introduced in Java 8, Lambda Expressions provide a concise way to represent anonymous functions, while the Streams API enables functional-style operations on collections of data.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class LambdaStreamDemo {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");
names.add("David");
// Using Lambda Expression with forEach
System.out.println("Names using Lambda:");
names.forEach(name -> System.out.println(name));
// Using Streams to filter and transform data
List<String> filteredNames = names.stream()
.filter(name -> name.startsWith("A")) // Filter names starting with 'A'
.map(name -> name.toUpperCase()) // Convert to uppercase
.collect(Collectors.toList()); // Collect into a new List
System.out.println("Filtered and Uppercased Names: " + filteredNames); // Output: [ALICE]
// Stream operations for aggregation
int sumOfLengths = names.stream()
.mapToInt(name -> name.length()) // Map to integer stream (lengths)
.sum(); // Sum all lengths
System.out.println("Sum of name lengths: " + sumOfLengths); // Output: 22 (5+3+7+7)
}
}
Conclusion and Next Steps
This tutorial has provided a solid introduction to Java programming, covering its core concepts, OOP principles, and some powerful modern features. Java's robustness, scalability, and vast ecosystem make it a cornerstone of enterprise and Android development. To further your Java journey:
- **Practice regularly** by building diverse Java applications.
- **Explore advanced topics:** Generics, Annotations, Reflection, JDBC for database connectivity.
- **Dive into frameworks:** Spring Framework (Spring Boot for web/microservices), Hibernate (ORM).
- **Learn Android development** if you're interested in mobile apps.
- Consult the official Oracle Java Documentation.