Back to blog

Phase 1: Java Fundamentals - Getting Started with Java

javaprogrammingfundamentalsbeginnerbackend
Phase 1: Java Fundamentals - Getting Started with Java

Welcome to Phase 1

Welcome to the first phase of your Java learning journey! If you're coming from another programming language, you'll find many familiar concepts here. The goal of this phase is to get you comfortable with Java syntax and understand how Java approaches fundamental programming concepts.

This is not a "what is a variable?" tutorial. Instead, we'll focus on Java-specific syntax, conventions, and patterns that differentiate it from other languages you may know.

Time commitment: 2 weeks, 1-2 hours daily
Prerequisite: Programming experience in any language

What You'll Learn

By the end of Phase 1, you'll be able to:

✅ Set up a Java development environment
✅ Write and run Java programs
✅ Understand Java's type system
✅ Use control flow structures effectively
✅ Write methods with proper signatures
✅ Work with arrays and strings
✅ Create basic classes and objects
✅ Understand Java's compilation and execution model

Setting Up Your Environment

1. Install JDK

Download and install the Java Development Kit (JDK):

Recommended: Java 17 LTS or Java 21 LTS

Options:

Verify installation:

java --version
javac --version

Both commands should display version 17+ or 21+.

2. Choose an IDE

IntelliJ IDEA (Recommended):

Alternative options:

  • Eclipse - Mature, free, and widely used
  • VS Code - Lightweight with Java Extension Pack

3. Create Your First Project

In IntelliJ IDEA:

  1. File → New → Project
  2. Select "Java" (not Java Enterprise or Maven/Gradle yet)
  3. Set JDK version to 17 or 21
  4. Create project

Hello World:

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

Run it: Right-click → Run 'HelloWorld.main()'

What's happening:

  • public class HelloWorld - Every Java file must have a class
  • public static void main(String[] args) - Entry point for Java applications
  • System.out.println() - Prints to console (like Python's print() or JavaScript's console.log())

Java Type System

Java is statically typed and strongly typed. Every variable must have a declared type.

Primitive Types

Java has 8 primitive types:

// Integers
byte age = 25;              // 8-bit: -128 to 127
short population = 30000;   // 16-bit: -32,768 to 32,767
int count = 1000000;        // 32-bit: most common integer type
long bigNumber = 10000000000L;  // 64-bit: note the 'L' suffix
 
// Floating-point
float price = 19.99f;       // 32-bit: note the 'f' suffix
double pi = 3.14159265359;  // 64-bit: most common decimal type
 
// Character and Boolean
char grade = 'A';           // 16-bit Unicode character
boolean isActive = true;    // true or false

