# Basics of Java for C Programmers

### **Why Learn Java After C?**

As a C programmer, you are already familiar with low-level programming, manual memory management, and efficient code execution. So why learn Java? Here are some compelling reasons:

1. **Portability**:  
    Java follows the mantra of **"Write Once, Run Anywhere."** Java programs are compiled into platform-independent bytecode, which can be executed on any system with a Java Virtual Machine (JVM). This means you don’t need to worry about platform-specific details, making Java an ideal choice for cross-platform development.
    
2. **Built-in Memory Management**:  
    Java eliminates the need for manual memory management with its **automatic garbage collection**. In C, you have to allocate and free memory explicitly, which can lead to errors like memory leaks or dangling pointers. Java’s garbage collector handles memory deallocation, reducing the chances of such bugs.
    
3. **Rich Standard Library**:  
    Java provides a comprehensive **standard library** (`java.lang`, `java.util`, [`java.io`](http://java.io), etc.) that makes it easier to perform common tasks such as:
    
    * String manipulation
        
    * Data structures (lists, sets, maps)
        
    * File I/O
        
    * Networking
        
    * Multithreading  
        These built-in libraries reduce the need to reinvent the wheel and speed up development.
        
4. **Object-Oriented Programming (OOP)**:  
    While C is procedural, Java promotes an object-oriented approach. Even if you’re focusing on basic Java, understanding OOP will help you build modular, reusable, and maintainable code when you’re ready to explore it further.
    
5. **Security and Robustness**:  
    Java provides a secure execution environment and robust error handling via **exceptions**. The language’s strict type-checking and absence of pointers help prevent common vulnerabilities like buffer overflows.
    

#### **Hello World in Java**

Let’s start with the classic **"Hello, World!"** program to understand the basic structure of a Java program.

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

#### **Explanation of the Code**

* `public`:  
    This is an access modifier. It makes the class and the `main` method accessible from anywhere. In Java, the `main` method must be `public` because it needs to be called by the JVM when the program starts.
    
* `class`:  
    Defines a class named `HelloWorld`. In Java, all code must be inside a class. A class is a blueprint for objects, but in this simple example, it just serves as a container for the `main` method.
    
* `HelloWorld`:  
    The name of the class. The class name must match the filename. For example, if your class is named `HelloWorld`, the file must be saved as [`HelloWorld.java`](http://HelloWorld.java).
    
* `static`:  
    The `main` method is `static`, which means it belongs to the class itself and not to any object. The JVM can call the `main` method directly without creating an instance of the class.
    
* `void`:  
    The return type of the `main` method. `void` means the method does not return any value.
    
* `main`:  
    The entry point of any Java program. The JVM looks for this method to start execution.
    
* `String[] args`:  
    The `main` method accepts an array of `String` arguments, which can be passed from the command line when the program runs.
    
* `System.out.println("Hello, World!");`:
    
    * `System`: A built-in class that provides access to system resources.
        
    * `out`: A static field in `System` that represents the standard output stream (console).
        
    * `println`: A method that prints the provided string and moves to the next line.
        

#### **Compiling and Running Java Code**

1. **Save the File**:  
    Save the code in a file named [`HelloWorld.java`](http://HelloWorld.java).
    
2. **Compile the Code**:  
    Open your terminal or command prompt and navigate to the directory where you saved [`HelloWorld.java`](http://HelloWorld.java). Compile the code using the `javac` command:
    
    ```bash
    javac HelloWorld.java
    ```
    
    This will generate a file named `HelloWorld.class`, which contains the bytecode.
    
3. **Run the Code**:  
    Execute the program using the `java` command:
    
    ```bash
    java HelloWorld
    ```
    
    **Output**:
    
    ```java
    Hello, World!
    ```
    
    ### **Basic Syntax and Data Types in Java**
    
    In this section, we will explore Java’s primitive data types, compare them with C types, and highlight key differences such as type safety and the absence of pointers.
    
    ### **Primitives in Java**
    
    Java has eight primitive data types, similar to those in C, but with a few notable differences. Here is a comparison:
    
      
    **Code Examples**
    
    ```java
    public class PrimitiveDemo {
        public static void main(String[] args) {
            byte b = 10;
            short s = 200;
            int i = 10000;
            long l = 123456789L; // Note the 'L' suffix for long literals
    
            float f = 3.14f;    // Note the 'f' suffix for float literals
            double d = 3.141592653589793;
    
            char c = 'A';
            boolean isJavaFun = true;
    
            System.out.println("byte: " + b);
            System.out.println("short: " + s);
            System.out.println("int: " + i);
            System.out.println("long: " + l);
            System.out.println("float: " + f);
            System.out.println("double: " + d);
            System.out.println("char: " + c);
            System.out.println("boolean: " + isJavaFun);
        }
    }
    ```
    
    **Output**:
    
    ```java
    byte: 10
    short: 200
    int: 10000
    long: 123456789
    float: 3.14
    double: 3.141592653589793
    char: A
    boolean: true
    ```
    
    ### **Type Safety in Java**
    
    Java enforces **strict type safety**, meaning variables must be declared with a specific type and cannot change to another type during execution. Unlike C, Java does not allow implicit conversion between unrelated types.
    
    For example, the following code would result in an error:
    
    ```java
    int num = 5;
    // num = "Hello"; // Compilation error: incompatible types
    ```
    
    ### **Type Promotion and Conversion**
    
    In Java, type promotion and type conversion work similarly to C, but with stricter rules to ensure safety. Let’s explore **widening** and **narrowing** conversions.
    
    #### **Widening Conversion (Automatic Type Promotion)**
    
    Widening occurs when a smaller data type is converted to a larger data type. This happens automatically in Java because it’s safe and there is no risk of data loss.
    
    **Example**:
    
    ```java
    public class WideningDemo {
        public static void main(String[] args) {
            int intValue = 100;
            long longValue = intValue; // int to long (widening)
            double doubleValue = longValue; // long to double (widening)
    
            System.out.println("int value: " + intValue);
            System.out.println("long value: " + longValue);
            System.out.println("double value: " + doubleValue);
        }
    }
    ```
    
    **Output**:
    
    ```java
    int value: 100
    long value: 100
    double value: 100.0
    ```
    
    #### **Narrowing Conversion (Explicit Casting)**
    
    Narrowing occurs when converting a larger data type to a smaller data type. This requires explicit casting because there is a risk of data loss.
    
    **Example**:
    
    ```java
    public class NarrowingDemo {
        public static void main(String[] args) {
            double doubleValue = 123.456;
            int intValue = (int) doubleValue; // Explicit cast from double to int
    
            System.out.println("double value: " + doubleValue);
            System.out.println("int value: " + intValue);
        }
    }
    ```
    
    **Output**:
    
    ```java
    double value: 123.456
    int value: 123
    ```
    
    Notice that the fractional part is truncated when casting from `double` to `int`.
    
    #### **Type Promotion in Expressions**
    
    In Java, when you mix different data types in an expression, smaller types are promoted to larger types.
    
    **Example**:
    
    ```java
    public class TypePromotionDemo {
        public static void main(String[] args) {
            byte b = 10;
            short s = 20;
            int result = b + s; // byte and short are promoted to int
    
            System.out.println("Result: " + result);
        }
    }
    ```
    
    **Output**:
    
    ```java
    Result: 30
    ```
    
    ### **No Pointers in Java**
    
    Unlike C, Java does not support pointers. Instead, Java uses references to manage memory. This design choice:
    
    1. **Prevents direct memory manipulation**, reducing errors like segmentation faults.
        
    2. **Enhances security** by not exposing memory addresses.
        
    3. **Simplifies programming** by allowing garbage collection to manage memory automatically.
        
    
    **In C**:
    
    ```c
    int num = 10;
    int *ptr = &num;
    printf("%d\n", *ptr);
    ```
    
    **In Java**:
    
    ```java
    Integer num = 10;
    System.out.println(num);
    ```
    
    In Java, objects are manipulated via references, but these references cannot be used to perform pointer arithmetic.
    

### **Variables and Constants in Java**

In Java, understanding how to declare, initialize, and use variables and constants is crucial. This section explores these concepts, including scope and lifetime.

### **Declaration and Initialization of Variables**

In Java, a variable must be **declared with a specific type** before use. Declaration and initialization can happen separately or together.

#### **Syntax**

```java
type variableName = value;
```

* `type`: The data type of the variable (`int`, `double`, `String`, etc.).
    
* `variableName`: The identifier name for the variable.
    
* `value`: The initial value assigned to the variable.
    

#### **Examples**

```java
public class VariableDemo {
    public static void main(String[] args) {
        // Declaration and initialization
        int num = 5;
        double pi = 3.14;
        String name = "Alice";

        // Declaration first, then initialization
        int age;
        age = 20;

        System.out.println("num: " + num);
        System.out.println("pi: " + pi);
        System.out.println("name: " + name);
        System.out.println("age: " + age);
    }
}
```

**Output**:

```java
num: 5
pi: 3.14
name: Alice
age: 20
```

### **Constants in Java**

A **constant** is a variable whose value cannot be changed after it is initialized. In Java, constants are declared using the `final` keyword.

#### **Syntax**

```java
final type CONSTANT_NAME = value;
```

* By convention, constant names are written in **UPPERCASE** with underscores (`_`) separating words.
    

#### **Example**

```java
public class ConstantDemo {
    public static void main(String[] args) {
        final double TAX_RATE = 0.18;
        final int MAX_SCORE = 100;

        System.out.println("Tax Rate: " + TAX_RATE);
        System.out.println("Max Score: " + MAX_SCORE);

        // Attempting to change the constant will result in a compilation error
        // TAX_RATE = 0.20; // Error: cannot assign a value to final variable 'TAX_RATE'
    }
}
```

**Output**:

```java
Tax Rate: 0.18
Max Score: 100
```

#### **Why Use Constants?**

* **Readability**: Constants make the code more understandable.
    
* **Maintainability**: Easier to update values in one place rather than multiple locations.
    
* **Prevents Errors**: Ensures values do not change accidentally.
    

### **Scope and Lifetime of Variables**

In Java, the **scope** of a variable refers to the region of the program where the variable can be accessed, and the **lifetime** refers to how long the variable exists in memory.

#### **Types of Scope**

1. **Local Scope (Block Scope)**
    
2. **Class Scope (Instance and Static Variables)**
    
3. **Method Parameters**
    

#### **1\. Local Scope (Block Scope)**

A **local variable** is declared within a block of code (e.g., inside a method, loop, or conditional). It is accessible **only within that block**.

* **Lifetime**: Exists only during the execution of the block.
    
* **Must be initialized before use**.
    

**Example**:

```java
public class ScopeDemo {
    public static void main(String[] args) {
        int num = 10; // Declared in the main method (method scope)

        if (num > 5) {
            int blockVar = 20; // Local to the if-block
            System.out.println("Inside if-block: " + blockVar);
        }

        // System.out.println(blockVar); // Error: blockVar is out of scope

        for (int i = 0; i < 3; i++) {
            System.out.println("Loop iteration: " + i);
        }

        // System.out.println(i); // Error: i is out of scope
    }
}
```

**Output**:

```java
Inside if-block: 20
Loop iteration: 0
Loop iteration: 1
Loop iteration: 2
```

**Explanation**:

* `blockVar` is only accessible within the `if` block.
    
* `i` is declared in the `for` loop and is inaccessible outside the loop.
    

#### **2\. Class Scope (Instance and Static Variables)**

* **Instance Variables**: Declared within a class but outside any method. They are tied to an instance of the class.
    
* **Static Variables**: Declared with the `static` keyword and shared among all instances of the class.
    

**Example**:

```java
public class ClassScopeDemo {
    int instanceVar = 10; // Instance variable
    static int staticVar = 20; // Static variable

    public static void main(String[] args) {
        ClassScopeDemo obj = new ClassScopeDemo();
        System.out.println("Instance variable: " + obj.instanceVar);
        System.out.println("Static variable: " + staticVar);
    }
}
```

**Output**:

```java
Instance variable: 10
Static variable: 20
```

#### **3\. Method Parameters**

Variables passed as arguments to a method are called **method parameters**. They exist only during the method’s execution.

**Example**:

```java
public class MethodParamDemo {
    public static void main(String[] args) {
        greet("Alice");
    }

    public static void greet(String name) {
        System.out.println("Hello, " + name);
    }
}
```

**Output**:

```java
Hello, Alice
```

### **Summary**

1. **Declaration and Initialization**:
    
    * Variables must be declared with a type.
        
    * Constants use the `final` keyword and follow the `UPPERCASE` naming convention.
        
2. **Scope**:
    
    * **Local Scope**: Variables declared inside blocks are accessible only within those blocks.
        
    * **Class Scope**: Instance and static variables belong to the class.
        
    * **Method Parameters**: Exist only during the method’s execution.
        
3. **Lifetime**:
    
    * Local variables exist only within their block.
        
    * Class variables (instance and static) exist as long as the object or class is in memory.
        

### **Control Structures in Java**

Java provides several control structures that enable programmers to execute code conditionally or repeatedly. If you're familiar with C, you'll find many of these structures familiar. Here, we'll cover **conditional statements** and different types of **loops** with detailed explanations and examples.

## **Conditional Statements**

Java supports the following conditional statements:

* `if`
    
* `else`
    
* `else if`
    

### **Syntax**

```java
if (condition) {
    // Code block if condition is true
} else if (anotherCondition) {
    // Code block if anotherCondition is true
} else {
    // Code block if none of the conditions are true
}
```

### **Example**

```java
public class ConditionalDemo {
    public static void main(String[] args) {
        int age = 20;

        if (age >= 18) {
            System.out.println("Adult");
        } else if (age >= 13) {
            System.out.println("Teenager");
        } else {
            System.out.println("Child");
        }
    }
}
```

**Output**:

```java
Adult
```

### **Explanation**

* `if (age >= 18)`: Checks if the `age` is 18 or older. If true, prints "Adult."
    
* `else if (age >= 13)`: If the first condition is false, checks if the `age` is 13 or older. If true, prints "Teenager."
    
* `else`: If none of the conditions are true, prints "Child."
    

## **Loops**

Loops in Java allow you to execute a block of code repeatedly. Java provides the following types of loops:

1. `for` loop (C-style)
    
2. **Enhanced** `for-each` loop (for collections and arrays)
    
3. `while` loop
    
4. `do-while` loop
    

### `for` Loop (C-style)

The `for` loop is useful when you know the number of iterations in advance.

### **Syntax**

```java
for (initialization; condition; update) {
    // Code block to be executed
}
```

### **Example**

```java
public class ForLoopDemo {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            System.out.println("Iteration: " + i);
        }
    }
}
```

**Output**:

```java
Iteration: 0
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
```

### **Explanation**

* **Initialization**: `int i = 0` initializes the loop counter.
    
* **Condition**: `i < 5` checks if `i` is less than 5. The loop stops when this condition becomes false.
    
* **Update**: `i++` increments `i` by 1 after each iteration.
    

### **Enhanced** `for-each` Loop

The enhanced `for` loop (also known as a `for-each` loop) is ideal for iterating over arrays or collections.

### **Syntax**

```java
for (type variable : collection) {
    // Code block to be executed for each element
}
```

### **Example with Arrays**

```java
public class ForEachDemo {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};

        for (int num : numbers) {
            System.out.println("Number: " + num);
        }
    }
}
```

**Output**:

```java
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
```

### **Explanation**

* `int num : numbers` iterates through each element of the `numbers` array.
    
* The loop automatically assigns the current element to `num` during each iteration.
    

### **Example with Collections**

```java
import java.util.ArrayList;

public class ForEachCollectionDemo {
    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Cherry");

        for (String fruit : fruits) {
            System.out.println("Fruit: " + fruit);
        }
    }
}
```

**Output**:

```java
Fruit: Apple
Fruit: Banana
Fruit: Cherry
```

### `while` Loop

The `while` loop is useful when the number of iterations is unknown and depends on a condition.

### **Syntax**

```java
while (condition) {
    // Code block to be executed as long as the condition is true
}
```

### **Example**

```java
public class WhileLoopDemo {
    public static void main(String[] args) {
        int count = 0;

        while (count < 5) {
            System.out.println("Count: " + count);
            count++;
        }
    }
}
```

**Output**:

```java
Count: 0
Count: 1
Count: 2
Count: 3
Count: 4
```

### **Explanation**

* The loop checks the condition `count < 5` before each iteration.
    
* The variable `count` is incremented each time until it reaches 5.
    

### `do-while` Loop

The `do-while` loop is similar to the `while` loop, but it guarantees at least one execution of the loop body because the condition is checked **after** the loop body executes.

### **Syntax**

```java
do {
    // Code block to be executed
} while (condition);
```

### **Example**

```java
public class DoWhileLoopDemo {
    public static void main(String[] args) {
        int count = 0;

        do {
            System.out.println("Count: " + count);
            count++;
        } while (count < 5);
    }
}
```

**Output**:

```java
Count: 0
Count: 1
Count: 2
Count: 3
Count: 4
```

### **Explanation**

* The loop executes the code block **once** before checking the condition `count < 5`.
    
* If the condition is true, it continues looping; otherwise, it stops.
    

### **Summary**

| **Control Structure** | **When to Use** |
| --- | --- |
| `if`, `else`, `else if` | For conditional execution based on different criteria. |
| `for` loop | When the number of iterations is known in advance. |
| **Enhanced** `for-each` | When iterating over arrays or collections. |
| `while` loop | When the loop depends on a condition and the iterations are unknown. |
| `do-while` loop | When you need to execute the loop at least once. |

### **Arrays in Java**

Arrays in Java are used to store multiple values of the same type in a contiguous block of memory. They provide a simple way to manage collections of data such as integers, doubles, or objects.

### **Declaration and Initialization of Arrays**

#### **Single-Dimensional Arrays**

In Java, arrays are objects that can be declared and initialized in multiple ways.

**Syntax for Declaration and Initialization**

1. **Declaration and Allocation**:  
    This creates an array of a fixed size, with default values initialized.
    
    ```java
    int[] arr = new int[5]; // Creates an array of size 5, initialized with 0s
    ```
    
2. **Declaration and Initialization with Values**:  
    This initializes the array with specified values.
    
    ```java
    int[] nums = {1, 2, 3, 4, 5};
    ```
    
3. **Alternative Declaration Syntax**:  
    Both of these are valid:
    
    ```java
    int arr[] = new int[5]; // Alternative syntax (less preferred)
    ```
    

#### **Example**

```java
public class ArrayDemo {
    public static void main(String[] args) {
        // Declaration and Allocation
        int[] arr = new int[3];
        arr[0] = 10;
        arr[1] = 20;
        arr[2] = 30;

        // Declaration and Initialization
        int[] nums = {1, 2, 3, 4, 5};

        // Accessing Elements
        System.out.println("First element of arr: " + arr[0]);
        System.out.println("Second element of nums: " + nums[1]);
    }
}
```

**Output**:

```java
First element of arr: 10
Second element of nums: 2
```

### **Accessing Elements**

Elements in an array are accessed by their **index**, which starts at 0 (zero-based indexing).

**Syntax**

```java
arrayName[index] = value; // Assign value to a specific index
System.out.println(arrayName[index]); // Retrieve value at a specific index
```

**Example**

```java
public class AccessArray {
    public static void main(String[] args) {
        int[] numbers = {5, 10, 15, 20};

        // Assign a new value to the first element
        numbers[0] = 100;

        // Access elements
        System.out.println("First element: " + numbers[0]);
        System.out.println("Third element: " + numbers[2]);
    }
}
```

**Output**:

```java
First element: 100
Third element: 15
```

### **Length Property**

Each array in Java has a `length` property that provides the number of elements in the array. This is useful for iterating through arrays.

**Syntax**

```java
arrayName.length
```

**Example**

```java
public class ArrayLength {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5};

        System.out.println("Array length: " + numbers.length);

        // Iterating through the array using length
        for (int i = 0; i < numbers.length; i++) {
            System.out.println("Element at index " + i + ": " + numbers[i]);
        }
    }
}
```

**Output**:

```java
Array length: 5
Element at index 0: 1
Element at index 1: 2
Element at index 2: 3
Element at index 3: 4
Element at index 4: 5
```

### **Multidimensional Arrays**

Java supports multidimensional arrays, such as 2D arrays (arrays of arrays). These can be thought of as tables with rows and columns.

#### **Declaration and Initialization**

**Syntax**

```java
int[][] matrix = new int[2][3]; // 2 rows and 3 columns
```

**Initializing with Values**

```java
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6}
};
```

#### **Accessing Elements**

Elements are accessed using two indices: one for the row and one for the column.

**Example**

```java
public class MultiDimensionalArray {
    public static void main(String[] args) {
        int[][] matrix = {
            {1, 2, 3},
            {4, 5, 6}
        };

        // Accessing elements
        System.out.println("Element at row 0, column 1: " + matrix[0][1]);
        System.out.println("Element at row 1, column 2: " + matrix[1][2]);

        // Iterating through the 2D array
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                System.out.print(matrix[i][j] + " ");
            }
            System.out.println();
        }
    }
}
```

**Output**:

```java
Element at row 0, column 1: 2
Element at row 1, column 2: 6
1 2 3 
4 5 6
```

#### **Jagged Arrays**

Java supports **jagged arrays** (arrays with varying column sizes).

**Example**

```java
public class JaggedArray {
    public static void main(String[] args) {
        int[][] jagged = {
            {1, 2},
            {3, 4, 5},
            {6}
        };

        for (int i = 0; i < jagged.length; i++) {
            for (int j = 0; j < jagged[i].length; j++) {
                System.out.print(jagged[i][j] + " ");
            }
            System.out.println();
        }
    }
}
```

**Output**:

```java
1 2 
3 4 5 
6
```

### **Summary**

* **Single-Dimensional Arrays** are declared with `type[] arrayName` and accessed with zero-based indexing.
    
* **Multidimensional Arrays** can represent tables or matrices and are accessed using multiple indices.
    
* The `length` property helps determine the size of an array.
    
* **Jagged Arrays** allow each row to have a different number of columns.
    

Arrays provide a fundamental way to store and manipulate collections of data efficiently in Java.

### **Strings in Java**

In Java, strings are a sequence of characters and are represented by the `String` class. Unlike C, where strings are character arrays, Java strings are **objects**. They are **immutable**, meaning once a string is created, its contents cannot be changed.

### **String Basics**

#### **Declaration and Initialization**

Strings can be created in two ways:

1. **Using String Literals**  
    This is the most common way to create a string.
    
    ```java
    String name = "John";
    ```
    
2. **Using the** `new` Keyword  
    This explicitly creates a new `String` object.
    
    ```java
    String name = new String("John");
    ```
    

#### **Example**

```java
public class StringBasics {
    public static void main(String[] args) {
        String name1 = "John";
        String name2 = new String("Doe");

        System.out.println("Name1: " + name1);
        System.out.println("Name2: " + name2);
    }
}
```

**Output**:

```java
Name1: John
Name2: Doe
```

### **Common String Operations**

#### **Concatenation**

Strings can be concatenated using the `+` operator or the `concat()` method.

**Example**:

```java
public class StringConcatenation {
    public static void main(String[] args) {
        String firstName = "John";
        String lastName = "Doe";

        // Using the + operator
        String fullName1 = firstName + " " + lastName;
        System.out.println("Full Name (using +): " + fullName1);

        // Using the concat() method
        String fullName2 = firstName.concat(" ").concat(lastName);
        System.out.println("Full Name (using concat): " + fullName2);
    }
}
```

**Output**:

```java
Full Name (using +): John Doe
Full Name (using concat): John Doe
```

#### **Length**

You can find the length of a string using the `length()` method.

**Example**:

```java
public class StringLength {
    public static void main(String[] args) {
        String name = "John Doe";
        System.out.println("Length of the string: " + name.length());
    }
}
```

**Output**:

```java
Length of the string: 8
```

#### **Substring**

The `substring()` method extracts a portion of the string. It takes one or two arguments:

* `substring(int beginIndex)`: Extracts from `beginIndex` to the end.
    
* `substring(int beginIndex, int endIndex)`: Extracts from `beginIndex` to `endIndex - 1`.
    

**Example**:

```java
public class StringSubstring {
    public static void main(String[] args) {
        String sentence = "Hello, World!";

        // Extracting "World"
        String word = sentence.substring(7, 12);
        System.out.println("Extracted word: " + word);

        // Extracting from index 7 to the end
        String partial = sentence.substring(7);
        System.out.println("Partial string: " + partial);
    }
}
```

**Output**:

```java
Extracted word: World
Partial string: World!
```

#### **Comparison**

Java provides multiple methods for comparing strings:

1. `equals()`: Checks if two strings have the same content.
    
2. `equalsIgnoreCase()`: Compares strings, ignoring case.
    
3. `compareTo()`: Lexicographically compares two strings (returns `0` if equal, a positive number if the first string is greater, and a negative number if the second string is greater).
    

**Example**:

```java
public class StringComparison {
    public static void main(String[] args) {
        String str1 = "Hello";
        String str2 = "hello";
        String str3 = "Hello";

        // Case-sensitive comparison
        System.out.println("str1 equals str2: " + str1.equals(str2));
        System.out.println("str1 equals str3: " + str1.equals(str3));

        // Case-insensitive comparison
        System.out.println("str1 equalsIgnoreCase str2: " + str1.equalsIgnoreCase(str2));

        // Lexicographical comparison
        System.out.println("str1 compareTo str2: " + str1.compareTo(str2));
    }
}
```

**Output**:

```java
str1 equals str2: false
str1 equals str3: true
str1 equalsIgnoreCase str2: true
str1 compareTo str2: -32
```

#### **Case Conversion**

Java provides methods to convert string cases:

* `toUpperCase()`: Converts the string to uppercase.
    
* `toLowerCase()`: Converts the string to lowercase.
    

**Example**:

```java
public class StringCaseConversion {
    public static void main(String[] args) {
        String text = "Java Programming";

        System.out.println("Uppercase: " + text.toUpperCase());
        System.out.println("Lowercase: " + text.toLowerCase());
    }
}
```

**Output**:

```java
Uppercase: JAVA PROGRAMMING
Lowercase: java programming
```

### **Other Useful String Methods**

1. `trim()`: Removes leading and trailing whitespace.
    
    ```java
    String str = "   Hello   ";
    System.out.println(str.trim()); // Output: "Hello"
    ```
    
2. `charAt(int index)`: Returns the character at the specified index.
    
    ```java
    String str = "Java";
    System.out.println(str.charAt(1)); // Output: 'a'
    ```
    
3. `replace(char oldChar, char newChar)`: Replaces all occurrences of `oldChar` with `newChar`.
    
    ```java
    String str = "banana";
    System.out.println(str.replace('a', 'o')); // Output: "bonono"
    ```
    
4. `contains(CharSequence sequence)`: Checks if the string contains the specified sequence.
    
    ```java
    String str = "Hello, World!";
    System.out.println(str.contains("World")); // Output: true
    ```
    

### **Summary**

* **Strings in Java** are objects and are immutable.
    
* **Concatenation** can be done using `+` or `concat()`.
    
* `length()` returns the string's length.
    
* `substring()` extracts portions of a string.
    
* **Comparison** methods include `equals()`, `equalsIgnoreCase()`, and `compareTo()`.
    
* **Case conversion** can be done using `toUpperCase()` and `toLowerCase()`.
    
* Strings offer a wide range of methods for manipulation and querying.
    

Strings in Java are powerful and flexible, making text processing straightforward and intuitive.

### **Basic Collections in Java**

Java collections are part of the **Java Collections Framework**, providing powerful data structures to manage groups of objects. The three most commonly used collections are:

1. `ArrayList` – A resizable list.
    
2. `HashSet` – A collection of unique elements.
    
3. `HashMap` – A key-value mapping.
    

This section introduces these collections, basic operations, and iteration using the enhanced `for` loop. We'll also cover preliminary generics to ensure type safety.

### **Generics in Collections**

Java collections use **generics** to enforce type safety, ensuring that only specified types can be stored in a collection. Generics help prevent runtime errors by catching type mismatches at compile time.

**Syntax for Generics**:

```java
CollectionType<ElementType> collection = new CollectionType<>();
```

For example:

* `ArrayList<Integer>`: A list that holds `Integer` objects.
    
* `HashSet<String>`: A set that holds `String` objects.
    
* `HashMap<String, Integer>`: A map with `String` keys and `Integer` values.
    

### **ArrayList**

An `ArrayList` is a resizable array-like data structure. It allows **duplicate elements** and maintains the **insertion order**.

#### **Declaration and Initialization**

```java
import java.util.ArrayList;

public class ArrayListDemo {
    public static void main(String[] args) {
        // Create an ArrayList of Integers
        ArrayList<Integer> list = new ArrayList<>();

        // Adding elements to the list
        list.add(1);
        list.add(2);
        list.add(3);

        // Accessing elements by index
        System.out.println("First element: " + list.get(0));

        // Iterating through the list using the enhanced for loop
        for (Integer num : list) {
            System.out.println(num);
        }
    }
}
```

#### **Output**

```java
First element: 1
1
2
3
```

#### **Explanation**

1. `list.add(1);`: Adds elements to the `ArrayList`.
    
2. `list.get(0);`: Accesses the first element (index 0).
    
3. **Enhanced for loop**: Iterates through each element of the list.
    

### **HashSet**

A `HashSet` is a collection that does not allow **duplicate elements**. It is unordered, meaning the elements are not guaranteed to be in any specific order.

#### **Declaration and Initialization**

```java
import java.util.HashSet;

public class HashSetDemo {
    public static void main(String[] args) {
        // Create a HashSet of Strings
        HashSet<String> set = new HashSet<>();

        // Adding elements to the set
        set.add("apple");
        set.add("banana");
        set.add("cherry");
        set.add("apple"); // Duplicate element (will be ignored)

        // Displaying the set
        System.out.println("Set elements: " + set);

        // Iterating through the set using the enhanced for loop
        for (String fruit : set) {
            System.out.println(fruit);
        }
    }
}
```

#### **Output**

```java
Set elements: [banana, cherry, apple]
banana
cherry
apple
```

#### **Explanation**

1. `set.add("apple");`: Adds elements to the `HashSet`. Duplicate values are ignored.
    
2. `System.out.println(set);`: Displays the set (order may vary).
    
3. **Enhanced for loop**: Iterates through each element of the set.
    

### **HashMap**

A `HashMap` is a collection that stores key-value pairs. Each key is unique, and each key maps to one value.

#### **Declaration and Initialization**

```java
import java.util.HashMap;

public class HashMapDemo {
    public static void main(String[] args) {
        // Create a HashMap with String keys and Integer values
        HashMap<String, Integer> map = new HashMap<>();

        // Adding key-value pairs to the map
        map.put("age", 25);
        map.put("score", 90);
        map.put("height", 175);

        // Accessing a value by key
        System.out.println("Age: " + map.get("age"));
        System.out.println("Score: " + map.get("score"));
    }
}
```

#### **Output**

```java
Age: 25
Score: 90
```

#### **Explanation**

1. `map.put("age", 25);`: Adds a key-value pair to the `HashMap`.
    
2. `map.get("age");`: Retrieves the value associated with the key `"age"`.
    

### **Summary of Basic Collections**

| **Collection** | **Description** | **Allows Duplicates** | **Order** |
| --- | --- | --- | --- |
| `ArrayList` | Resizable list of elements | Yes | Maintains order |
| `HashSet` | Unordered set of unique elements | No | No order |
| `HashMap` | Key-value pairs for fast lookup | No (keys) | No order |

### **Iteration Using the Enhanced For Loop**

The **enhanced for loop** (also known as the `for-each` loop) provides a simpler way to iterate through collections without using an index or iterator explicitly.

#### **Syntax**

```java
for (ElementType element : collection) {
    // Code to execute for each element
}
```

#### **Example with** `ArrayList`

```java
ArrayList<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie");

for (String name : names) {
    System.out.println(name);
}
```

#### **Example with** `HashSet`

```java
HashSet<Integer> numbers = new HashSet<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);

for (Integer num : numbers) {
    System.out.println(num);
}
```

### **Conclusion**

* `ArrayList`: Use for ordered, resizable lists that allow duplicates.
    
* `HashSet`: Use for unordered collections where duplicates are not allowed.
    
* `HashMap`: Use for key-value mappings.
    
* **Generics** ensure type safety by specifying the element type.
    
* The **enhanced for loop** provides a clean and simple way to iterate through lists and sets.
    

These basic collections cover essential use cases, making it easier to manage and manipulate groups of data in Java.  
**Basic Input/Output in Java**

Java provides easy ways to handle user input and output. The `Scanner` class is commonly used for reading input, and the `System.out.println()` method is used for printing output. This section explores how to use `Scanner` for different input types and how to format and concatenate output.

### **Reading Input Using** `Scanner`

To read input from the user, the `Scanner` class from the `java.util` package is used. The `Scanner` class can handle different types of input, including strings, integers, doubles, and even comma-separated values.

#### **Basic** `Scanner` Usage

1. **Import the** `Scanner` Class:  
    Add the following import statement at the top of your program:
    
    ```java
    import java.util.Scanner;
    ```
    
2. **Create a** `Scanner` Object:  
    Create an instance of `Scanner` to read from standard input ([`System.in`](http://System.in)).
    
    ```java
    Scanner sc = new Scanner(System.in);
    ```
    
3. **Read a String**:  
    Use `nextLine()` to read an entire line of input.
    
    ```java
    System.out.print("Enter your name: ");
    String name = sc.nextLine();
    System.out.println("Hello, " + name);
    ```
    

#### **Full Example**

```java
import java.util.Scanner;

public class BasicInput {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("Enter your name: ");
        String name = sc.nextLine();

        System.out.println("Hello, " + name);
    }
}
```

**Output**:

```java
Enter your name: Alice
Hello, Alice
```

### **Reading Different Data Types**

The `Scanner` class provides methods to read different types of input:

* `nextInt()`: Reads an integer.
    
* `nextDouble()`: Reads a double.
    
* `next()`: Reads a single word (delimited by whitespace).
    
* `nextLine()`: Reads an entire line.
    

#### **Example of Reading Different Data Types**

```java
import java.util.Scanner;

public class DataTypeInput {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("Enter your age: ");
        int age = sc.nextInt();

        System.out.print("Enter your height (in meters): ");
        double height = sc.nextDouble();

        System.out.print("Enter your favorite word: ");
        String word = sc.next();

        // Clear the newline character left by nextInt() or nextDouble()
        sc.nextLine();

        System.out.print("Enter a sentence about yourself: ");
        String sentence = sc.nextLine();

        System.out.println("\nYour Details:");
        System.out.println("Age: " + age);
        System.out.println("Height: " + height);
        System.out.println("Favorite Word: " + word);
        System.out.println("About You: " + sentence);
    }
}
```

**Output**:

```java
Enter your age: 25
Enter your height (in meters): 1.75
Enter your favorite word: Java
Enter a sentence about yourself: I love programming in Java.

Your Details:
Age: 25
Height: 1.75
Favorite Word: Java
About You: I love programming in Java.
```

#### **Note**:

When using `nextInt()` or `nextDouble()`, a newline character remains in the input buffer. To clear it before reading a string with `nextLine()`, use an additional `sc.nextLine()`.

### **Reading Comma-Separated Values**

You can read comma-separated values (CSV) by using `nextLine()` and then splitting the input using the `split()` method.

#### **Example of Reading CSV Input**

```java
import java.util.Scanner;

public class CSVInput {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.print("Enter comma-separated numbers: ");
        String input = sc.nextLine();

        String[] numbers = input.split(",");

        System.out.println("You entered the following numbers:");
        for (String num : numbers) {
            System.out.println(num.trim()); // trim() removes any leading/trailing spaces
        }
    }
}
```

**Output**:

```java
Enter comma-separated numbers: 1, 2, 3, 4, 5
You entered the following numbers:
1
2
3
4
5
```

### **Printing Output**

Java provides the following methods for printing output:

* `System.out.print()`: Prints text without a newline.
    
* `System.out.println()`: Prints text followed by a newline.
    
* `System.out.printf()`: Formats output similarly to `printf` in C.
    

#### **Example**

```java
public class PrintDemo {
    public static void main(String[] args) {
        System.out.print("Hello ");
        System.out.print("World!");
        System.out.println(); // Prints a newline

        System.out.println("This is a new line.");

        // Formatted output
        int age = 25;
        double height = 1.75;
        System.out.printf("I am %d years old and %.2f meters tall.%n", age, height);
    }
}
```

**Output**:

```java
Hello World!
This is a new line.
I am 25 years old and 1.75 meters tall.
```

### **String Concatenation with Other Types**

You can concatenate strings with other data types using the `+` operator.

#### **Example**

```java
public class ConcatenationDemo {
    public static void main(String[] args) {
        String name = "Alice";
        int age = 30;
        double salary = 50000.75;

        // Concatenate strings with other types
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
        System.out.println("Salary: $" + salary);

        // Combining multiple types in a single statement
        System.out.println(name + " is " + age + " years old and earns $" + salary + " annually.");
    }
}
```

**Output**:

```java
Name: Alice
Age: 30
Salary: $50000.75
Alice is 30 years old and earns $50000.75 annually.
```

### **Summary**

* `Scanner` is used for reading different types of input: strings, integers, doubles, and comma-separated values.
    
* Always clear the buffer with `sc.nextLine()` after using `nextInt()` or `nextDouble()` before reading a string.
    
* **Output Methods**:
    
    * `print()`: Prints without a newline.
        
    * `println()`: Prints with a newline.
        
    * `printf()`: Formats output.
        
* **String Concatenation** using `+` allows combining strings with other data types seamlessly.
    

These basic input and output techniques are essential for interacting with users in console-based Java applications.

### **Differences Between Java and C**

Java and C are both powerful programming languages, but they differ significantly in their design philosophy and features. Here are the key differences between the two languages:

### **Memory Management**

* **Java**:  
    Java has **automatic garbage collection**. The Java Virtual Machine (JVM) manages memory, automatically reclaiming unused objects to prevent memory leaks.
    
    **Example**:
    
    ```java
    String name = new String("John");
    // The garbage collector will automatically clean up the object when no longer referenced.
    ```
    
* **C**:  
    In C, memory management is **manual**. You must explicitly allocate (`malloc`, `calloc`) and deallocate (`free`) memory, which can lead to issues like memory leaks and segmentation faults.
    
    **Example**:
    
    ```c
    char* name = (char*)malloc(10 * sizeof(char));
    strcpy(name, "John");
    free(name); // Must manually free the allocated memory.
    ```
    

### **Pointers**

* **Java**:  
    Java does not support pointers. Instead, it uses **references** to objects. This design improves security and robustness by preventing direct memory manipulation.
    
    **Example**:
    
    ```java
    String str = "Hello";
    // No pointer arithmetic or direct memory access.
    ```
    
* **C**:  
    C supports pointers, which allow direct memory access and manipulation. This provides flexibility but can lead to errors like buffer overflows.
    
    **Example**:
    
    ```c
    int num = 10;
    int* ptr = &num;
    printf("%d\n", *ptr);
    ```
    

### **String Handling**

* **Java**:  
    Strings are **objects** and are **immutable** (cannot be changed after creation). Operations on strings produce new string objects.
    
    **Example**:
    
    ```java
    String str = "Hello";
    str = str + " World"; // Creates a new string object.
    System.out.println(str); // Output: Hello World
    ```
    
* **C**:  
    Strings are **character arrays** terminated by a null character (`\0`). They are mutable, and string manipulation functions (like `strcpy`, `strcat`) need to be used carefully to avoid buffer overflows.
    
    **Example**:
    
    ```c
    char str[20] = "Hello";
    strcat(str, " World");
    printf("%s\n", str); // Output: Hello World
    ```
    

### **Error Handling**

* **Java**:  
    Java uses **exceptions** for error handling with `try`, `catch`, and `finally` blocks. This provides a structured way to handle runtime errors.
    
    **Example**:
    
    ```java
    try {
        int result = 10 / 0;
    } catch (ArithmeticException e) {
        System.out.println("Error: Division by zero");
    } finally {
        System.out.println("Cleanup code if needed");
    }
    ```
    
* **C**:  
    C handles errors through **return codes** and **error flags**. There are no built-in exception mechanisms.
    
    **Example**:
    
    ```c
    FILE* file = fopen("nonexistent.txt", "r");
    if (file == NULL) {
        printf("Error: Could not open file\n");
    }
    ```
    

### **Type Safety**

* **Java**:  
    Java is **strictly type-safe**. Variables must be declared with a type and cannot change types during execution. This helps catch errors at compile time.
    
    **Example**:
    
    ```java
    int num = 10;
    // num = "Hello"; // Compile-time error
    ```
    
* **C**:  
    C is **loosely type-safe** and allows implicit type conversions. This can lead to unexpected behavior.
    
    **Example**:
    
    ```c
    int num = 10;
    num = 'A'; // Allowed: Implicit conversion of 'A' to its ASCII value (65)
    ```
    

### **Class-Based**

* **Java**:  
    Java is a **class-based, object-oriented language**. Everything in Java is contained within a class.
    
    **Example**:
    
    ```java
    public class HelloWorld {
        public static void main(String[] args) {
            System.out.println("Hello, World!");
        }
    }
    ```
    
* **C**:  
    C is a **procedural language**. Functions and variables are defined outside of classes.
    
    **Example**:
    
    ```c
    #include <stdio.h>
    
    int main() {
        printf("Hello, World!\n");
        return 0;
    }
    ```
    

### **Practice Examples**

Here are some simple programs to reinforce the basic concepts of Java.

#### **Calculate Factorial**

```java
import java.util.Scanner;

public class Factorial {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter a number: ");
        int num = sc.nextInt();
        int factorial = 1;

        for (int i = 1; i <= num; i++) {
            factorial *= i;
        }

        System.out.println("Factorial of " + num + " is " + factorial);
    }
}
```

#### **Print Fibonacci Series**

```java
import java.util.Scanner;

public class Fibonacci {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter the number of terms: ");
        int n = sc.nextInt();

        int a = 0, b = 1;
        System.out.print("Fibonacci Series: " + a + " " + b);

        for (int i = 2; i < n; i++) {
            int next = a + b;
            System.out.print(" " + next);
            a = b;
            b = next;
        }
    }
}
```

#### **Basic Calculator Using** `Scanner`

```java
import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter first number: ");
        double num1 = sc.nextDouble();

        System.out.print("Enter an operator (+, -, *, /): ");
        char operator = sc.next().charAt(0);

        System.out.print("Enter second number: ");
        double num2 = sc.nextDouble();

        double result;
        switch (operator) {
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num1 - num2;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                result = num1 / num2;
                break;
            default:
                System.out.println("Invalid operator");
                return;
        }

        System.out.println("Result: " + result);
    }
}
```

#### **Count Occurrences of a Character in a String**

```java
import java.util.Scanner;

public class CharCount {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter a string: ");
        String input = sc.nextLine();

        System.out.print("Enter a character to count: ");
        char ch = sc.next().charAt(0);

        int count = 0;
        for (int i = 0; i < input.length(); i++) {
            if (input.charAt(i) == ch) {
                count++;
            }
        }

        System.out.println("Occurrences of '" + ch + "': " + count);
    }
}
```

#### **Reverse an Array**

```java
import java.util.Scanner;

public class ReverseArray {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter the number of elements: ");
        int n = sc.nextInt();

        int[] arr = new int[n];
        System.out.println("Enter elements:");
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }

        System.out.println("Reversed array:");
        for (int i = n - 1; i >= 0; i--) {
            System.out.print(arr[i] + " ");
        }
    }
}
```
