Java Fundamentals Tutorial 0/33 lessons ~6 min read Lesson 5

    Java Syntax

    Java syntax is not arbitrary punctuation — it is a contract between compiler, JVM, and every engineer on your team.

    Course progress0%
    Focus
    21 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Java syntax is not arbitrary punctuation — it is a contract between compiler, JVM, and every engineer on your team. Packages define namespace boundaries. Classes encapsulate state and behavior. Methods express operations with explicit signatures. Variables declare typed storage the JVM allocates on stack or heap.

    Enterprise codebases with 500+ microservices fail not because developers lack syntax knowledge — they fail because inconsistent naming, god classes, and public fields compound into unmaintainable systems that fail code review, SonarQube gates, and staff-level architecture reviews.

    This lesson teaches Java syntax the way Goldman Sachs, Amazon, and Google style guides expect: packages mirror domain boundaries, classes stay small and focused, methods do one thing, and naming communicates intent. Every example includes expected output and line-by-line explanation — because reading production Java means reading structure, not just keywords.

    Business problem

    Syntax chaos scales into organizational debt:

    • Package sprawl: com.company.util.util2.helpers — engineers cannot find code; circular dependencies block builds.
    • God classes: 2,000-line OrderService with 40 public methods — untestable, unreviewable, merge-conflict magnets.
    • Magic numbers and cryptic names: int x = 86400; and process(d, f) — onboarding takes weeks; bugs hide in plain sight.
    • Public mutable state: public static HashMap cache — thread-safety incidents in production; SonarQube blocks merge.

    Why this topic exists

    Java enforces structure at compile time — the language design pushes teams toward readable, maintainable code:

    • Static typing: Every variable and method signature declares types — compiler catches mismatches before deploy.
    • Single public class per file: File name matches class name — predictable navigation in IDEs and code review.
    • Package-private default: No modifier = package visibility — encourages intentional API surface (public) vs internal (package-private).
    • Explicit access modifiers: public, protected, package-private, private — encapsulation is syntactic, not optional.

    Core concepts

    Java syntax building blocks — enterprise reference:

    • Package declaration: package com.acme.payments.domain; — reverse DNS, lowercase, no underscores. First line of every file.
    • Import statements: Explicit dependencies after package. Avoid import com.acme.*; wildcards in production code.
    • Class: Blueprint for objects. One top-level public class per file. Name = PascalCase noun (PaymentOrder).
    • Method: Behavior block. Signature = modifiers + return type + name + parameters. Name = camelCase verb (calculateTotal).
    • Variables: Local (stack), instance (heap, per object), static (heap, per class). Declare closest to first use. Prefer final when value won't change.
    • Blocks: Code enclosed in { }. Class body, method body, if/for/while blocks define scope.

    Internal architecture

    Enterprise package layout — how syntax maps to architecture in a Spring Boot microservice:

    text
    com.acme.payments/ ← root package (company.domain.service)
    ├── PaymentsApplication.java ← @SpringBootApplication entry
    ├── domain/ ← business entities (no framework imports)
    │ ├── PaymentOrder.java ← class: core domain object
    │ ├── Money.java ← value type (record in Java 21)
    │ └── PaymentStatus.java ← enum
    ├── application/ ← use cases / service layer
    │ ├── PaymentService.java ← methods: processPayment(), refund()
    │ └── dto/
    │ └── PaymentRequest.java ← API boundary types
    ├── infrastructure/ ← DB, messaging, external APIs
    │ └── PaymentRepository.java
    └── api/ ← REST controllers
    └── PaymentController.java ← public methods = HTTP endpoints
    Naming rules:
    Package → lowercase, reverse DNS com.acme.payments.domain
    Class → PascalCase noun PaymentOrder, PaymentService
    Method → camelCase verb processPayment, calculateTotal
    Variable → camelCase noun orderTotal, customerId
    Constant → UPPER_SNAKE_CASE MAX_RETRY_COUNT, DEFAULT_CURRENCY
    Enum → PascalCase type, PaymentStatus.PENDING
    UPPER_SNAKE values

    Three structural views — class anatomy, method signature, and naming convention map:

    Class file structure
    package
    Namespace declaration
    imports
    Explicit dependencies
    class
    PascalCase name
    fields
    Instance / static state
    methods
    Behavior blocks
    main()
    Optional entry point
    Top-to-bottom order enforced by Java — package always first.
    Method signature anatomy
    modifiers
    public static final
    return type
    void, int, String
    name
    camelCase verb
    params
    (Type name, ...)
    body
    { statements }
    Signature is the contract — callers depend on it; change breaks API.
    Variable scope & lifetime
    Local var
    Method stack frame
    Instance field
    Per-object heap
    Static field
    Per-class heap
    Parameter
    Method-local copy
    Scope determines visibility; lifetime determines when GC can reclaim.
    Enterprise naming convention map
    PascalCase
    Classes, interfaces, enums, records
    camelCase
    Methods, variables, parameters
    UPPER_SNAKE
    static final constants
    lowercase
    package segments
    Google Java Style Guide + Oracle conventions — industry standard.

    Code walkthrough

    Complete enterprise example — package, class, methods, variables, output display, and line-by-line explanation:

    • Line 1 — package: Must match directory structure. JVM resolves class path from this.
    • Line 11 — private static final: Constant — one copy per class, immutable, encapsulated.
    • Line 15 — private final field: Set once in constructor; cannot be reassigned (thread-safe if object not escaped).
    • Line 19 — constructor: Initializes instance state. No return type — compiler enforces name = class name.
    • Line 24 — method: public API surface. Parameters typed. Returns BigDecimal — never use double for money.
    • Line 46 — main: JVM entry point. Local variables live on stack; objects (calc, subtotal) live on heap.
    java
    // ── File: com/acme/payments/domain/InvoiceCalculator.java ──
    package com.acme.payments.domain; // 1. Package — matches directory path
    import java.math.BigDecimal; // 2. Explicit import (no wildcards)
    import java.math.RoundingMode;
    public class InvoiceCalculator { // 3. Public class — name matches filename
    // 4. Constants — UPPER_SNAKE_CASE, static final
    private static final BigDecimal TAX_RATE = new BigDecimal("0.08");
    private static final int SCALE = 2;
    // 5. Instance field — one copy per object, private encapsulation
    private final String currency;
    // 6. Constructor — same name as class, no return type
    public InvoiceCalculator(String currency) {
    this.currency = currency; // 'this' disambiguates field vs parameter
    }
    // 7. Public method — camelCase verb, explicit return type
    public BigDecimal calculateTotal(BigDecimal subtotal) {
    BigDecimal tax = subtotal.multiply(TAX_RATE)
    .setScale(SCALE, RoundingMode.HALF_UP);
    BigDecimal total = subtotal.add(tax);
    return total;
    }
    // 8. Method overloading — same name, different parameters
    public String formatTotal(BigDecimal total) {
    return currency + " " + total.toPlainString();
    }
    public static void main(String[] args) {
    // 9. Local variables — declared inside method, stack-allocated
    InvoiceCalculator calc = new InvoiceCalculator("USD");
    BigDecimal subtotal = new BigDecimal("100.00");
    BigDecimal total = calc.calculateTotal(subtotal);
    String display = calc.formatTotal(total);
    // 10. Output — System.out.println for demo; SLF4J in production
    System.out.println("Subtotal: " + subtotal);
    System.out.println("Total: " + display);
    }
    }
    /*
    * Expected output:
    * Subtotal: 100.00
    * Total: USD 108.00
    *
    * Explanation:
    * - TAX_RATE 8% applied: 100.00 × 0.08 = 8.00
    * - Total: 100.00 + 8.00 = 108.00
    * - formatTotal prepends currency code
    */

    Production example

    Production service class — how syntax standards appear in a real Spring Boot payment module:

    • @Service — Spring stereotype; class registered as singleton bean.
    • private final repository — immutable dependency; set via constructor injection.
    • SLF4J logger — structured logging with placeholders; never string concatenation in hot paths.
    • var order — local variable type inference (Java 10+); type still checked at compile time.
    java
    package com.acme.payments.application;
    import com.acme.payments.domain.PaymentOrder;
    import com.acme.payments.domain.Money;
    import com.acme.payments.infrastructure.PaymentRepository;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Service;
    @Service
    public class PaymentService {
    private static final Logger log = LoggerFactory.getLogger(PaymentService.class);
    private static final int MAX_RETRY_ATTEMPTS = 3;
    private final PaymentRepository repository;
    public PaymentService(PaymentRepository repository) {
    this.repository = repository;
    }
    public PaymentOrder processPayment(String customerId, Money amount) {
    log.info("Processing payment customerId={} amount={}", customerId, amount);
    var order = PaymentOrder.create(customerId, amount);
    return repository.save(order);
    }
    }
    // Clean code rules applied:
    // ✓ One class, one responsibility (process payments)
    // ✓ Constructor injection (testable, no @Autowired on fields)
    // ✓ Logger — not System.out.println
    // ✓ Constants for magic numbers
    // ✓ Method name = verb describing action
    // ✓ Parameters typed — no raw Object or Map<String,Object>

    Enterprise case study

    Google Java Style Guide at scale: Google's internal Java codebase (Search, Ads, Android backend) enforces style via automated tooling — not optional code review nitpicks. Key rules that prevent enterprise pain:

    • 2-space indent, 100-char line limit — enforced by google-java-format; zero formatting debates in PRs.
    • No wildcard imports — every import explicit; merge conflicts and ambiguity eliminated.
    • @Override mandatory — compiler catches signature drift when interfaces change.
    • Before: 40-minute PR debates on naming and formatting; inconsistent packages across teams.
    • After: Automated format + Checkstyle + Error Prone — reviewers focus on logic, not syntax.

    Performance considerations

    Syntax choices affect JVM performance — subtle but measurable at scale:

    • Prefer primitives in hot loops: int vs Integer — boxing allocates on heap; autoboxing in tight loops creates GC pressure.
    • final local variables: Enable JIT optimizations (effectively final analysis) — no perf cost, helps compiler.
    • String concatenation in loops: result += item creates new String each iteration — use StringBuilder.
    • Static final constants: Compile-time constants inlined by javac — zero runtime field lookup.

    Security considerations

    Syntax and visibility modifiers are security boundaries:

    • private by default: Expose only what callers need — public surface is attack surface.
    • No public mutable fields: public String password — any code can read/write; use private + accessor or record.
    • Package-private for internal APIs: Classes in internal subpackage not exported via JPMS module.
    • Validate at method entry: Check parameters in public methods — fail fast with clear exceptions.

    Scalability considerations

    Syntax conventions enable team scale:

    • Package-by-feature: Teams own com.acme.payments.* — not package-by-layer that crosses team boundaries.
    • Small classes (<300 lines): Reviewable in 15 minutes; testable in isolation; parallel development without conflicts.
    • Consistent naming: New engineers navigate 500-service monorepos by convention — no tribal knowledge required.
    • Module boundaries (Java 9+): module-info.java exports only public API packages — syntax enforces architecture.

    Production challenges

    Syntax-related production incidents — real patterns:

    • Static mutable state: private static Map cache = new HashMap() — shared across requests in Spring singleton; race conditions under load.
    • Wrong equals/hashCode: Missing override on entity classes — HashSet/HashMap silent corruption in dedup logic.
    • Package-private test access: Tests in same package access internals — brittle; prefer package structure that separates test fixtures.
    • Hungarian notation revival: strCustomerName — rejected by modern style guides; type is in the declaration.

    Common mistakes

    • Using import java.util.*; — hides which classes are used; causes naming conflicts (List from which package?).
    • Public fields instead of private + accessors — breaks encapsulation; impossible to add validation later.
    • Single-letter variables outside loop counters — int n = getCount() should be int retryCount.
    • Mismatching class name and filename — PaymentService.java containing class OrderService — compile error.
    • Using double for currency — floating-point rounding errors in financial calculations; use BigDecimal.

    Debugging guide

    When syntax-related errors block builds or runtime:

    • cannot find symbol: Typo in variable/method name, missing import, or wrong package — IDE red underline usually catches; check javac error line number.
    • class X is public, should be declared in a file named X.java: Filename must match public class name exactly.
    • illegal start of expression: Missing semicolon, unmatched brace, or keyword in wrong place — count { } pairs.
    • incompatible types: Assigning String to int — compiler enforces static typing; fix declaration or cast explicitly.
    bash
    # Compile with verbose errors
    javac -Xlint:all com/acme/payments/domain/InvoiceCalculator.java
    # Common lint warnings to treat as errors in CI:
    # - unused imports
    # - raw types (List without generic)
    # - deprecated API usage
    # - missing @Override

    Best practices

    • Follow Google Java Style Guide or Oracle Code Conventions — pick one, enforce with Checkstyle/Spotless in CI.
    • Packages: reverse DNS, lowercase, singular nouns — com.acme.payment.domain not com.acme.Payments.Domains.
    • Classes: one responsibility, PascalCase noun — PaymentValidator not Utils or Helper.
    • Methods: camelCase verb, <20 lines ideally — validatePaymentAmount() not check().
    • Variables: declare closest to use, prefer finalfinal BigDecimal tax = calculateTax(subtotal);
    • Constants: private static final + UPPER_SNAKE — group at top of class.
    • Use var for obvious local types (Java 10+); explicit types for fields and public API.
    • Never System.out.println in production — SLF4J with structured parameters.

    Anti-patterns

    • public class Utils with 30 static methods — god utility class; split by domain responsibility.
    • int temp, tmp, t; — meaningless names; self-documenting code reduces comment need.
    • 500-line methods — extract private methods; each method one level of abstraction.
    • Abbreviations: custAddr, procPmt — spell out customerAddress, processPayment.
    • Empty catch blocks: catch (Exception e) { } — swallow errors; at minimum log and rethrow.

    Staff engineer notes

    • Code review at staff level evaluates structure before logic — package placement, class size, method naming reveal design thinking.
    • Enforce formatting mechanically (Spotless, google-java-format) — human reviewers should never debate brace placement.
    • A method signature is a published API — changing parameter order or types is a breaking change; treat public methods like REST endpoints.
    • When onboarding to a new Java service, read package structure first — it tells you more than any README about architecture intent.
    • Records (Java 16+) replace boilerplate DTOs — prefer record PaymentRequest(String customerId, BigDecimal amount) over 50-line POJO for immutable data carriers.

    Interview questions

    Interview preparation

    15 questions grouped by difficulty — expand any card for a model answer and follow-up probe.

    Beginner

    5
    1. 1What is a package in Java and why use reverse DNS naming?
      Beginner

      Model answer

      • Package groups related classes into a namespace, prevents naming conflicts, and maps to directory structure. Reverse DNS (com.company.project) ensures global uniqueness
      • same convention as Maven groupId.

      Follow-up probe

      Can two classes in different packages have the same name?

    2. 2Explain the difference between class, object, and instance.
      Beginner

      Model answer

      • Class is the blueprint (defined in source code). Object is the runtime entity in heap memory. Instance is one specific object of a class
      • 'an instance of PaymentOrder' means one particular PaymentOrder object.

      Follow-up probe

      Where is the class definition stored vs the instance?

    3. 3What are the Java naming conventions?
      Beginner

      Model answer

      payments).

      Classes/interfaces/enums/records: PascalCase (PaymentService).

      Methods/variables: camelCase (processPayment).

      Constants: UPPER_SNAKE_CASE (MAX_RETRIES).

      Parameters: camelCase (customerId).

      Follow-up probe

      Why not use underscores in class names?

    4. 4What is the difference between local, instance, and static variables?
      Beginner

      Model answer

      Local: declared inside method/block, stack-allocated, method scope.

      Instance: declared in class without static, one per object, heap.

      Static: one per class, shared across all instances, heap in Metaspace-adjacent area.

      Follow-up probe

      Are static variables thread-safe?

    5. 5Why must the public class name match the filename?
      Beginner

      Model answer

      • Java compiler requirement
      • public class must be in a file named ClassName.java. Enables predictable class loading and IDE navigation. Non-public classes can have different filenames but convention avoids this.

      Follow-up probe

      Can a file have two public classes?

    Intermediate

    5
    1. 6Explain method overloading vs overriding.
      Intermediate

      Model answer

      • Overloading: same method name, different parameter list, same class
      • compile-time polymorphism. Overriding: subclass redefines parent method with same signature
      • runtime polymorphism via @Override.

      Follow-up probe

      Can you overload by return type only?

    2. 7What does 'final' mean for variables, methods, and classes?
      Intermediate

      Model answer

      final variable: assign once, cannot reassign.

      final method: cannot be overridden in subclass.

      g.

      String, Integer).

      final parameter: cannot reassign within method.

      Follow-up probe

      Is final about immutability?

    3. 8Why avoid wildcard imports in enterprise code?
      Intermediate

      Model answer

      • Hides actual dependencies
      • reader cannot tell which classes are used. Causes naming conflicts when two packages export same class name. Google/Oracle style guides prohibit; Checkstyle enforces.

      Follow-up probe

      Does wildcard import affect compile time?

    4. 9What is the difference between public, protected, default, and private?
      Intermediate

      Model answer

      • private: same class only. package-private (default): same package. protected: same package + subclasses. public: everywhere. Principle: expose minimum necessary
      • public API surface is maintenance contract.

      Follow-up probe

      Can protected members be accessed from another package?

    5. 10When should you use 'var' vs explicit types?
      Intermediate

      Model answer

      var (Java 10+): local variables where type is obvious from RHS — var list = new ArrayList(). Explicit: fields, method parameters, return types, public API — clarity over brevity. var is not dynamic typing.

      Follow-up probe

      Can var be used for fields?

    Advanced

    5
    1. 11Design package structure for a payment microservice with 15 engineers.
      Advanced

      Model answer

      payments: domain (entities, no framework), application (use cases), infrastructure (repos, clients), api (controllers).

      Each team owns subpackages.

      java exports only api + application.

      Internal packages package-private.

      Follow-up probe

      Package-by-layer vs package-by-feature?

    2. 12How would you enforce Java coding standards across 200 microservices?
      Advanced

      Model answer

      Parent POM with Checkstyle/Spotless/Error Prone plugins.

      google-java-format in pre-commit hook.

      CI fails on violations.

      ArchUnit tests for package dependency rules.

      SonarQube quality gates.

      No merge without green build.

      Document exceptions in ADR.

      Follow-up probe

      What rules would you never automate?

    3. 13Refactor this: public class Utils { public static void doEverything(Order o) { ... 400 lines } }
      Advanced

      Model answer

      format().

      Move to domain-appropriate packages.

      Make methods instance-based for testability.

      Inject dependencies via constructor.

      Each class <100 lines, each method <20 lines.

      Follow-up probe

      When is a utility class acceptable?

    4. 14Explain why BigDecimal is used instead of double for money.
      Advanced

      Model answer

      • double is IEEE 754 floating point
      • 0.1 + 0.2 != 0.3 exactly. Financial systems require exact decimal arithmetic. BigDecimal provides arbitrary precision with explicit scale and rounding mode
      • required for PCI/compliance.

      Follow-up probe

      Performance cost of BigDecimal?

    5. 15What makes Java syntax 'enterprise-ready' vs tutorial code?
      Advanced

      Model answer

      out, single class, magic numbers, no packages.

      Enterprise: encapsulated fields, SLF4J, layered packages, constants, constructor injection, immutability where possible, automated style enforcement, typed APIs.

      Follow-up probe

      How do records change enterprise DTO syntax?

    Hands-on exercise

    Lab: Write enterprise-grade syntax — run the playground, then extend:

    • Run the starter code — observe formatted output from formatReceipt().
    • Add a constant TAX_RATE and refactor tax calculation into a private method calculateTax().
    • Rename any vague variables to self-documenting camelCase names.
    • Add a package comment (as first line): what domain this class belongs to.
    • Bonus: convert the data holder to a Java 21 record if fields are immutable.

    JavaJava Syntax

    Starter Templates
    OutputRemote JVM (Piston · Java 15)
    Press Run to execute. Real javac + JVM via remote API. Falls back to simulator on network failure.

    Architecture trade-offs

    • Explicit types vs var: Explicit wins for public API and fields; var wins for obvious local declarations reducing noise.
    • Package-by-feature vs package-by-layer: Feature wins for team ownership; layer wins for small apps with one team.
    • BigDecimal vs double: BigDecimal wins for money/precision; double wins for scientific computation and performance.
    • POJO vs record: Record wins for immutable DTOs (Java 16+); POJO with builders wins when mutable or inheritance needed.

    Summary

    Java syntax is the grammar of enterprise systems — packages define boundaries, classes encapsulate behavior, methods express intent, and naming conventions let teams scale without confusion. You can now read and write production-grade Java structure with expected output reasoning and line-by-line understanding. Next: data types and the Java type system.

    Key takeaways

    • Package declaration sets namespace — reverse DNS, lowercase, matches directory path.
    • Class = PascalCase noun, one public class per file; Method = camelCase verb with typed signature.
    • Variables: local (stack), instance (heap per object), static (heap per class) — prefer final when possible.
    • Enterprise naming: Google/Oracle conventions enforced by Checkstyle — not optional style preference.
    • Clean code: small classes, short methods, SLF4J not System.out, BigDecimal for money, no public mutable fields.
    Ready to mark this lesson complete?Track your journey across the entire course.