انتقل إلى المحتوى
أمين أبوزيد
منشورBEG-011-L03

تحويل النصوص إلى أعداد

  • الدرس 3 من 6
  • 12 دقيقة قراءة
  • مبتدئ
في هذا الدرس 11 موضوعات

هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.

Lesson Overview

Whatever the user types arrives as text. Even when you call nextInt(), Scanner is reading text and converting it for you behind the scenes. In this lesson you do that conversion yourself. You read a line as a String, then turn it into an int or a double.

Why bother, when nextInt() exists? Because converting yourself gives you control. A line read with nextLine() never leaves a leftover (the problem from Lesson 2), it works for numbers that arrive from places other than a keyboard (a file, a web request, a settings value), and it separates two steps that are worth keeping apart: getting the text and understanding the text.

Think of the shop counter again. The customer hands over a slip of paper that says 42. It is a piece of paper with the characters 4 and 2, not yet a quantity you can add to. Parsing is reading the slip and understanding it as the number forty-two.

This lesson builds on Lessons 1 and 2, and on BEG-009 (types and the difference between "42" and 42).

Learning Objectives

By the end of this lesson you will be able to:

  • Explain the difference between the text "42" and the number 42.
  • Convert a String to an int with Integer.parseInt and to a double with Double.parseDouble.
  • Predict what "42" + 1 and Integer.parseInt("42") + 1 produce.
  • Recognise text that cannot be parsed, and recognise the error message that results.
  • Use hasNextInt() and hasNextDouble() to check what is waiting before reading it.
  • Read a whole form as lines and parse the numbers, with no leftover problem.

Written Explanation

Text is not a number

In BEG-009 you learned that "42" (a String) and 42 (an int) are different things. Adding 1 shows it:

java
String text = "42";
System.out.println(text + 1);                    // 421
System.out.println(Integer.parseInt(text) + 1);  // 43

The first line uses + as text joining, so "42" and 1 become "421". The second line first converts the text to the number 42, then adds. The output of the compiled program is:

text
421
43

The two parse methods

MethodConvertsExampleResult
Integer.parseInt(String)text to intInteger.parseInt("42")42
Double.parseDouble(String)text to doubleDouble.parseDouble("3.5")3.5

Both are static methods: you call them on the class name, Integer or Double, without creating an object. (Integer and Double are the classes that go with int and double; BEG-009 mentioned that primitives and classes are different. For now, treat the two names as part of the method name.) Both are in java.lang, so no import is needed.

Here is a short tour, compiled and run:

java
System.out.println(Double.parseDouble("3.5") * 2);       // 7.0
System.out.println(Double.parseDouble("3") * 2);         // 6.0
System.out.println(Integer.parseInt("+7") + Integer.parseInt("-7"));  // 0

Notice that Double.parseDouble("3") is fine: a whole number is a valid decimal. The Javadoc for Integer.parseInt says an optional minus or plus sign is accepted as the first character, so "+7" and "-7" both parse.

What does not parse

Parsing is strict. For Integer.parseInt, the Javadoc says a NumberFormatException is thrown when:

  • the text is empty (or null);
  • any character is not a decimal digit, apart from one leading sign;
  • the value is outside the range of int, from -2,147,483,648 to 2,147,483,647.

That list has some consequences that surprise beginners:

TextparseInt resultWhy
"42"42digits only
"3.5"errorthe dot is not a digit
""errornothing to parse
" 42"errorthe space is not a digit
"2147483648"errortoo large for int

When parsing fails the program stops with an error message. Two real ones, from the compiled test programs:

text
Exception in thread "main" java.lang.NumberFormatException: For input string: "3.5"
Exception in thread "main" java.lang.NumberFormatException: For input string: " 42"

Read the message: it names the exact text that failed. The second one is the sneaky one, because a space is hard to see. This is why the [ ] trick from Lesson 2 pays off.

Double.parseDouble follows the same idea but is more lenient: its Javadoc says surrounding whitespace is ignored, as if trim() had been applied. So Double.parseDouble(" 2.5 ") works and gives 2.5, while the same spaces break parseInt. It also accepts the special words NaN and Infinity, which we will meet again in Lesson 5. It follows Java's decimal-point notation: "2,5" is not a number to parseDouble, regardless of your locale. (This differs from nextDouble(), which uses the locale; see Lesson 1.)

Cleaning the text with trim()

The String method trim() removes spaces, tabs, and similar whitespace from both ends. It returns a new string and leaves the original unchanged (strings are immutable, as BEG-009 explained). So the safe habit is to trim before parsing an integer:

java
int n = Integer.parseInt(line.trim());

Reading a whole form as lines

Now the fix promised in Lesson 2. Read every answer with nextLine(), and parse the numbers:

java
int age = Integer.parseInt(in.nextLine().trim());
String name = in.nextLine();
double height = Double.parseDouble(in.nextLine().trim());

Every read consumes its own line break, so there is no leftover and no trap. The code is longer per number, but it behaves the same for every question. The cost is that a bad number now fails at the parse call instead of the nextInt call; the failure is the same kind, an exception that stops the program.

