Java Fundamentals

Java Syntax and IDE Setup

IntelliJ IDEA, Java syntax, types, operators, and encapsulation

Recap: What We've Learned

In the previous lectures, we covered:

Today: We write our first Java code! Setting up IntelliJ and learning Java syntax.

Quick Review: Class Relationships

classDiagram
    direction TB
    A -- B : Association
    C o-- D : Aggregation
    E *-- F : Composition
    G <|-- H : Inheritance
            
Association (--) "uses" or "knows about"
Aggregation (o--) "has" - parts can exist independently
Composition (*--) "owns" - parts cannot exist alone
Inheritance (<|--) "is a" - child extends parent

Our Development Tool: IntelliJ IDEA

IntelliJ IDEA is one of the most popular Java IDEs (Integrated Development Environment):

Download: IntelliJ IDEA Community Edition (free) at jetbrains.com/idea

IntelliJ IDEA Interface

Key shortcuts:

Shift + ShiftSearch anything
Ctrl + SpaceCode completion
Alt + EnterQuick fixes and suggestions
Ctrl + /Comment/uncomment line
Shift + F10Run current program

Creating Your First Project

  1. Open IntelliJ IDEA
  2. Click New Project
  3. Select Java (left panel)
  4. Choose your JDK (Java 17+ recommended)
    • If no JDK listed, click "Download JDK" and select a version
  5. Name your project: JavaExercises
  6. Click Create
IntelliJ automatically creates a src folder for your source code.

Creating a Java Class

  1. Right-click on the src folder
  2. Select New → Java Class
  3. Enter: fr.wayup.exercises.HelloWorld
    • This creates a package fr.wayup.exercises and class HelloWorld
  4. Press Enter
package fr.wayup.exercises;

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

Click the green play button or press Shift+F10 to run!

Anatomy of a Java Class

package fr.wayup.exercises; 

public class JavaSyntaxDemo { 
    private String demoVersion = "1.0"; 

    public JavaSyntaxDemo() { 
        // Initialization code
    }

    public String getDemoVersion() { 
        return this.demoVersion;
    }
}
Package - Namespace to organize classes
Class declaration - Blueprint for objects
Field - Property/attribute of the class
Constructor - Same name as class, no return type
Method - Behavior with return type

Basic Code Elements

Packages and Imports

Packages organize your classes and prevent naming conflicts:

package fr.wayup.banking;  // This class belongs to this package

import java.util.ArrayList;  // Import a specific class
import java.time.*;          // Import all classes from a package

public class Account {
    private ArrayList transactions;
    private LocalDate openDate;
}

Two Kinds of Types in Java

Primitive Types Reference Types (Objects)
Built into the language Created from classes
Stored directly in memory Stored as references (pointers)
Lowercase names: int, double Uppercase names: String, ArrayList
Have default values (0, false) Default to null
Cannot be null Can be null
int count = 10;              // Primitive
String message = "Hello";    // Reference (Object)

Primitive Types: Integers

Type Size Range Example
byte 1 byte -128 to 127 byte b = 100;
short 2 bytes -32,768 to 32,767 short s = 1000;
int 4 bytes ±2.1 billion int i = 100000;
long 8 bytes ±9.2 quintillion long l = 100000L;
Most common: Use int for most integer values. Use long with L suffix for large numbers.

Primitive Types: Floating Point

