Java Syntax & Structure
Every Java program follows a specific structure. Understanding this foundation is essential before writing any code. Let's explore the anatomy of a Java program.
What is Syntax?
Syntax refers to the rules that define the structure of a programming language. Just as English has grammar rules (subject-verb-object), Java has syntax rules that must be followed exactly. A single misplaced character can prevent your entire program from running.
Key Syntax Rules
- Java is case-sensitive:
Mainandmainare different - Every statement ends with a semicolon
; - Code blocks are wrapped in curly braces
{ } - The filename must match the public class name exactly
- String literals use double quotes
"text"
Common Syntax Errors
- Missing semicolon at end of statement
- Mismatched curly braces
{ } - Using single quotes for strings
'text' - Incorrect capitalization of keywords
- File name not matching class name
Anatomy of a Java Program
Let's examine the structure of a complete Java program. Every Java application must have
at least one class and a main method as the entry point:
// 1. Package declaration (optional - for organizing classes)
package com.example.myapp;
// 2. Import statements (to use external classes)
import java.util.Scanner;
// 3. Class declaration (must match filename: MyProgram.java)
public class MyProgram {
// 4. Main method - entry point of the program
public static void main(String[] args) {
// 5. Statements - your code goes here
System.out.println("Hello, Java!");
}
}
Output:
Hello, Java!
Let's break down each component:
| Component | Purpose | Required? |
|---|---|---|
package |
Organizes classes into namespaces (like folders) | Optional |
import |
Brings external classes into scope | As needed |
class |
Container for all Java code (blueprint for objects) | Required |
main() |
Entry point where program execution begins | Required* |
public static void main(String[] args). Any deviation and Java
will not recognize it as the program entry point.
Understanding the Main Method
The main method is where your program starts executing. Let's understand each keyword:
public static void main(String[] args) {
// Your code here
}
public
Accessible from anywhere. JVM needs to access it from outside the class.
static
Can be called without creating an object. JVM calls it before any objects exist.
void
Returns nothing. The main method does not return a value.
String[] args
Command-line arguments passed to the program as an array of strings.
Using Command-Line Arguments
public class Greeting {
public static void main(String[] args) {
// args contains command-line arguments
if (args.length > 0) {
System.out.println("Hello, " + args[0] + "!");
} else {
System.out.println("Hello, World!");
}
}
}
Running from terminal:
# Compile the program
javac Greeting.java
# Run without arguments
java Greeting
# Output: Hello, World!
# Run with an argument
java Greeting Alice
# Output: Hello, Alice!
Java Naming Conventions
Java has established naming conventions that all developers follow. These make code more readable and maintainable:
| Element | Convention | Example |
|---|---|---|
| Classes | PascalCase (UpperCamelCase) | MyProgram, BankAccount, ArrayList |
| Methods | camelCase (starts lowercase) | calculateTotal(), getUserName() |
| Variables | camelCase (starts lowercase) | firstName, totalAmount, isValid |
| Constants | UPPER_SNAKE_CASE | MAX_SIZE, PI, DEFAULT_VALUE |
| Packages | all lowercase, reversed domain | com.example.myapp, org.apache.commons |
// Naming conventions in action
package com.mycompany.banking;
public class BankAccount { // PascalCase for class
private static final double INTEREST_RATE = 0.05; // UPPER_SNAKE_CASE for constants
private String accountNumber; // camelCase for variables
private double currentBalance;
public void depositMoney(double amount) { // camelCase for methods
currentBalance += amount;
}
public double calculateInterest() {
return currentBalance * INTEREST_RATE;
}
}
Data Types
Java is a statically-typed language, meaning you must declare a variable's type before using it. Java has two categories of data types: primitive types and reference types.
Primitive vs Reference Types
Primitive Types
Store actual values directly in memory. Fixed size.
- 8 types: byte, short, int, long, float, double, char, boolean
- Stored on the stack (fast access)
- Cannot be null
- Start with lowercase
Reference Types
Store memory addresses pointing to objects.
- Examples: String, Arrays, Classes, Interfaces
- Objects stored on the heap
- Can be
null - Start with uppercase
The 8 Primitive Data Types
Java provides 8 primitive data types organized into 4 categories: integers, floating-point, characters, and booleans.
| Type | Size | Range | Default | Example |
|---|---|---|---|---|
| Integer Types | ||||
byte |
1 byte | -128 to 127 | 0 | byte age = 25; |
short |
2 bytes | -32,768 to 32,767 | 0 | short year = 2024; |
int |
4 bytes | -2.1B to 2.1B | 0 | int population = 1400000000; |
long |
8 bytes | -9.2E18 to 9.2E18 | 0L | long distance = 9460730472580800L; |
| Floating-Point Types | ||||
float |
4 bytes | 6-7 decimal digits | 0.0f | float price = 19.99f; |
double |
8 bytes | 15-16 decimal digits | 0.0d | double pi = 3.141592653589793; |
| Character Type | ||||
char |
2 bytes | 0 to 65,535 (Unicode) | '\u0000' | char grade = 'A'; |
| Boolean Type | ||||
boolean |
1 bit* | true or false | false | boolean isActive = true; |
public class DataTypeDemo {
public static void main(String[] args) {
// Integer types
byte smallNumber = 100; // 1 byte: -128 to 127
short mediumNumber = 30000; // 2 bytes
int regularNumber = 2000000000; // 4 bytes (most common)
long bigNumber = 9223372036854775807L; // 8 bytes (note the L suffix)
// Floating-point types
float price = 19.99f; // 4 bytes (note the f suffix)
double precise = 3.141592653589793; // 8 bytes (default for decimals)
// Character type
char letter = 'A'; // Single character in single quotes
char unicode = '\u0041'; // Unicode for 'A'
// Boolean type
boolean isJavaFun = true; // true or false only
boolean isHard = false;
// Print sizes
System.out.println("int max: " + Integer.MAX_VALUE);
System.out.println("long max: " + Long.MAX_VALUE);
}
}
Output:
int max: 2147483647
long max: 9223372036854775807
long literals must end with L, and float
literals must end with f. Without these suffixes, Java treats them
as int and double respectively.
String: A Special Reference Type
String is not a primitive type, but it's used so frequently that Java gives it
special treatment. Strings are immutable (cannot be changed after creation).
public class StringDemo {
public static void main(String[] args) {
// String declaration (reference type, but special syntax)
String greeting = "Hello, World!";
String name = "Alice";
// String concatenation
String message = greeting + " My name is " + name;
System.out.println(message);
// String methods
System.out.println("Length: " + greeting.length()); // 13
System.out.println("Uppercase: " + greeting.toUpperCase()); // HELLO, WORLD!
System.out.println("Contains 'World': " + greeting.contains("World")); // true
System.out.println("First char: " + greeting.charAt(0)); // H
// String comparison (use .equals(), not ==)
String str1 = "Java";
String str2 = "Java";
String str3 = new String("Java");
System.out.println(str1 == str2); // true (same literal in pool)
System.out.println(str1 == str3); // false (different objects)
System.out.println(str1.equals(str3)); // true (same content)
}
}
Output:
Hello, World! My name is Alice
Length: 13
Uppercase: HELLO, WORLD!
Contains 'World': true
First char: H
true
false
true
.equals() to compare String
content, never ==. The == operator compares memory
addresses, not actual text content.
Wrapper Classes
Each primitive type has a corresponding wrapper class that provides additional functionality and allows primitives to be used as objects (e.g., in collections).
| Primitive | Wrapper Class | Useful Methods |
|---|---|---|
int |
Integer |
parseInt(), valueOf(), MAX_VALUE |
double |
Double |
parseDouble(), isNaN(), isInfinite() |
boolean |
Boolean |
parseBoolean(), TRUE, FALSE |
char |
Character |
isDigit(), isLetter(), toUpperCase() |
public class WrapperDemo {
public static void main(String[] args) {
// Autoboxing: primitive to wrapper (automatic)
Integer num = 42; // int to Integer
Double price = 19.99; // double to Double
// Unboxing: wrapper to primitive (automatic)
int value = num; // Integer to int
double amount = price; // Double to double
// Parsing strings to numbers
int parsed = Integer.parseInt("123");
double decimal = Double.parseDouble("3.14");
boolean flag = Boolean.parseBoolean("true");
System.out.println("Parsed int: " + parsed); // 123
System.out.println("Parsed double: " + decimal); // 3.14
System.out.println("Parsed boolean: " + flag); // true
// Useful constants
System.out.println("Int max: " + Integer.MAX_VALUE);
System.out.println("Int min: " + Integer.MIN_VALUE);
}
}
Variables
Variables are containers that store data values. In Java, every variable must have a declared type, and you must declare a variable before using it.
Declaration and Initialization
A variable has three components: a type, a name, and optionally an initial value.
public class VariableDemo {
public static void main(String[] args) {
// Declaration only (variable exists but has no value yet)
int age;
String name;
// Initialization (assigning a value)
age = 25;
name = "Alice";
// Declaration + Initialization (most common)
double salary = 50000.00;
boolean isEmployed = true;
// Multiple declarations of same type
int x = 10, y = 20, z = 30;
// Constants (final keyword = cannot be changed)
final double PI = 3.14159;
final int MAX_USERS = 100;
// PI = 3.14; // ERROR: cannot assign to final variable
System.out.println("Name: " + name + ", Age: " + age);
System.out.println("PI value: " + PI);
}
}
Output:
Name: Alice, Age: 25
PI value: 3.14159
Variable Naming Rules
Valid Names
firstName- camelCase (recommended)_privateVar- starts with underscore$dollarSign- starts with dollar signcount123- letters with numbersMAX_VALUE- uppercase for constants
Invalid Names
123abc- cannot start with numbermy-name- no hyphens allowedmy name- no spaces allowedclass- reserved keywordint- reserved keyword
Variable Scope
Scope determines where a variable can be accessed. Java has different types of variable scope:
public class ScopeDemo {
// Instance variable (belongs to object, accessible in all methods)
private String instanceVar = "I'm an instance variable";
// Static variable (belongs to class, shared by all objects)
private static int staticVar = 0;
public void demonstrateScope() {
// Local variable (only accessible within this method)
int localVar = 10;
System.out.println(instanceVar); // Accessible
System.out.println(staticVar); // Accessible
System.out.println(localVar); // Accessible
// Block scope
if (true) {
int blockVar = 20; // Only accessible within this if block
System.out.println(blockVar); // Accessible here
}
// System.out.println(blockVar); // ERROR: not accessible here
// Loop scope
for (int i = 0; i < 3; i++) {
// i is only accessible within this for loop
System.out.println("Loop: " + i);
}
// System.out.println(i); // ERROR: i not accessible here
}
public static void main(String[] args) {
ScopeDemo demo = new ScopeDemo();
demo.demonstrateScope();
}
}
Instance Variables
Declared in class, outside methods. Each object has its own copy.
Static Variables
Declared with static. Shared by all objects of the class.
Local Variables
Declared inside methods or blocks. Only accessible within that scope.
Type Casting
Type casting is converting a value from one data type to another. Java supports two types of casting: implicit (automatic) and explicit (manual).
Implicit Casting (Widening)
Implicit casting happens automatically when converting from a smaller type to a larger type. No data is lost because the larger type can hold all values of the smaller type.
public class ImplicitCasting {
public static void main(String[] args) {
// Widening: smaller to larger type (automatic)
byte byteVal = 10;
short shortVal = byteVal; // byte to short
int intVal = shortVal; // short to int
long longVal = intVal; // int to long
float floatVal = longVal; // long to float
double doubleVal = floatVal; // float to double
System.out.println("byte: " + byteVal); // 10
System.out.println("short: " + shortVal); // 10
System.out.println("int: " + intVal); // 10
System.out.println("long: " + longVal); // 10
System.out.println("float: " + floatVal); // 10.0
System.out.println("double: " + doubleVal); // 10.0
// int to double (common case)
int quantity = 5;
double price = 19.99;
double total = quantity * price; // quantity is auto-cast to double
System.out.println("Total: " + total); // 99.95
}
}
Widening Order (Automatic)
byte
short
int
long
float
double
Explicit Casting (Narrowing)
Explicit casting is required when converting from a larger type to a
smaller type. You must use the cast operator (type) because data may be
lost during conversion.
public class ExplicitCasting {
public static void main(String[] args) {
// Narrowing: larger to smaller type (manual)
double doubleVal = 9.78;
int intVal = (int) doubleVal; // Explicitly cast to int
System.out.println("double: " + doubleVal); // 9.78
System.out.println("int: " + intVal); // 9 (decimal truncated!)
// Be careful with data loss!
int bigNumber = 1000;
byte smallByte = (byte) bigNumber; // byte can only hold -128 to 127
System.out.println("Original: " + bigNumber); // 1000
System.out.println("As byte: " + smallByte); // -24 (overflow!)
// char to int and vice versa
char letter = 'A';
int ascii = letter; // char to int (automatic)
System.out.println("ASCII of 'A': " + ascii); // 65
int code = 66;
char character = (char) code; // int to char (explicit)
System.out.println("Char of 66: " + character); // B
// Practical example: calculating average
int sum = 17;
int count = 5;
double average = (double) sum / count; // Cast before division!
System.out.println("Average: " + average); // 3.4
// Without casting:
double wrongAvg = sum / count; // Integer division first!
System.out.println("Wrong average: " + wrongAvg); // 3.0
}
}
Output:
double: 9.78
int: 9
Original: 1000
As byte: -24
ASCII of 'A': 65
Char of 66: B
Average: 3.4
Wrong average: 3.0
double to
int, the decimal portion is truncated (not rounded). When casting to
a smaller integer type, overflow can occur.
Converting To and From Strings
public class StringConversion {
public static void main(String[] args) {
// String to primitive types
String numStr = "42";
String doubleStr = "3.14";
String boolStr = "true";
int num = Integer.parseInt(numStr);
double decimal = Double.parseDouble(doubleStr);
boolean flag = Boolean.parseBoolean(boolStr);
System.out.println("Parsed int: " + num); // 42
System.out.println("Parsed double: " + decimal); // 3.14
System.out.println("Parsed boolean: " + flag); // true
// Primitive to String (3 ways)
int value = 123;
// Method 1: String.valueOf()
String str1 = String.valueOf(value);
// Method 2: Concatenation with empty string
String str2 = value + "";
// Method 3: Integer.toString()
String str3 = Integer.toString(value);
System.out.println("All equal: " + str1.equals(str2) + ", " + str2.equals(str3));
// Handling invalid conversions
try {
int invalid = Integer.parseInt("abc"); // Will throw exception
} catch (NumberFormatException e) {
System.out.println("Error: Cannot convert 'abc' to int");
}
}
}
Input & Output
Every program needs to communicate with users. Java provides several ways to display output and read input from the console.
Console Output
Java provides three main methods for console output through System.out:
public class OutputDemo {
public static void main(String[] args) {
// println() - prints and moves to next line
System.out.println("Hello, World!");
System.out.println("This is on a new line.");
// print() - prints without newline
System.out.print("Hello, ");
System.out.print("World!");
System.out.println(); // Now add newline
// printf() - formatted output (like C)
String name = "Alice";
int age = 25;
double salary = 50000.50;
System.out.printf("Name: %s, Age: %d%n", name, age);
System.out.printf("Salary: $%.2f%n", salary);
System.out.printf("Salary: $%,.2f%n", salary); // With thousand separator
// Common format specifiers
System.out.printf("Integer: %d%n", 42);
System.out.printf("Float: %f%n", 3.14159);
System.out.printf("Float (2 decimals): %.2f%n", 3.14159);
System.out.printf("String: %s%n", "Hello");
System.out.printf("Character: %c%n", 'A');
System.out.printf("Boolean: %b%n", true);
System.out.printf("Percentage: %.1f%%%n", 85.5); // %% for literal %
// Padding and alignment
System.out.printf("|%10d|%n", 42); // Right align, width 10
System.out.printf("|%-10d|%n", 42); // Left align, width 10
System.out.printf("|%010d|%n", 42); // Zero-padded, width 10
}
}
Output:
Hello, World!
This is on a new line.
Hello, World!
Name: Alice, Age: 25
Salary: $50000.50
Salary: $50,000.50
Integer: 42
Float: 3.141590
Float (2 decimals): 3.14
String: Hello
Character: A
Boolean: true
Percentage: 85.5%
| 42|
|42 |
|0000000042|
Console Input with Scanner
The Scanner class (from java.util) is the most common way
to read input from the keyboard:
import java.util.Scanner;
public class InputDemo {
public static void main(String[] args) {
// Create Scanner object to read from keyboard
Scanner scanner = new Scanner(System.in);
// Reading different types
System.out.print("Enter your name: ");
String name = scanner.nextLine(); // Reads entire line
System.out.print("Enter your age: ");
int age = scanner.nextInt(); // Reads integer
System.out.print("Enter your GPA: ");
double gpa = scanner.nextDouble(); // Reads double
// Display input
System.out.println("\n--- Your Information ---");
System.out.println("Name: " + name);
System.out.println("Age: " + age);
System.out.printf("GPA: %.2f%n", gpa);
// Close scanner when done (good practice)
scanner.close();
}
}
Sample Run:
Enter your name: Alice Johnson
Enter your age: 21
Enter your GPA: 3.85
--- Your Information ---
Name: Alice Johnson
Age: 21
GPA: 3.85
Scanner Methods Reference
| Method | Returns | Description |
|---|---|---|
nextLine() |
String |
Reads entire line including spaces |
next() |
String |
Reads single word (until whitespace) |
nextInt() |
int |
Reads integer value |
nextDouble() |
double |
Reads double value |
nextBoolean() |
boolean |
Reads true or false |
hasNextInt() |
boolean |
Checks if next token is an integer |
nextInt() or nextDouble() followed by
nextLine(), the newline character remains in the buffer. Add an
extra nextLine() to consume it.
import java.util.Scanner;
public class ScannerPitfall {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter age: ");
int age = scanner.nextInt();
scanner.nextLine(); // Consume leftover newline!
System.out.print("Enter name: ");
String name = scanner.nextLine();
System.out.println("Name: " + name + ", Age: " + age);
scanner.close();
}
}
Input Validation
Input validation is the process of checking user input to ensure it meets expected criteria before processing. This prevents errors, crashes, and security vulnerabilities by rejecting invalid data early. Always validate input for correct type, range, and format.
import java.util.Scanner;
public class InputValidation {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int age = 0;
// Keep asking until valid input
while (true) {
System.out.print("Enter your age (1-120): ");
if (scanner.hasNextInt()) {
age = scanner.nextInt();
if (age >= 1 && age <= 120) {
break; // Valid input, exit loop
} else {
System.out.println("Age must be between 1 and 120.");
}
} else {
System.out.println("Please enter a valid number.");
scanner.next(); // Clear invalid input
}
}
System.out.println("Your age is: " + age);
scanner.close();
}
}
Key Takeaways
Strict Syntax Rules
Java is case-sensitive. Every statement needs a semicolon. Curly braces define code blocks. Filename must match the public class name.
8 Primitive Types
Java has 8 primitives: byte, short, int, long, float, double, char, boolean. Use int and double as defaults.
Type Casting Matters
Widening (small to large) is automatic. Narrowing (large to small) requires explicit cast (type) and may lose data.
Scanner for Input
Use Scanner class for keyboard input. Remember to consume newlines after nextInt(). Always close the scanner.
Output Options
Use println() for simple output, printf() for formatted output with specifiers like %d, %f, %s.
Comment Your Code
Use // for quick notes, /* */ for blocks, and /** */ Javadoc for documentation. Follow consistent naming conventions.
Knowledge Check
Test your understanding of Java basics:
Which data type would you use to store the price of a product like $19.99?
What will be the output of: int result = (int) 9.7;?
Which Scanner method reads an entire line of text including spaces?
Which is a valid Java variable name?
What is the correct way to compare two String values for equality?
What suffix is required when declaring a long literal value?
Comments & Code Organization
Comments document your code, making it easier to understand and maintain. Java supports three types of comments, each with specific use cases.
Types of Comments
// Single-lineQuick notes on one line. Ideal for brief explanations.
/* Multi-line */Block comments for longer explanations or disabling code.
/** Javadoc */Documentation comments. Generates API docs automatically.
Common Javadoc Tags
@param@param name The user's name@return@return The calculated sum@throws@throws IOException If file not found@author@author Sarosh Baig@version@version 1.0@see@see String#length()@deprecated@deprecated Use newMethod() insteadCode Organization Best Practices