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, 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.

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.

  • 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.

  2. Compile the Code:
    Open your terminal or command prompt and navigate to the directory where you saved HelloWorld.java. Compile the code using the javac command:

     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:

     java HelloWorld
    

    Output:

     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

    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:

    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:

    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:

    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:

    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:

    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:

    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:

    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:

    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:

    int num = 10;
    int *ptr = #
    printf("%d\n", *ptr);

In 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

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

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:

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

final type CONSTANT_NAME = value;
  • By convention, constant names are written in UPPERCASE with underscores (_) separating words.

Example

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:

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:

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:

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:

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:

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:

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

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

Output:

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

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

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:

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

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

Example

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

Output:

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

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

Example with Arrays

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:

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

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:

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

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

Example

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

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

Output:

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

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

Example

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

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

Output:

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 StructureWhen to Use
if, else, else ifFor conditional execution based on different criteria.
for loopWhen the number of iterations is known in advance.
Enhanced for-eachWhen iterating over arrays or collections.
while loopWhen the loop depends on a condition and the iterations are unknown.
do-while loopWhen 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.

     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.

     int[] nums = {1, 2, 3, 4, 5};
    
  3. Alternative Declaration Syntax:
    Both of these are valid:

     int arr[] = new int[5]; // Alternative syntax (less preferred)
    

Example

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:

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

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

Example

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:

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

arrayName.length

Example

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:

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

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

Initializing with Values

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

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:

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

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:

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.

     String name = "John";
    
  2. Using the new Keyword
    This explicitly creates a new String object.

     String name = new String("John");
    

Example

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:

Name1: John
Name2: Doe

Common String Operations

Concatenation

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

Example:

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:

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:

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

Output:

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:

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:

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:

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:

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:

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:

Uppercase: JAVA PROGRAMMING
Lowercase: java programming

Other Useful String Methods

  1. trim(): Removes leading and trailing whitespace.

     String str = "   Hello   ";
     System.out.println(str.trim()); // Output: "Hello"
    
  2. charAt(int index): Returns the character at the specified index.

     String str = "Java";
     System.out.println(str.charAt(1)); // Output: 'a'
    
  3. replace(char oldChar, char newChar): Replaces all occurrences of oldChar with newChar.

     String str = "banana";
     System.out.println(str.replace('a', 'o')); // Output: "bonono"
    
  4. contains(CharSequence sequence): Checks if the string contains the specified sequence.

     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:

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

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

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

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

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

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

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

CollectionDescriptionAllows DuplicatesOrder
ArrayListResizable list of elementsYesMaintains order
HashSetUnordered set of unique elementsNoNo order
HashMapKey-value pairs for fast lookupNo (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

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

Example with ArrayList

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

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:

     import java.util.Scanner;
    
  2. Create a Scanner Object:
    Create an instance of Scanner to read from standard input (System.in).

     Scanner sc = new Scanner(System.in);
    
  3. Read a String:
    Use nextLine() to read an entire line of input.

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

Full Example

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:

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

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:

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

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:

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

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:

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

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:

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:

      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:

      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:

      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:

      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:

      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:

      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:

      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:

      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:

      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:

      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:

      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:

      #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

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

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

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

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

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] + " ");
        }
    }
}
23
Subscribe to my newsletter

Read articles from Jyotiprakash Mishra directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jyotiprakash Mishra
Jyotiprakash Mishra

I am Jyotiprakash, a deeply driven computer systems engineer, software developer, teacher, and philosopher. With a decade of professional experience, I have contributed to various cutting-edge software products in network security, mobile apps, and healthcare software at renowned companies like Oracle, Yahoo, and Epic. My academic journey has taken me to prestigious institutions such as the University of Wisconsin-Madison and BITS Pilani in India, where I consistently ranked among the top of my class. At my core, I am a computer enthusiast with a profound interest in understanding the intricacies of computer programming. My skills are not limited to application programming in Java; I have also delved deeply into computer hardware, learning about various architectures, low-level assembly programming, Linux kernel implementation, and writing device drivers. The contributions of Linus Torvalds, Ken Thompson, and Dennis Ritchie—who revolutionized the computer industry—inspire me. I believe that real contributions to computer science are made by mastering all levels of abstraction and understanding systems inside out. In addition to my professional pursuits, I am passionate about teaching and sharing knowledge. I have spent two years as a teaching assistant at UW Madison, where I taught complex concepts in operating systems, computer graphics, and data structures to both graduate and undergraduate students. Currently, I am an assistant professor at KIIT, Bhubaneswar, where I continue to teach computer science to undergraduate and graduate students. I am also working on writing a few free books on systems programming, as I believe in freely sharing knowledge to empower others.