Key differences from Python/JavaScript:

  • Types are explicit, not inferred (before Java 10)
  • No automatic type conversion between incompatible types
  • Primitives are NOT objects (they don't have methods)

Type Inference with var (Java 10+)

Modern Java supports local type inference:

// Instead of:
String message = "Hello";
ArrayList<String> names = new ArrayList<>();
 
// You can write:
var message = "Hello";         // Type inferred as String
var names = new ArrayList<String>();  // Type inferred as ArrayList<String>

Rules for var:

  • Only for local variables (not fields or method parameters)
  • Requires initialization (compiler needs to infer type)
  • Type is fixed at compile time

When to use var:

// Good: Type is obvious
var username = "john_doe";
var count = 42;
var list = new ArrayList<String>();
 
// Avoid: Type is not obvious
var result = doSomething();  // What type is this?

Wrapper Classes

Every primitive has a corresponding wrapper class:

Integer age = 25;        // Wrapper for int
Double price = 19.99;    // Wrapper for double
Boolean isActive = true; // Wrapper for boolean

Why wrapper classes exist:

  • Collections require objects (can't store primitives directly)
  • Provide utility methods (e.g., Integer.parseInt())
  • Support nullability (primitives can't be null)

Autoboxing and Unboxing:

// Autoboxing: primitive → wrapper
int primitive = 42;
Integer wrapper = primitive;  // Automatic conversion
 
// Unboxing: wrapper → primitive
Integer wrapped = 100;
int value = wrapped;  // Automatic conversion

Variables and Constants

Variable Declaration

// Declaration and initialization
int count = 0;
String name = "Alice";
 
// Declaration without initialization
int value;
// value = ...; // Must initialize before use
 
// Multiple variables
int x = 10, y = 20, z = 30;

Constants

Use final for constants:

final int MAX_SIZE = 100;
final double PI = 3.14159;
 
// MAX_SIZE = 200;  // Compiler error: cannot reassign

Naming conventions:

  • Variables: camelCase (e.g., userName, totalCount)
  • Constants: UPPER_SNAKE_CASE (e.g., MAX_VALUE, DEFAULT_TIMEOUT)
  • Classes: PascalCase (e.g., UserService, OrderProcessor)

Control Flow

Conditional Statements

if-else:

int score = 85;
 
if (score >= 90) {
    System.out.println("Grade: A");
} else if (score >= 80) {
    System.out.println("Grade: B");
} else if (score >= 70) {
    System.out.println("Grade: C");
} else {
    System.out.println("Grade: F");
}

Ternary operator:

String result = score >= 60 ? "Pass" : "Fail";

switch statement (traditional):

int day = 3;
String dayName;
 
switch (day) {
    case 1:
        dayName = "Monday";
        break;
    case 2:
        dayName = "Tuesday";
        break;
    case 3:
        dayName = "Wednesday";
        break;
    default:
        dayName = "Invalid day";
}

switch expressions (Java 14+):

String dayName = switch (day) {
    case 1 -> "Monday";
    case 2 -> "Tuesday";
    case 3 -> "Wednesday";
    default -> "Invalid day";
};

Loops

for loop:

for (int i = 0; i < 5; i++) {
    System.out.println("Count: " + i);
}

Enhanced for loop (for-each):

String[] fruits = {"Apple", "Banana", "Orange"};
 
for (String fruit : fruits) {
    System.out.println(fruit);
}

while loop:

int count = 0;
while (count < 5) {
    System.out.println(count);
    count++;
}

do-while loop:

int i = 0;
do {
    System.out.println(i);
    i++;
} while (i < 5);

Methods

Methods in Java are similar to functions in other languages, but they're always part of a class.

Basic Method Syntax

public class Calculator {
    
    // Method with return value
    public int add(int a, int b) {
        return a + b;
    }
    
    // Method with no return value
    public void printSum(int a, int b) {
        System.out.println("Sum: " + (a + b));
    }
    
    // Method with multiple parameters
    public double calculateAverage(int[] numbers) {
        int sum = 0;
        for (int num : numbers) {
            sum += num;
        }
        return (double) sum / numbers.length;
    }
}

Method Modifiers

public class Example {
    
    // Public: accessible from anywhere
    public void publicMethod() { }
    
    // Private: only accessible within this class
    private void privateMethod() { }
    
    // Static: belongs to class, not instance
    public static void staticMethod() { }
    
    // Final: cannot be overridden
    public final void finalMethod() { }
}

Method Overloading

Java supports method overloading (same name, different parameters):

public class MathOperations {
    
    public int add(int a, int b) {
        return a + b;
    }
    
    public double add(double a, double b) {
        return a + b;
    }
    
    public int add(int a, int b, int c) {
        return a + b + c;
    }
}
 
// Usage
MathOperations math = new MathOperations();
int sum1 = math.add(5, 10);          // Calls first method
double sum2 = math.add(5.5, 10.5);   // Calls second method
int sum3 = math.add(5, 10, 15);      // Calls third method

Arrays

Arrays in Java are fixed-size, homogeneous data structures.

Array Declaration and Initialization

// Declaration and initialization
int[] numbers = {1, 2, 3, 4, 5};
 
// Declaration with size, then initialization
int[] values = new int[5];
values[0] = 10;
values[1] = 20;
// ...
 
// Array length
System.out.println("Length: " + numbers.length);  // 5

Multidimensional Arrays

// 2D array
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};
 
// Access elements
int value = matrix[1][2];  // 6
 
// Iterate 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();
}

Common Array Operations

import java.util.Arrays;
 
int[] numbers = {5, 2, 8, 1, 9};
 
// Sort
Arrays.sort(numbers);  // {1, 2, 5, 8, 9}
 
// Search (requires sorted array)
int index = Arrays.binarySearch(numbers, 5);  // 2
 
// Copy
int[] copy = Arrays.copyOf(numbers, numbers.length);
 
// Fill
int[] filled = new int[5];
Arrays.fill(filled, 10);  // {10, 10, 10, 10, 10}
 
// Compare
boolean equal = Arrays.equals(numbers, copy);
 
// Convert to string
String arrayString = Arrays.toString(numbers);  // "[1, 2, 5, 8, 9]"

Strings

Strings in Java are objects, not primitives.

String Basics

// String literals
String greeting = "Hello, World!";
 
// String concatenation
String firstName = "John";
String lastName = "Doe";
String fullName = firstName + " " + lastName;
 
// String length
int length = greeting.length();  // 13
 
// Character access
char firstChar = greeting.charAt(0);  // 'H'

Common String Methods

String text = "  Hello, Java!  ";
 
// Case conversion
text.toUpperCase();        // "  HELLO, JAVA!  "
text.toLowerCase();        // "  hello, java!  "
 
// Trimming
text.trim();               // "Hello, Java!"
 
// Substring
text.substring(2, 7);      // "Hello"
 
// Replace
text.replace("Java", "World");  // "  Hello, World!  "
 
// Split
String[] words = "apple,banana,orange".split(",");  // ["apple", "banana", "orange"]
 
// Check content
text.contains("Java");     // true
text.startsWith("  Hel");  // true
text.endsWith("va!  ");    // true
 
// Comparison
text.equals("Hello");      // false (different content)
text.equalsIgnoreCase("HELLO");  // false

String Immutability

Important: Strings are immutable in Java!

String original = "Hello";
String modified = original.concat(" World");
 
System.out.println(original);  // "Hello" (unchanged)
System.out.println(modified);  // "Hello World" (new string)

StringBuilder for Efficiency

When building strings in loops, use StringBuilder:

// Inefficient (creates many string objects)
String result = "";
for (int i = 0; i < 1000; i++) {
    result += i + ",";
}
 
// Efficient (mutable string builder)
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i).append(",");
}
String result = sb.toString();

