عرض عملي: ترجمة Hello World وتشغيله وتعطيله وإصلاحه في الطرفية
في هذا الدرس 11 موضوعات
هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.
Lesson Overview
This is a guided demo. You will follow along on your own machine and repeat the whole pipeline from this module, with deliberate mistakes: write and compile Hello World, look inside the .class file, break the program in a way the compiler catches, break it in a way only the running program reveals, and make the file-name mistake that trips up almost every beginner. Then you will fix each one.
The point is not the program, which is tiny. The point is that you meet each error message on purpose, with a calm mind, so that when it appears by surprise later, it is familiar. This demo also prepares the lab, BEG-007-LAB1, which has you record two of these messages and classify them.
Why this matters: professional developers spend a large part of their time reading messages. Learning to separate "found while compiling" from "happened while running" is the first debugging skill.
This lesson builds on L01 to L04 and on the terminal skills from BEG-006.
Learning Objectives
By the end of this lesson you will be able to:
- Carry out the full cycle of write, compile, inspect the
.class, and run from the terminal. - Explain what you see when you open a
.classfile in a text editor. - Produce a compile-time error on purpose, read its message, and fix it.
- Produce a runtime error on purpose, read its message, and fix it.
- Recognise and fix the file-name mismatch error.
- Classify a given message as compile-time or runtime from where and when it appeared.
Written Explanation
Do each step in a fresh folder. The exact message text and layout can differ between JDK versions and operating systems, so the messages below are typical, not guaranteed. What matters is the shape and when it appears.
Setup
mkdir demo-007
cd demo-007Create Hello.java:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello, backend!");
}
}Step 1: write, compile, run
javac Hello.java
java HelloYou expect no output from javac, then Hello, backend! from java. List the folder: you should see Hello.java and Hello.class.
If instead you get "command not found" or similar, return to BEG-005 and check your PATH and your JDK install, using javac -version as the test.
Step 2: look inside the .class file
Open Hello.class in a plain text editor. The way to open it differs by operating system and editor, so use "Open with" from your file manager or open it from inside a text editor, and do not save any changes. You will see mostly unreadable symbols, with a few fragments of text, such as the name of the class or your message, possibly visible between them.
This is expected. A .class file is binary bytecode, a structured format for the JVM, as you saw in L02. A text editor tries to show bytes as characters and fails for most of them. It is not damaged. Close the file without saving.
Optional, if you want to see the raw bytes: a hex viewer tool shows them as numbers. The tool name differs by system (for example xxd or hexdump on many Linux and macOS setups, Format-Hex in PowerShell). The first four bytes of a valid class file are CA FE BA BE, the magic number described in the JVM Specification. Treat this as optional curiosity.
Classify: nothing went wrong in steps 1 and 2. This is the normal pipeline.
Step 3: a compile-time error (remove a semicolon)
In Hello.java, delete the semicolon after the println(...) call and save. Then compile:
javac Hello.javaA typical result:
Hello.java:3: error: ';' expected
System.out.println("Hello, backend!")
^
1 errorRecord three things, exactly as the lab asks:
- The message:
';' expected. - The location: file
Hello.java, line 3. - The stage: compile-time error. It appeared while running
javac, before any program ran.
What about the old Hello.class from step 1? Failed compilation does not produce a new class file for this source, so the old one is still sitting in the folder. If you now ran java Hello, you would see the old output. This is a trap: a failed compile leaves the last successful .class behind. Read the compile output first.
Fix: put the semicolon back, compile again, and confirm the silent success.
Step 4: a runtime error (divide by zero)
Replace the body of main so that the file reads:
public class Hello {
public static void main(String[] args) {
System.out.println("Starting...");
int zero = 0;
int x = 5 / zero;
System.out.println("Result: " + x);
}
}Compile and run:
javac Hello.java
java Hellojavac stays silent. The program has valid syntax, so the compiler accepts it. Then java Hello prints something like:
Starting...
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Hello.main(Hello.java:5)Record:
- The message:
ArithmeticException: / by zero. - The location: line 5 of
Hello.java, insidemain. Notice that this line reference appears underat, which is the JVM telling you where the program was when it stopped. - The stage: runtime error. Compilation had succeeded, and the output
Starting...shows the program ran up to the failing line. The lineResult: ...never printed.
The language specification states that integer division by zero throws an ArithmeticException. It is not an error you can see by reading the grammar: the compiler does not know what zero will contain when the program runs (here you can see it, but in a real program the value could come from a user or a database).
Why did we use a variable and not write 5 / 0? Writing the constant directly is also valid code, and some compilers print a warning for it. Using a variable models the real situation, where the divisor is only known at run time.
Fix: decide what the program should do when the divisor is zero. A simple fix for the demo is to check before dividing:
public class Hello {
public static void main(String[] args) {
System.out.println("Starting...");
int zero = 0;
if (zero == 0) {
System.out.println("Cannot divide by zero.");
} else {
System.out.println("Result: " + (5 / zero));
}
}
}Compile and run again. The program now handles the case and finishes normally. Notice that the fix is about the logic, not about syntax.
Step 5: the planned mistake (file name does not match)
Rename the file so that it does not match the class, for example from Hello.java to hello.java. Use the terminal rename command from BEG-006 (mv in Bash, Rename-Item or mv in PowerShell). Then compile:
javac hello.javaA typical message, which can vary by version:
hello.java:1: error: class Hello is public, should be declared in a file named Hello.java
public class Hello {
^
1 errorRecord: the message says exactly what is wrong, and it is a compile-time error, because it came from javac.
Fix: rename the file back to Hello.java, compile, and run. (On systems whose file names ignore capitalisation the rename may need two steps, so check the folder listing afterwards.)
The mental checklist
When you see a message, ask in this order:
- Which command printed it:
javacorjava? - If
javac: it is a compile-time error. Read the file, the line, the reason. - If
java: did the JVM fail to find the class (a launch problem), or did the program start and then fail (a runtime error)? AnException in thread "main"line followed byat ...lines means the program was running.
Then run it in IntelliJ
For the lab you also run the same program in IntelliJ IDEA (installed in BEG-005). Menus and button names differ between versions, so look for the equivalent in yours: create a project, add a class named Hello, paste the program, and use the green run button or the run option in the class's context menu. The IDE compiles and runs behind the scenes. Typos and errors appear in the editor as you type, and the output appears in a panel at the bottom. The same two error kinds exist there. They are just displayed differently.
Examples
Example 1: classify these three messages (simple)
| Message | Printed by | Kind |
|---|---|---|
error: ';' expected | javac | Compile-time |
ArithmeticException: / by zero | java | Runtime |
error: class Hello is public, should be declared in a file named Hello.java | javac | Compile-time |
Example 2: the stale class trap (practical)
You introduce a typo, javac shows an error, you ignore it and run java Hello. The program runs, but with the old behaviour. You wonder why your edit did nothing. The cause: no new .class file was produced, and the old one still exists.
Habit: compile, read the output, and run only when javac was silent.
Example 3: a misleading success (realistic)
A program reads a number of items from a file and computes the average price. It compiles, it runs, and on today's test file it prints a sensible answer. Tomorrow's file has zero items, and the program stops with the same kind of message as in Step 4. Nothing in the compiler could have predicted this. A teammate who tests an empty file in advance finds it before customers do.
Backend Insight
Backend logs contain both families of message. A build log shows compile-time errors, usually with a file and a line number, and the build fails before anything is deployed. A runtime log shows a stack trace like the one above, with the at lines pointing into your code. In production you will be reading stack traces at unpleasant hours. The skill you practised here is identical: identify the message, find the location, and decide whether the cause is the code's rules, the data, or the logic.
You also saw that a runtime error is often fixed by deciding what should happen in an unusual case. That is a design decision, not just a typo fix. Backend services must define their behaviour for zero, empty, and missing values.
Common Mistakes
Mistake 1: Reading the first error as the only one
A compile run can report several errors, and a first error sometimes causes later ones. Fix the first one and recompile before concluding anything about the rest.
Mistake 2: Running after a failed compile
The old .class file is still there. Always check that javac printed nothing.
Mistake 3: Looking for a runtime error with only the compiler
javac cannot warn you about every runtime failure. You must run the program, ideally with unusual input.
Mistake 4: Classifying by how bad it looks
A long red message is not necessarily "worse" than a short one. Classify by which command printed it and when, not by its length.
Exercises
Try each exercise yourself before opening the solutions. Hands-on items must be done on your machine.
Level A: Foundation
A1. Name the two commands used in this demo and what each produces or does.
أظهر الحل A1
A1. javac Hello.java compiles the source and produces Hello.class. java Hello starts the JVM, which runs the class.
A2. What do you see if you open a .class file in a text editor, and why?
أظهر الحل A2
A2. Mostly unreadable symbols, with a few text fragments, because a .class file contains binary bytecode and the editor tries to show bytes as characters.
A3. Classify: (a) a missing closing brace; (b) a program that crashes with / by zero.
أظهر الحل A3
A3. (a) Compile-time error. (b) Runtime error.
Level B: Application
B1. Reproduce the compile-time error from Step 3. Write down the message, the file, the line number, and the stage.
أظهر الحل B1
B1. Expected: a message such as ';' expected, file Hello.java, the line of the statement (3 in the lesson's layout, possibly the line before the one the caret suggests), stage compile-time, printed by javac.
B2. Reproduce the runtime error from Step 4. Write down the message, the line shown after at, and the stage. Which line of output proves the program started running?
أظهر الحل B2
B2. Expected: java.lang.ArithmeticException: / by zero, with an at Hello.main(Hello.java:5) line in the lesson's layout, stage runtime. The line Starting... proves the program began running before it failed.
B3. Rename Hello.java to Hi.java while the class is still public class Hello. Compile it, record the message, and describe two ways to fix it.
أظهر الحل B3
B3. A message like class Hello is public, should be declared in a file named Hello.java. Fix 1: rename the file back to Hello.java. Fix 2: rename the class to Hi to match the file name.
Level C: Challenge
C1. Write a program, Share.java, that stores a bill of 90 and a number of people in two variables and prints the share. Make it fail with a runtime error when people is 0, record the message, then fix it so that it prints a friendly message instead.
أظهر الحل C1
C1. Example solution:
public class Share {
public static void main(String[] args) {
int bill = 90;
int people = 0;
if (people == 0) {
System.out.println("Nobody to share with.");
} else {
System.out.println("Each pays " + (bill / people));
}
}
}Before adding the if, the line bill / people with people equal to 0 fails with ArithmeticException: / by zero at run time. The fixed version prints the friendly message.
C2. A friend reports: "I fixed the typo but the program still behaves the old way." Give two possible causes related to this module and the command you would run to check each.
أظهر الحل C2
C2. (1) The code was edited but not recompiled, or compilation failed and the old .class remained: run javac again and read its output. (2) The terminal is running a different copy of the class, for example in another folder: check with pwd and ls that you are in the folder with the file you edited.
Mini Challenge
Make a "message field guide" with four rows: the semicolon error, the file-name error, the divide-by-zero error, and one more error of your own that you create on purpose, such as misspelling System. For each row record: the command that printed it, the message text, the line number, and whether it is compile-time or runtime. This is the first half of the lab.
Check your work: each row has the right command, and every error that came from javac is classified compile-time.
Summary & Next Lesson
Key takeaways
- The full cycle is write,
javac, look at.class,java. - A
.classfile is binary bytecode, unreadable in a text editor. - A missing semicolon is a compile-time error:
javacreports it with a file and line, before anything runs. - Dividing by zero (with a value known only at run time) is a runtime error:
javacis silent, andjavastops withArithmeticException. - A file-name mismatch for a public class is a compile-time error.
- A failed compile leaves the last good
.classfile behind. Read the compile output before running.
Next lesson
This is the last lesson in the module. Next is the lab BEG-007-LAB1, "Hello from the terminal", where you repeat these steps, capture both messages, and run the same program in IntelliJ.
Self-check
- Which command prints compile-time errors?
- What proves that a runtime error happened after the program started?
- Why does a failed compile still let you run an old program?
- Why is
5 / zero(with a variable) a better demo than a constant? - What does the file-name error say, and how do you fix it?
أظهر الإجابات
javac.- Output printed before the failure (such as
Starting...) and anException in thread "main"message withatlines. - The old
.classfile is still in the folder, because no new one replaces it. - It models real programs, where the divisor is only known at run time, and avoids a possible compiler warning for a constant zero.
- It says the public class must be declared in a file with the matching name. Rename the file or the class so that they match.
References
- Oracle, The Java Language Specification, Java SE 21, section 15.6 and the
ArithmeticExceptionAPI page. They confirm that integer division by zero throwsArithmeticException. - Oracle, The Java Virtual Machine Specification, Java SE 21, chapter 4. It gives the class file magic number
0xCAFEBABE. - Oracle, The Java Language Specification, Java SE 21, section 7.6. It describes the rule that a public class belongs in a file of the same name.
- Oracle,
javaccommand reference, JDK 21. It describes class-file output. - Not verified: the exact wording of compile and runtime messages shown here, that a failed compile leaves an older
.classuntouched, and IntelliJ menu names. These come from general experience, are marked as typical, and may differ by version.
التطبيق
طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.
تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.