Free Programming learning guide
Java Programming for Beginners: A Step-by-Step Guide
Java Programming for Beginners: A Step-by-Step Guide — a free beginner-level guide covering how to learn to code with java. Learn with clear...
What you will learn
1. Getting Started with Java
Why Java? A Language That Runs the World When you withdraw cash from an ATM, swipe your credit card at a grocery store, or load up a game of Minecraft, you are interacting with Java. First released by Sun Microsystems in 1995, Java was designed with a simple but radical goal: Write Once, Run Anywhere. In the early days of computing, if you wrote a program for a Windows machine, it would not work on a Mac. You had to rewrite the software entirely for the new system. Java solved this problem by acting as a middleman. Instead of talking directly to the computer's hardware, a Java program talks to a "virtual" computer. This means the exact same Java code can run on a Windows PC, a Mac, a Linux server, or a tiny microchip in a smart card, without needing to be rewritten. Java is a high-level language. In programming, "high-level" doesn't mean complicated; it means the language is closer to human language than to machine language (the 1s and 0s a computer's processor actually understands). This makes it an excellent language for beginners to learn, because you can focus on learning how to think like a programmer rather than struggling with the arcane mechanics of the computer's hardware. Before we can write our first line of code, we need to understand the tools that make Java work, and then set up our digital workspace. The Java Engine: JDK, JRE, and JVM If you spend any time around Java developers, you will hear three acronyms thrown around constantly: JVM, JRE, and JDK. They sound intimidating, but they are simply three different layers of the Java ecosystem. Think of them like a kitchen. The Java Virtual Machine (JVM) The JVM is the engine that actually runs your Java program. When you write Java code, it is eventually translated into a format called bytecode. The computer's hardware cannot read bytecode directly. The JVM acts as an interpreter, reading the bytecode line-by-line and translating it into the specific machine code that your operating system (Windows, Mac, Linux) understands. In our kitchen analogy, the JVM is the oven. The oven does the actual work of baking the cake, but it only understands one specific format: heat. The Java Runtime Environment (JRE) The JRE is the physical environment where your Java program lives and runs. It includes the JVM, but it also contains a massive library of pre-written code (called core libraries) that your program needs to function. For example, if you want your program to draw a window on the screen or connect to the internet, the JRE contains the tools to do that. If the JVM is the oven, the JRE is …
2. Variables and Data Types
The Memory Box Concept Imagine you are filling out a digital form to book a flight. You type in your name, select your destination, choose the number of passengers, and check a box indicating if you want travel insurance. Behind the scenes, the computer has to temporarily remember all these different pieces of information to calculate your final price. In Java, a variable is a named location in the computer's memory used to store data. Think of a variable as a labeled box. You put something inside the box, slap a label on the outside so you know what’s inside, and later, when you need the contents, you just look for the label. Because computers handle different kinds of data in different ways, Java requires you to specify what type of data will go into the box before you put it there. A box designed to hold a whole number (like the number of passengers) is built differently than a box designed to hold text (like your name) or a true/false value (like travel insurance). Declaring and Initializing Variables To use a variable in Java, you must go through two steps: declaration and assignment. Often, these two steps are combined into a single process called initialization. 1. Declaration: This is when you create the box and put the label on it. You tell Java the data type and the name of the variable. 2. Assignment: This is when you actually put a value into the box using the equals sign (=), which is called the assignment operator. Let’s look at how this works inside the main method of a Java class—the entry point we set up in IntelliJ IDEA previously. Most of the time, programmers do both steps on the same line to save space and keep code readable. This is called initialization: When this line of code runs, Java finds an empty spot in memory, names it passengerCount, restricts it to only hold integers (whole numbers), and places the number 2 inside it. Naming Conventions You can’t just name a variable anything you want. Java has strict rules and widely accepted conventions for naming variables. Hard Rules (If broken, your code won't run): - Names can only contain letters, numbers, underscores (), and dollar signs ($). - Names cannot start with a number. - Names cannot be Java keywords (like int, class, public, etc.). - Names are case-sensitive (passengerCount and PassengerCount are entirely different variables). Conventions (Best practices used by professionals): - Use camelCase: Start the first word lowercase and capitalize the first letter of every subsequent word (e.g., firstName, totalPriceAfterTax). - Make names descriptive. A variable named p tells you nothing, but passengerCount makes your code self-explanatory. - …
3. Control Flow and Logic
The Crossroads of a Program Imagine you are driving to a coffee shop. As you approach an intersection, the traffic light turns red. You stop. When it turns green, you proceed. If you reach the shop and it’s closed, you drive home; if it’s open, you go inside and order. Every decision you make alters your path. In our first two chapters, we wrote Java programs that executed strictly from top to bottom. Every statement we wrote ran exactly once, in the exact order we wrote it. But real-world applications rarely work this way. A banking app needs to check if a password is correct before allowing a login. A video game needs to run a battle sequence repeatedly until a monster is defeated. To make these scenarios work, we need a way to control the execution path of our program. This is called control flow. It is the mechanism that allows our code to make decisions, skip statements, or repeat actions based on specific conditions. Making Decisions with if, else if, and else The most fundamental building block of control flow is the conditional statement. A conditional statement tells Java to execute a specific block of code only if a certain condition is true. In Java, we build conditional statements using the keywords if, else if, and else. The basic if statement An if statement evaluates a boolean expression—a statement that ultimately resolves to either true or false. If the expression is true, the code inside the curly braces {} runs. If it is false, Java skips that block entirely. Because 75 is greater than 70, the expression temperature 70 evaluates to true, and the message prints to the console. Adding an else If we want something to happen when the condition is false, we add an else block. Java guarantees that either the if block or the else block will execute, but never both. Here, 45 is not greater than 70. The if condition fails, so Java skips the first block and runs the else block instead. Branching with else if Often, there are more than two possible outcomes. To evaluate multiple conditions in a sequence, we use else if. Java will evaluate these conditions from top to bottom. As soon as it finds one that is true, it executes that block and skips the rest. In this scenario, 65 is not greater than 80, so the first block is skipped. It is greater than 60, so the second block runs. Java prints "It's mild. A light jacket is perfect." and then exits the entire conditional structure, ignoring the remaining else if and else statements. Evaluating Multiple Conditions Sometimes a decision depends on more than one factor. For …
4. Methods and Code Reusability
The Problem with Copy and Paste Imagine you are writing a program for a coffee shop. Every time a customer places an order, your program needs to calculate the total price, apply a local sales tax, print a receipt, and update the daily revenue log. You could write the exact same ten lines of code every single time a customer orders a latte. But what happens when the local sales tax changes? You would have to hunt down every single place you copied those ten lines and manually update the math. If you miss just one, your books will be wrong. In the early chapters of this book, we wrote all of our instructions inside the main method. As a reminder, main is the entry point—the specific location where the Java Virtual Machine (JVM) begins executing your code. For small learning exercises, keeping everything in main works perfectly fine. But as your programs grow in complexity, main becomes crowded, difficult to read, and prone to errors. The solution to the coffee shop problem—and to crowded main methods—is code reusability. Instead of writing the same logic multiple times, you write it once, give it a name, and simply tell Java to run that named block of code whenever you need it. In Java, these reusable, named blocks of code are called methods. Defining and Calling Static Methods A method is a collection of statements grouped together to perform a specific task. You have already been using one method this whole time: main. Now, we are going to learn how to create our own. When you create a new method, you are defining it. When you tell Java to execute that method, you are calling (or invoking) it. To define a method, you must follow a specific structure. Here is the blueprint: Let’s break down the first few parts of this blueprint: - modifier: For now, we will always use the word public. This tells Java that the method is accessible from other parts of your program. - static: This keyword means the method belongs to the class itself, rather than to a specific instance of an object. Since we are not covering Object-Oriented Programming (OOP) just yet, all of our custom methods will be static so they can be run directly from our main method. - returnType: This defines what kind of data the method will hand back to the code that called it. If a method performs a task but doesn't give any data back, we use the word void. A Simple Example Let’s create a simple method that prints a greeting to the console. When you run this code in your IDE (like IntelliJ IDEA Community Edition), the JVM …
5. Introduction to Object-Oriented Programming
From Blueprints to Objects Imagine you are managing a small library. To keep track of your inventory, you write down the title, author, and page count of every single book on index cards. You quickly realize you are writing the same categories over and over. Instead of starting from a blank card every time, you create a master template—a stencil that already has "Title:", "Author:", and "Pages:" printed on it. You just fill in the specific details for each book. In Chapter 1, we mentioned that Java is an Object-Oriented Programming (OOP) language. That master template is the core of OOP. In this chapter, we will move beyond simple variables and standalone methods, and start modeling real-world concepts using custom classes and objects. Classes and Objects: The Core Blueprint In Java, a class is a blueprint. It defines what properties and behaviors a specific concept should have. An object is an actual, concrete instance created from that blueprint. Think of a class as the architectural blueprint for a house. The blueprint itself isn't a house; you can't live in it. It just describes what the house will look like. The actual house built from that blueprint is the object. You can build many houses (objects) from the exact same blueprint (class). They all have the same structure, but one house might have blue walls while another has white walls. Let’s look at how this translates into Java code. Here is a simple class representing a Book: Modeling State with Instance Variables In Chapter 2, we learned about variables like int and String to hold data. When we define variables inside a class—but outside of any method—they become instance variables. Instance variables represent the state or properties of an object. If our class is a blueprint for a Book, the instance variables are the blank spaces on our index card waiting to be filled in. Every time we create a new Book object from this class, that specific object will get its own copy of these variables. One book might have the title "1984" and 328 pages, while another has "The Hobbit" and 310 pages. Because these variables belong to a specific instance of the class, we call them instance variables. Modeling Behavior with Instance Methods In Chapter 4, we learned how to write reusable methods. Now, we will place methods inside our classes. When a method belongs to a class, it is called an instance method, and it represents the behavior of the objects created from that class. If a Book object could talk, what might it do? Perhaps it could tell us if it is a long read. Let's add a method to our Book class. Notice something important …
6. Inheritance and Polymorphism
Designing a Vehicle Management System Imagine you are building a Java application for a vehicle rental company. You need to keep track of cars, motorcycles, and trucks. All of these vehicles share certain characteristics—they have a brand, a model, and a mileage. They also share behaviors, like starting their engines or driving. If you were to create three completely separate classes for Car, Motorcycle, and Truck, you would end up writing the exact same code for those shared attributes and behaviors in all three classes. In the earlier chapters on Methods and Code Reusability and Introduction to Object-Oriented Programming, we explored how classes act as blueprints. But what if a blueprint could share its foundational designs with other, more specialized blueprints? This is where two of the most powerful concepts in Object-Oriented Programming (OOP) come in: inheritance and polymorphism. Inheritance allows you to create new classes that absorb the attributes and methods of an existing class. Polymorphism allows those new classes to behave in their own unique ways while still being treated as their general parent type. Together, they allow you to build flexible, organized, and highly reusable code. Inheritance: Building on Existing Foundations Inheritance is a mechanism in Java where a new class (the child class) derives properties and behaviors from an existing class (the parent class or superclass). Think of a family tree. A child inherits certain physical traits from their parents. However, the child is still a unique individual with their own specific traits. In Java, a child class inherits the fields and methods from its parent, meaning you don't have to write that code again. The child class can then add its own unique fields and methods, or even change how the inherited methods work. Let's look at this with our vehicle example. We will create a parent class named Vehicle. The Vehicle class holds the fundamental data and actions that apply to every type of vehicle in our system. The 'extends' Keyword To create a child class that inherits from Vehicle, we use the extends keyword. Let's create a Car class. A car is a vehicle, but it also has a specific attribute that a basic vehicle might not have: the number of doors. By using extends, the Car class automatically inherits the brand, model, and mileage attributes, as well as the startEngine() and drive() methods from Vehicle. We didn't have to write that code in the Car class. Here is how you would use this in your main program: When you run Run 'Main.main()' in your IntelliJ IDEA Community Edition project, the output will show that the Car object successfully uses the methods and fields defined in the Vehicle parent class. The 'super' Keyword …
7. Arrays and Collections
Managing Multiple Values Imagine you are building a simple application to track the high scores of players in a game. If your game only has three players, you could easily create three separate variables: int score1 = 100;, int score2 = 250;, and int score3 = 75;. But what happens if your game suddenly becomes popular and you need to track the scores of 1,000 players? Or a million? Creating a million individual variables is impossible to manage. When we need to store and manage groups of related data, Java provides structures designed specifically to hold multiple values under a single name. In this chapter, we will look at how to use fixed-size arrays for data that won't change in size, and dynamic collections (like ArrayList and HashMap) for data that needs to grow, shrink, or map together as your program runs. Fixed-Size Arrays An array is a container object that holds a fixed number of values of a single type. When you create an array in Java, you must declare exactly how many items it will hold. Once the array is created, its size is permanently locked in. Think of an array like a pill organizer or an egg carton: it has a specific number of compartments, and you can put one item in each compartment. Declaring and Populating Arrays To declare an array, you specify the data type of the elements it will hold, followed by square brackets [], and then the array's name. You then use the new keyword to allocate the memory for a specific number of slots. When you create an array of primitives (like int or double) this way, Java automatically fills every slot with a default value. For integers, that default value is 0. To put your own data into the array, you use indexing. Every slot in an array has an index, which is its position number. In Java, array indexing always starts at 0. The first item is at index 0, the second is at index 1, and so on. The last item is always at the array's length minus one. If you already know exactly what values you want to put in the array at the time you create it, Java provides a shorthand syntax called an array literal. This automatically sizes the array to fit the exact number of items you provide. Iterating Through Arrays Because we learned about Control Flow and Logic in Chapter 3, we know that loops are perfect for repeating tasks. The most common task with an array is iteration—visiting every element inside it. Every array in Java has a built-in property called length that tells you exactly how many items it holds. We can …
8. Exception Handling
When Good Code Meets Bad Data Imagine you have written a Java program to manage a library catalog. The program asks the user to type in the ID number of the book they want to borrow. The program expects an integer, like 1042. But the user is typing on a smartphone, autocorrect interferes, and they accidentally submit the string "one thousand". If your program blindly attempts to read that text as a number, Java will panic. It will crash immediately, spitting a wall of red text at the user and closing the application. The user loses their place, their data might be corrupted, and they are likely frustrated. In previous chapters, we built programs assuming the user and the system would always behave perfectly. We assumed arrays would always have valid indices and methods would always receive the correct data types. In the real world, however, things break. Networks disconnect, files disappear, and users make unpredictable mistakes. Exception handling is Java’s mechanism for anticipating these runtime errors and managing them gracefully. Instead of letting the program crash, exception handling allows you to catch the error, display a friendly message to the user, and keep the program running. What is an Exception? In Java, an exception is an event that disrupts the normal flow of a program's instructions during execution. When an error occurs, Java creates an object representing that error. In the chapter Introduction to Object-Oriented Programming, we learned that objects are instances of classes. Exceptions are no different—they are objects created from the Exception class, or one of its many subclasses. When Java creates this exception object and hands it over to the runtime system, it is called throwing an exception. If you do not write any code to handle the exception, the JVM (Java Virtual Machine) will catch it, print a stack trace (that wall of red text detailing exactly where the error happened), and terminate the program. Let’s look at a classic example of an exception using concepts from Arrays and Collections: If you click Run 'Main.main()' in your IDE, this code will compile perfectly. The compiler doesn't check if 5 is a valid index. But during execution, Java realizes there is no sixth element in this array. It throws an ArrayIndexOutOfBoundsException. The program crashes immediately, and the line System.out.println(numbers[5]); is never executed. The Difference Between Errors and Exceptions Java uses the term "Error" for severe problems that a reasonable application should not try to catch. For example, if your computer runs out of memory (an OutOfMemoryError), the JVM is failing. You cannot write code to gracefully handle a system failure of that magnitude. Exceptions, on the other hand, are conditions within your application's logic that you …
9. File Input and Output
Why Store Data Outside Your Program? Imagine you are building a simple expense tracker. Every time the user runs the program, they enter their daily purchases. You store these purchases in an ArrayList (from Arrays and Collections), and the program calculates the total. But there is a fatal flaw: when the user closes the application, the JVM shuts down, and all the data stored in your computer's short-term memory (RAM) vanishes. The next time the program runs, the user has to start from scratch. To make data permanent, we must save it to the computer's hard drive. This process is known as File Input and Output (often abbreviated as I/O). Input means reading data from an external file into your program. Output means writing data from your program out to an external file. In this chapter, we will explore how Java interacts with text files. We will build directly on the concepts of Variables and Data Types, Control Flow and Logic, and Exception Handling, as file manipulation relies heavily on all three. Navigating the File System: Paths Before you can read or write a file, your Java program needs to know exactly where that file lives on your computer. The location of a file is called its path. There are two ways to specify a path: absolute and relative. Absolute Paths An absolute path is the complete, exact location of a file, starting from the root of your computer's file system. On Windows: C:\Users\JohnDoe\Documents\expenses.txt On macOS: /Users/JohnDoe/Documents/expenses.txt Absolute paths are precise, but they are rarely used in professional Java development because they tie your program to a specific computer. If you hardcode C:\Users\JohnDoe\... into your program, it will crash the moment you send it to a colleague using a Mac, or even another Windows user with a different name. Relative Paths A relative path specifies a file's location relative to the current working directory of your program. When you run a Java program, the JVM designates a "starting point" folder. If you are using an Integrated Development Environment (IDE) like IntelliJ IDEA Community Edition, the current working directory is almost always the root folder of your New Project. If you create a text file named expenses.txt directly inside your project folder (alongside the src folder), you can refer to it in your code simply by its name: "expenses.txt" If you create a folder named data inside your project folder and put the file inside it, the relative path becomes: "data/expenses.txt" (or "data\\expenses.txt" on Windows, though Java understands forward slashes on both operating systems). Using relative paths makes your code portable, staying true to the Java philosophy of Write Once, Run Anywhere. Reading Data from a File Java provides several classes …
10. Debugging and Testing Basics
The Art of Finding What Went Wrong You have written the code. It compiles without errors. You hit the run button, expecting your program to gracefully read a file, process the data, and print the results. Instead, the console flashes red text, the program crashes, and you are left staring at a wall of text that looks like a foreign language. Every programmer, from absolute beginners to seasoned veterans, spends a significant portion of their time finding and fixing mistakes. In software development, a mistake in the code is called a bug. The term allegedly originates from the 1940s when a literal moth got trapped in a relay of an early computer, causing a malfunction. Today, bugs are rarely physical insects; they are logical errors, typos, or misunderstandings in our code. The process of finding, analyzing, and eliminating these bugs is called debugging. For a beginner, debugging can feel frustrating. However, with the right tools and techniques, it becomes a satisfying process of deduction. Modern development environments provide specialized tools that allow you to pause a running program in mid-air, look at exactly what is happening, and figure out exactly where your logic went wrong. Before you can fix a bug, you must locate it. When a Java program crashes, it leaves behind a trail of breadcrumbs. Reading and Interpreting Java Stack Traces When a Java program encounters an error it cannot recover from (like trying to access an array index that doesn't exist, as covered in Arrays and Collections), it throws an exception. If this exception is not caught using a try-catch block (as discussed in Exception Handling), the program will crash and print a stack trace to the console. A stack trace is a report generated by the Java Virtual Machine (JVM) that shows exactly what was happening when the error occurred. It lists the sequence of method calls that led to the error. Anatomy of a Stack Trace To a beginner, a stack trace looks intimidating. Let’s break one down. Imagine you have a program that processes user ages, and it crashes with the following output: Here is how to read it, piece by piece: 1. The Exception Type: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException. This first line tells you what went wrong. In this case, the main thread of your program tried to access an index of an array that did not exist. 2. The Error Message: Index 5 out of bounds for length 5. This is the JVM giving you extra context. It is telling you that your array has a length of 5 (valid indexes 0 through 4), but your code asked for index 5. 3. The Stack (The Breadcrumbs): The lines starting with at …
Continue learning
- Intermediate Python Automation Scripts for BeginnersIntermediate Python Automation Scripts for Beginners — a free intermediate-level guide covering intermediate python automation scripts for beginners....
- Intermediate Python Projects for Portfolio BuildingIntermediate Python Projects for Portfolio Building — a free intermediate-level guide covering intermediate python projects for portfolio building....
- C# for Beginners: A Complete Step-by-Step GuideC# for Beginners: A Complete Step-by-Step Guide — a free beginner-level guide covering how to learn c# for beginners. Learn with clear explanations,...
- C++ for Beginners: A Comprehensive Step-by-Step GuideC++ for Beginners: A Comprehensive Step-by-Step Guide — a free beginner-level guide covering how to learn c++ for beginners. Learn with clear...