Text Blocks (Java 15+)

For multi-line strings:

String json = """
    {
        "name": "John Doe",
        "age": 30,
        "email": "john@example.com"
    }
    """;

Basic Classes and Objects

Creating a Simple Class

public class Person {
    // Fields (instance variables)
    String name;
    int age;
    
    // Constructor
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // Method
    public void introduce() {
        System.out.println("Hi, I'm " + name + " and I'm " + age + " years old.");
    }
}
 
// Usage
Person person = new Person("Alice", 25);
person.introduce();  // "Hi, I'm Alice and I'm 25 years old."

Getters and Setters

public class Account {
    private double balance;  // Private field
    
    // Getter
    public double getBalance() {
        return balance;
    }
    
    // Setter
    public void setBalance(double balance) {
        if (balance >= 0) {
            this.balance = balance;
        }
    }
}

We'll explore classes and objects in much more depth in Phase 2: Object-Oriented Programming.

Compilation and Execution Model

How Java Works

  1. Write Java source code (.java files)
  2. Compile to bytecode (.class files) using javac
  3. Execute bytecode on the JVM using java
# Compile
javac HelloWorld.java
 
# Run
java HelloWorld

The Java Virtual Machine (JVM)

Key concept: Java is "write once, run anywhere"

  • Java code compiles to bytecode (platform-independent)
  • JVM interprets bytecode for your specific OS
  • No need to recompile for different platforms

This means:

  • Same Java program runs on Windows, macOS, Linux
  • No platform-specific builds needed
  • JVM handles memory management (garbage collection)

Best Practices for Phase 1

1. Follow Naming Conventions

// Good
public class UserService { }
private String userName;
public static final int MAX_RETRY = 3;
 
// Bad
public class userservice { }
private String UserName;
public static final int maxRetry = 3;

2. Use Meaningful Names

// Good
int studentCount = 50;
String customerEmail = "user@example.com";
 
// Bad
int n = 50;
String str = "user@example.com";

3. Keep Methods Small

// Good: Single responsibility
public boolean isValidEmail(String email) {
    return email != null && email.contains("@");
}
 
// Bad: Too many responsibilities
public void processUser(String name, String email, int age) {
    // Validate name
    // Validate email
    // Validate age
    // Create user
    // Save to database
    // Send welcome email
}

4. Use var When Type is Obvious

// Good
var username = "john_doe";
var count = users.size();
 
// Avoid
var data = process();  // What type is this?

Common Pitfalls

❌ Using == for String Comparison

String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
 
s1 == s2;  // true (string pool)
s1 == s3;  // false (different objects)
 
// ✅ Always use .equals()
s1.equals(s3);  // true

❌ Array Index Out of Bounds

int[] numbers = {1, 2, 3};
int last = numbers[3];  // ArrayIndexOutOfBoundsException
 
// ✅ Use length - 1
int last = numbers[numbers.length - 1];

❌ Forgetting to Initialize Variables

int count;
System.out.println(count);  // Compiler error
 
// ✅ Always initialize
int count = 0;

❌ Modifying Arrays in Enhanced For Loop

int[] numbers = {1, 2, 3};
for (int num : numbers) {
    num = num * 2;  // Doesn't modify array!
}
 
// ✅ Use traditional for loop
for (int i = 0; i < numbers.length; i++) {
    numbers[i] = numbers[i] * 2;
}

Practice Exercises

Reinforce your learning with these exercises:

  1. Temperature Converter: Write a program that converts Celsius to Fahrenheit and vice versa
  2. Array Statistics: Calculate min, max, average, and sum of an integer array
  3. String Reverser: Reverse a string without using built-in methods
  4. Prime Number Checker: Determine if a number is prime
  5. FizzBuzz: Print numbers 1-100, but "Fizz" for multiples of 3, "Buzz" for 5, "FizzBuzz" for both

Summary

You've now covered the essential Java fundamentals:

✅ Set up Java development environment
✅ Understand Java's type system (primitives, wrappers, var)
✅ Use control flow structures (if, switch, loops)
✅ Write methods with proper signatures
✅ Work with arrays and strings
✅ Create basic classes and objects
✅ Understand compilation and execution model

Next Steps

You're ready to move to Phase 2: Object-Oriented Programming, where you'll learn:

  • Classes and objects in depth
  • Inheritance and polymorphism
  • Interfaces and abstract classes
  • Encapsulation and access modifiers
  • Design principles and patterns

🚀 Continue to Phase 2: Object-Oriented Programming →


Previous: Java Learning Roadmap ←
Next: Phase 2: Object-Oriented Programming →

Happy coding! ☕

📬 Subscribe to Newsletter

Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.

We respect your privacy. Unsubscribe at any time.

💬 Comments

Sign in to leave a comment

We'll never post without your permission.