Type Size Precision Example
float 4 bytes ~7 decimal digits float f = 3.14f;
double 8 bytes ~15 decimal digits double d = 3.14159;
float price = 19.99f;      // Note the 'f' suffix
double pi = 3.14159265359; // Default for decimals
double scientific = 1.5e10; // Scientific notation: 1.5 × 10^10
Most common: Use double for decimal numbers (it's the default).

Primitive Types: Boolean and Char

Type Size Values Example
boolean 1 bit* true or false boolean active = true;
char 2 bytes Unicode character char grade = 'A';
boolean isLoggedIn = false;
boolean hasPermission = true;

char firstLetter = 'A';       // Single quotes for char
char unicode = '\u0041';      // Unicode: also 'A'
char newline = '\n';          // Escape character
Note: char uses single quotes 'A', while String uses double quotes "Hello"

The String Type

String is a reference type (object), but it's used so often it has special syntax:

// String creation
String greeting = "Hello, World!";  // String literal
String name = new String("Alice");  // Using constructor (rarely needed)

// String operations
String fullName = "John" + " " + "Doe";  // Concatenation
int length = greeting.length();          // 13
String upper = greeting.toUpperCase();   // "HELLO, WORLD!"
boolean starts = greeting.startsWith("Hello"); // true
String sub = greeting.substring(0, 5);   // "Hello"
Important: Strings are immutable - methods return new strings, they don't modify the original.

Local Variable Type Inference: var

Since Java 10, you can use var to let the compiler infer the type:

// Traditional declarations
String message = "Hello";
ArrayList<String> names = new ArrayList<String>();
Map<String, List<Integer>> data = new HashMap<String, List<Integer>>();

// With var - compiler infers the type
var message = "Hello";                    // Inferred as String
var names = new ArrayList<String>();      // Inferred as ArrayList<String>
var data = new HashMap<String, List<Integer>>();  // Much cleaner!
Note: var only works for local variables with initializers. Not for fields, parameters, or return types.

When to Use var

Good Uses

// Type is obvious from right side
var count = 0;
var name = "Alice";
var list = new ArrayList<String>();

// Long generic types
var map = new HashMap<String, List<Integer>>();

// With streams
var filtered = names.stream()
    .filter(n -> n.startsWith("A"))
    .toList();

Avoid

// Type not clear
var result = getResult();  // What type?
var x = calculate();       // Unclear

// Numeric literals
var num = 3.14;  // double or float?
var id = 100;    // int or long?

// Diamond with var (fails)
var list = new ArrayList<>();  // Error!

var Best Practices

RuleExample
Use meaningful variable names var customerList = getCustomers(); (type clear from name)
Use when type is on the right side var scanner = new Scanner(System.in);
Avoid with primitive literals Use int count = 0; not var count = 0;
Great for loop variables for (var item : collection) { ... }
Remember: var is about reducing verbosity, not hiding types. If the type isn't obvious, use explicit declaration.

Arithmetic Operators

OperatorDescriptionExampleResult
+Addition5 + 38
-Subtraction5 - 32
*Multiplication5 * 315
/Division5 / 31 (integer!)
%Modulo (remainder)5 % 32
int a = 10, b = 3;
System.out.println(a / b);    // 3 (integer division!)
System.out.println(a % b);    // 1 (remainder)
System.out.println(10.0 / 3); // 3.333... (double division)

Increment and Compound Operators

int i = 10;

// Increment / Decrement
i++;      // i is now 11 (post-increment)
++i;      // i is now 12 (pre-increment)
i--;      // i is now 11

// Compound assignment operators
i += 5;   // Same as: i = i + 5  → i is 16
i -= 3;   // Same as: i = i - 3  → i is 13
i *= 2;   // Same as: i = i * 2  → i is 26
i /= 2;   // Same as: i = i / 2  → i is 13

// Pre vs Post increment
int a = 5;
int b = a++;  // b = 5, a = 6 (use then increment)
int c = ++a;  // c = 7, a = 7 (increment then use)

Comparison Operators

OperatorDescriptionExampleResult
==Equal to5 == 5true
!=Not equal to5 != 3true
>Greater than5 > 3true
<Less than5 < 3false
>=Greater or equal5 >= 5true
<=Less or equal5 <= 3false
For Strings: Use .equals() instead of ==!
String a = "hello";
a.equals("hello")  // true - correct way
a == "hello"       // may be false - compares references!

Logical Operators

OperatorDescriptionExampleResult
&&ANDtrue && falsefalse
||ORtrue || falsetrue
!NOT!truefalse
int age = 25;
boolean hasLicense = true;

// Combining conditions
boolean canDrive = age >= 18 && hasLicense;  // true
boolean isMinorOrNoLicense = age < 18 || !hasLicense; // false

// Short-circuit evaluation
if (name != null && name.length() > 0) {
    // Safe: second part only evaluated if first is true
}

Access Modifiers

Access modifiers control who can see and use your classes, fields, and methods:

Modifier Class Package Subclass World
public
protected
(default)
private
Best practice: Start with private, then widen access only when needed.

Access Modifiers: Example

public class BankAccount {
    public String accountNumber;    // Accessible from anywhere
    protected double balance;       // Package + subclasses
    String bankName;                // Default: package only
    private String pin;             // Only within this class

    public void deposit(double amount) {  // Public method
        if (amount > 0) {
            this.balance += amount;
            logTransaction("Deposit: " + amount);
        }
    }

    private void logTransaction(String msg) {  // Private helper
        System.out.println(msg);
    }
}

Encapsulation: Protecting Your Data

Encapsulation = hiding internal details and providing controlled access.

classDiagram
    class BankAccount {
        -double balance
        -String pin
        +getBalance() double
        +deposit(amount) void
        +withdraw(amount) boolean
    }
            

- = private, + = public

  • Problem: Public fields can be set to invalid values
  • Solution: Make fields private, provide getters/setters

Getters and Setters

public class BankAccount {
    private double balance;  // Private field

    // Getter - read access
    public double getBalance() {
        return this.balance;
    }

    // Setter - controlled write access
    public void setBalance(double balance) {
        if (balance >= 0) {  // Validation!
            this.balance = balance;
        } else {
            throw new IllegalArgumentException("Balance cannot be negative");
        }
    }
}

Complete Encapsulation Example

public class Customer {
    private String name;
    private String email;

    public Customer(String name, String email) {
        setName(name);   // Use setters for validation
        setEmail(email);
    }

    public String getName() { return name; }
    public void setName(String name) {
        if (name != null && !name.isEmpty()) {
            this.name = name;
        }
    }

    public String getEmail() { return email; }
    public void setEmail(String email) {
        if (email != null && email.contains("@")) {
            this.email = email;
        }
    }
}

Type Casting

Converting values from one type to another:

Widening order: byte → short → int → long → float → double

Type Casting Examples

// Widening - automatic, safe
byte b = 10;
int i = b;       // OK
long l = i;      // OK
double d = l;    // OK

// Narrowing - requires cast, may lose data
double price = 19.99;
int roundedPrice = (int) price;  // 19 (decimal lost)

long bigNumber = 10_000_000_000L;
int smaller = (int) bigNumber;   // OVERFLOW! Wrong value

// String conversions
int age = Integer.parseInt("25");
double salary = Double.parseDouble("50000.50");
String ageStr = String.valueOf(age);  // "25"
String concat = "" + age;             // "25" (quick way)

Exercise 1: Create the Bank Classes

Create Java classes based on this class diagram:

classDiagram
    direction LR
    class Customer {
        -String name
        -String address
    }
    class Account {
        -String accountNumber
        -double balance
    }
    class SavingsAccount {
        -double interestRate
    }
    class InvestmentAccount

    Customer "1" -- "0..*" Account
    Account <|-- SavingsAccount
    Account <|-- InvestmentAccount
        

Exercise 1: Tasks

For each class in the diagram, implement:

  1. Private fields as shown in the diagram
  2. Constructor to initialize all fields
  3. Getters and setters for each field with validation
Hints:
  • SavingsAccount and InvestmentAccount extend Account
  • A Customer can have multiple accounts (0 or more)
  • Use ArrayList<Account> in Customer to store accounts

Exercise 2: Add Behavior

Add the following methods to your SavingsAccount class:

  1. deposit(double amount)
    • Add amount to balance (must be positive)
  2. withdraw(double amount)
    • Subtract amount from balance (cannot go below 0)
  3. computeInterest()
    • Return: balance × interestRate
  4. applyInterest()
    • Add computed interest to balance
Remember: Validate inputs in your setters and methods!

Key Takeaways

Next lecture: JVM, compilation process, and control flow (if/switch)

Slide Overview