Checking before you read: hasNextInt()

You have no way yet to catch an exception (that comes in a later module), so you need another way to avoid the crash: look before you leap. Scanner has methods that ask "is the next token of this kind?" without reading it:

MethodTrue when
hasNextInt()the next token can be read as an int
hasNextDouble()the next token can be read as a double
hasNextLine()there is another line to read

The Javadoc says hasNextInt() returns true if the next token can be interpreted as an int, and does not advance past anything. It may wait for the user to type, like any read. To use the answer you need a decision, and you have not met if formally yet: that is the first lesson of the next module, BEG-012. Here is the shape only, so you can read it:

java
if (in.hasNextInt()) {
    // true: it is safe to call nextInt()
} else {
    // false: the next token is not a whole number
}

Read it as English: "if a whole number is waiting, do the first block, otherwise do the second block." We will use this in the examples below, and Lesson 5 puts it inside a loop.

Examples

Example 1: converting and adding (simple)

java
public class Parse {
    public static void main(String[] args) {
        String text = "42";
        System.out.println(text + 1);
        System.out.println(Integer.parseInt(text) + 1);
        System.out.println(Double.parseDouble("3.5") * 2);
        System.out.println(Integer.parseInt("  15 ".trim()));
        System.out.println(Double.parseDouble(" 2.5 ") + 1);
    }
}

Output:

text
421
43
7.0
15
3.5

Each line shows one idea: text joining against addition, the double conversion, trimming, and the whitespace tolerance of parseDouble.

Example 2: a form read as lines (practical)

java
import java.util.Scanner;

public class Lines {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Age: ");
        int age = Integer.parseInt(in.nextLine());
        System.out.print("Full name: ");
        String name = in.nextLine();
        System.out.print("Height in m: ");
        double height = Double.parseDouble(in.nextLine());
        System.out.println(name + ", " + age + ", " + height + " m");
    }
}

With the user typing 30, Ana Smith, and 1.7:

text
Age: 30
Full name: Ana Smith
Height in m: 1.7
Ana Smith, 30, 1.7 m

The age-then-name order that failed in Lesson 2 works here with no extra call. If the age line were thirty the program would stop at the first parseInt.

Example 3: peeking before reading (realistic)

A quantity prompt that explains itself instead of crashing:

java
import java.util.Scanner;

public class Peek {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Quantity: ");
        if (in.hasNextInt()) {
            int qty = in.nextInt();
            System.out.println("You ordered " + qty);
        } else {
            System.out.println("That is not a whole number.");
        }
    }
}

Tested with four different inputs:

User typesOutput
5You ordered 5
abcThat is not a whole number.
3.5That is not a whole number.
99999999999That is not a whole number.

The last row is the important one: a number that is too big for int is also not a valid int, and hasNextInt() says so without crashing. The program is now polite, but it still gives up after one try. Making it ask again is Lesson 5.

Backend Insight

Everything a web backend receives is text: the URL path, the query string, headers, and JSON bodies. A request such as /orders?quantity=3 carries 3 as characters, and the server must parse it into a number before using it. Frameworks do most of this for you later, but they are doing exactly what Integer.parseInt does, including failing on "3.5" and "abc".

Two lessons carry over:

  • Parsing is the border between untrusted text and trusted data. After a successful parse you hold a real int; before it, you hold only characters.
  • A parse failure is normal, not exceptional. In server code you expect some requests to carry bad numbers, and the right response is an error message to the caller, not a crash. The mechanism for that, exceptions, is taught later in the roadmap.

Money deserves a note. Double.parseDouble("0.10") gives the nearest double, which cannot represent most decimal fractions exactly (BEG-009 warned about using double for money). A later module introduces the proper tool; for the receipt in this module, double is fine for practice.

Common Mistakes

Mistake 1: Treating text as a number

  • Incorrect: String qty = in.nextLine(); int total = qty * 2; (does not compile: * cannot be applied to a String)
  • Correct: int total = Integer.parseInt(qty.trim()) * 2;

Mistake 2: Parsing a decimal as an int

Integer.parseInt("3.5") fails. If decimals are possible, use Double.parseDouble. If a whole number is required, the user must be told so.

Mistake 3: Forgetting that spaces break parseInt

" 42" fails because the space is not a digit. Call trim() first. Keep the habit even though parseDouble tolerates spaces.

Mistake 4: Calling a parse method on text you have not checked

The parse works only on text that is a valid number. If it can come from a user, check first (hasNextInt()), or accept that the program stops on bad input.

Mistake 5: Expecting hasNextInt() to consume anything

hasNextInt() only looks. If it is false, the bad token is still waiting, and asking again with hasNextInt() returns false again forever. Lesson 5 shows how to throw the bad token away.

Exercises

Try each exercise yourself before opening the solutions.

Level A: Foundation

A1. What is printed by System.out.println("7" + 2); and by System.out.println(Integer.parseInt("7") + 2);?

أظهر الحل A1

A1. 72 (text joining) and 9 (addition after conversion).

A2. Which of these texts make Integer.parseInt fail: "15", "-4", "1.5", "1 5", ""?

أظهر الحل A2

A2. "1.5" (dot), "1 5" (space inside), and "" (empty) fail. "15" and "-4" parse.

A3. Which method converts text to a decimal: Integer.parseInt or Double.parseDouble?

أظهر الحل A3

A3. Double.parseDouble.

Level B: Application

B1. Write a program that asks for a decimal number, reads it with nextLine(), doubles it with Double.parseDouble, and prints the result.

أظهر الحل B1

B1.

java
Scanner in = new Scanner(System.in);
System.out.print("Number: ");
double d = Double.parseDouble(in.nextLine());
System.out.println(d * 2);

B2. The program reads String s = in.nextLine(); and the user types 12 with a space at each end. Show how to get the integer 12 safely, and say what parseInt does without the fix.

أظهر الحل B2

B2. Use Integer.parseInt(s.trim()), which gives 12. Without trim(), parseInt(" 12 ") throws a NumberFormatException because spaces are not digits.

B3. What does in.hasNextInt() return if the user types 12abc? What does it return for -8?

أظهر الحل B3

B3. 12abc is one token and is not a valid int, so hasNextInt() returns false. -8 returns true: a leading minus sign is accepted.

Level C: Challenge

C1. Write a program that asks for a name (line), a year of birth (read as a line and parsed), and prints Ana will be 30 in 2026 computed from the birth year and a constant for the current year. Use the age-then-name order that failed in Lesson 2 to prove that the lines-only style works.

أظهر الحل C1

C1. One possible solution:

java
final int YEAR = 2026;
System.out.print("Birth year: ");
int born = Integer.parseInt(in.nextLine().trim());
System.out.print("Name: ");
String name = in.nextLine();
System.out.println(name + " will be " + (YEAR - born) + " in " + YEAR);

The number comes first and the name second, with no throw-away call, because every read took a whole line.

C2. A program does int a = in.nextInt(); String s = in.nextLine(); and the user types 5 apples on one line. Then it does int b = Integer.parseInt(s);. What happens and why? Suggest a one-line change that makes the program read apples safely.

أظهر الحل C2

C2. nextInt() reads 5; s becomes apples (with a leading space), the leftover of the line. parseInt(" apples") then throws a NumberFormatException, because the text is not a number. To read apples as text, write String s = in.nextLine().trim();, which also removes the leading space.

Mini Challenge

Write Price doubler. Ask for a product name (line) and a price (line, parsed with Double.parseDouble). Print the name and the price for a "buy two" offer: twice the price. Then run it three times with the inputs 2.50, 2.50, and 2,50, and write down what happens each time.

Check your work: you can explain why the first two give the same result, why the third stops the program, and where in the code the failure occurs.

Summary & Next Lesson

Key takeaways

  • Input is text. "42" is not 42: "42" + 1 is "421", Integer.parseInt("42") + 1 is 43.
  • Integer.parseInt makes an int; Double.parseDouble makes a double.
  • Parsing is strict: "3.5", "", and " 42" fail parseInt. trim() removes the spaces.
  • Reading everything as lines and parsing avoids the Lesson 2 trap.
  • hasNextInt() and hasNextDouble() look at the next token without reading it, so you can avoid a crash.

Next lesson

The next lesson, "Formatting output", turns to the print side: using printf and String.format to control decimals, widths, and alignment.

Self-check

  1. What is "42" + 1? What is Integer.parseInt("42") + 1?
  2. Why does Integer.parseInt("3.5") fail?
  3. What does trim() do, and why use it before parseInt?
  4. What is the advantage of reading numbers with nextLine() and parsing?
  5. Does hasNextInt() read the token it checks?
أظهر الإجابات
  1. "421" and 43.
  2. The dot is not a digit, so the text is not a valid int.
  3. It removes whitespace at both ends. A space makes parseInt fail, so trimming first avoids that.
  4. Each read consumes its own line break, so the Lesson 2 trap cannot happen.
  5. No, it only looks. The token stays in the input.

References

  • Oracle, Java SE 21 API, Integer.parseInt. Supports the accepted forms (optional leading sign, decimal digits) and the conditions for NumberFormatException: empty or null text, non-digit characters, and out-of-range values.
  • Oracle, Java SE 21 API, Double.parseDouble. Supports surrounding whitespace being ignored, acceptance of NaN and Infinity, and NumberFormatException for text that does not match.
  • Oracle, Java SE 21 API, Scanner. Supports hasNextInt() testing the next token without advancing, and out-of-range values not being valid ints.
  • The code and the quoted outputs were compiled and run with JDK 21. The Javadoc pages for Integer, Double, and Scanner were read, and claims here were paraphrased from them; the Backend Insight statements about web requests carrying all values as text are general knowledge, not tied to a page I checked.

التطبيق

طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.

المختبر والتمارين الاختبار

تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.

اكتب للبحث في المستويات والمراحل والوحدات والدروس.