A list that won't take a number
Riya is building a marks tracker for her class. She wants a growing list of marks, she reads each mark from a text box, and some students haven't taken the test yet. Three problems hit her in ten minutes.
Sir, ArrayList<int> won't compile, the text box gives me "85" instead of 85, and I have no way to say “this student has no mark yet”. 0 would be a real mark!
All three have the same answer: wrapper classes. Collections can only hold objects, so Java gives every primitive an object version. int has Integer. Use ArrayList<Integer>.
And the text?
Integer.parseInt("85") reads text and gives you the number. And because an Integer is an object, a variable of that type can hold null, which means “no value”. An int can never be null.
So wrappers are just boxes around numbers?
Boxes with a toolkit: converting, comparing, limits like Integer.MAX_VALUE. And one trap with == that catches many freshers. Let's open the box.
What are wrapper classes?
A wrapper class is a class in java.lang whose objects hold a single value of a primitive type. Java has eight: Byte, Short, Integer, Long, Float, Double, Character and Boolean. They let primitive values be used where objects are required (collections, generics, null), and provide constants and static utility methods for conversion and comparison. Wrapper classes are final and their objects are immutable.
A primitive is a bare value. A wrapper puts that value inside an object, so it can go wherever Java expects an object, and gives you handy tools to work with it.
Words you'll meet in this lesson
byte short int long float double char boolean (Lesson 2.2).Integer.valueOf(85).m.intValue().Integer.parseInt("85").Integer holding 85 holds 85 forever.Integer.valueOf reuses objects for -128 to 127.The eight wrappers
| Primitive | Wrapper class | Size | Example |
|---|---|---|---|
byte | Byte | 8 bits | Byte.MAX_VALUE → 127 |
short | Short | 16 bits | Short.parseShort("300") |
int | Integer | 32 bits | Integer.parseInt("85") |
long | Long | 64 bits | Long.parseLong("9876543210") |
float | Float | 32 bits | Float.parseFloat("2.5") |
double | Double | 64 bits | Double.parseDouble("99.5") |
char | Character | 16 bits | Character.isDigit('7') |
boolean | Boolean | (JVM-dependent) | Boolean.parseBoolean("true") |
| Package | java.lang: available without any import |
|---|---|
| Numeric parent | The six number wrappers extend the abstract class Number (intValue(), doubleValue() …) |
| Mutable? | No. Every wrapper object is immutable, like String |
| Can be null? | Yes, a wrapper variable can hold null; a primitive can't |
| Constructors | new Integer(5) is deprecated and marked for removal; use Integer.valueOf(5) |
Exam tip: only two wrapper names differ from their primitive: int → Integer and char → Character. The rest just capitalise the first letter. And remember: wrapper classes are final (no subclasses) and immutable.
Five jobs a wrapper class does
1. Create an object
Integer.valueOf(85), or just Integer m = 85; (autoboxing, next lesson).
2. Text to number
parseInt gives a primitive; valueOf(String) gives a wrapper object.
3. Limits and constants
Integer.MAX_VALUE, Long.MIN_VALUE, Integer.BYTES.
4. Check characters
Character.isDigit, isLetter, isUpperCase, toUpperCase.
5. Compare and convert
Integer.compare, equals, toBinaryString, toString.
Text to number: parseXxx vs valueOf
public class Main {
public static void main(String[] args) {
String fromForm = "250";
int qty = Integer.parseInt(fromForm); // primitive int
Integer boxed = Integer.valueOf(fromForm); // Integer object
double price = Double.parseDouble("99.5");
boolean agreed = Boolean.parseBoolean("TRUE"); // case-insensitive
System.out.println(qty + 1);
System.out.println(boxed);
System.out.println(price * 2);
System.out.println(agreed);
}
}If the text is not a valid number, parsing throws NumberFormatException, an unchecked exception (Lesson 9.3):
public class Main {
public static void main(String[] args) {
String[] inputs = {"42", "12a", ""};
for (String s : inputs) {
try {
System.out.println("ok: " + Integer.parseInt(s));
} catch (NumberFormatException e) {
System.out.println("bad: " + e.getMessage());
}
}
}
}Limits, characters and handy utilities
public class Main {
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE); // biggest int
System.out.println(Integer.MIN_VALUE);
System.out.println(Byte.MAX_VALUE);
System.out.println(Character.isDigit('7')); // true
System.out.println(Character.isLetter('#')); // false
System.out.println(Character.toUpperCase('r')); // R
System.out.println(Integer.toBinaryString(10)); // 1010
System.out.println(Integer.toHexString(255)); // ff
System.out.println(Integer.compare(5, 9)); // negative: 5 < 9
}
}Comparing wrappers: equals, not ==
public class Main {
public static void main(String[] args) {
Integer a = Integer.valueOf(127), b = Integer.valueOf(127);
Integer c = Integer.valueOf(128), d = Integer.valueOf(128);
System.out.println(a == b); // same cached object
System.out.println(c == d); // two different objects!
System.out.println(c.equals(d)); // compares the values
}
}The Integer cache trap: Integer.valueOf keeps ready-made objects for -128 to 127 and hands out the same one every time. Outside that range it creates a new object. == compares references (is it the same object?), so it says true for 127 and false for 128. Always compare wrapper values with equals(), or unbox to int first.
Which one to pick? Use primitives (int, double) for calculations and loop counters: they're faster and can't be null. Use wrappers when you need an object: in collections and generics, when “no value” (null) is meaningful, or for the static helper methods.
What happens when you call Integer.valueOf
You ask for an Integer
Integer seats = Integer.valueOf(120);valueOfis a static factory method of classInteger. It decides whether to reuse an object or create one.Is the value between -128 and 127?
The JDK has an inner classInteger.IntegerCacheholding an array of 256 ready-madeIntegerobjects, created when the cache class is first initialised. For 120,valueOfreturns the object at that slot. No new object is created.Outside the range: a new object
For 500,Integer fare = Integer.valueOf(500); // new Integer object on the heapvalueOfcreates a fresh object on the heap. Ask again for 500 and you get another fresh object. That's why==is unreliable.The variable holds a reference
seatsis a reference on the stack (like any object variable, Lesson 2.3). The value 120 lives inside the object on the heap, in aprivate final int valuefield.Getting the number back
int n = fare.intValue(); // unboxing: copies 500 out of the objectintValue()reads the privatevaluefield and returns a plainint. The object is unchanged: wrappers are immutable, so “changing” a wrapper variable always means pointing it to a different object.
Cached and new Integer objects: both views
Left: the code and what it prints. Right: the stack and heap, with the JDK's cache of ready-made Integer objects.
priceis a primitiveint: a bare value, no object.Integer.valueOf(120)gives back anIntegerobject holding 120.- The same call again. On screen nothing looks different.
valueOf(500): also an Integer object, holding 500.- Again for 500. Two variables, both holding 500.
a == bis true,c == dis false, yetc.equals(d)is true. The right side shows why.
- A primitive lives right in the stack frame. No heap object is involved.
- The JDK keeps 256 ready-made Integer objects for -128 to 127.
valueOf(120)returns the one for 120;astores a reference to it. valueOf(120)returns the same cached object. Nowaandbpoint to one object.- 500 isn't cached, so
valueOfcreates a new Integer object on the heap. - A second call creates a second object.
canddpoint to different objects that hold the same value. ==checks whether two references point to the same object: true for a/b, false for c/d.equals()compares the stored values: 500 equals 500.
Wrapper classes in real systems
Almost every program that reads input, stores data in collections or talks to a database uses wrapper classes, often without you noticing.
Watch it with an example: a train booking form
A booking page sends everything as text. Watch the server turn the passenger count into a number, and refuse text that isn't one.
- The user types 2 in the form. Browsers send form fields as text, so the server receives the String
"2". - The server calls
Integer.parseInt(text)to read the text as a number. - Parsing succeeds: a primitive
int2. Now arithmetic works: 2 × ₹450 = ₹900. - Another user types two.
parseIntcan't read it and throwsNumberFormatException. - The server catches the exception and shows a clear message instead of crashing. (Simplified: real sites also validate in the browser and check limits such as at most 6 passengers.)
1. Reading form and API input
Web forms, command-line arguments, query strings and JSON fields often arrive as text. Booking sites parse “number of passengers”, shops parse quantities, and every parse is wrapped in a check for bad input.
2. Collections of numbers
List<Integer> of order quantities, Map<String, Double> of product prices, Set<Long> of customer IDs. Collections and generics only work with objects (Module 11).
3. “No value” from databases
A SQL column can be NULL (not entered). Data-access code maps it to an Integer or Double field that can be null. An int field would silently turn it into 0, a real but wrong value.
4. Validating codes and passwords
IFSC codes, PIN codes, vehicle numbers and password rules are checked character by character with Character.isDigit, isLetter and isUpperCase.
5. Configuration values
Settings files store everything as text: timeout=30, debug=true. Applications read them with Integer.parseInt and Boolean.parseBoolean at start-up.
Examples are simplified. Real systems add more checks, such as ranges, trimming spaces and logging rejected input.
A billing counter that reads text input safely
import java.util.ArrayList;
public class Main {
static Integer readQty(String text) {
try {
return Integer.valueOf(text.trim());
} catch (NumberFormatException e) {
return null; // null means "invalid"
}
}
public static void main(String[] args) {
String[] typed = {"2", " 5 ", "two", "1"};
ArrayList<Integer> qtys = new ArrayList<>();
for (String t : typed) {
Integer q = readQty(t);
if (q == null) {
System.out.println("Skipped: '" + t + "'");
} else {
qtys.add(q);
}
}
int total = 0;
for (Integer q : qtys) {
total += q.intValue();
}
System.out.println("Quantities: " + qtys);
System.out.println("Total items: " + total);
}
}Integer.valueOf(text.trim())Removes spaces, then parses the text into an Integer object.return null;Only possible because the return type isInteger, notint. Null signals “bad input”.ArrayList<Integer>A list must hold objects, so we store Integer, not int.q.intValue()Unboxes the object to a plainintfor the arithmetic.
Watch the cache on the heap
This trace is recorded from the real JVM. Watch which valueOf calls create a new object (a new # number on the heap) and which hand back one that already exists.
Worked examples: real problems, solved and traced in memory
Three everyday tasks where wrapper classes do the heavy lifting: reading text, validating characters, and using null for “missing”.
Average marks from a CSV line
Problem statement
A results file stores each student as one line of text: Riya,85,92,78. Write a helper that reads the marks from the line and returns the average.
"Riya,85,92,78"
Riya: 85.0
Approach
- Split the line on commas: the first part is the name, the rest are marks as text.
- A helper
average(String[] parts)parses each mark withInteger.parseIntand adds it up. - Divide by the count as a
doubleand print.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Is this a valid PIN code?
Problem statement
A delivery app accepts Indian PIN codes. A valid PIN has exactly 6 characters, all digits, and must not start with 0. Write isValidPin(String pin).
"410210", "41021A", "012345"
true false false
Approach
- Check the length first.
- Reject a leading
'0'. - Loop over the characters and use
Character.isDigiton each.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Overtime hours with “not entered” days
Problem statement
An attendance system stores overtime hours for each day as Integer. A null means the manager hasn't entered that day yet. Total the entered hours and count the missing days.
{2, null, 3, null, 1}Total overtime: 6 h Days not entered: 2
Approach
- Store the week in an
Integer[]so a day can benull. - Loop: if the value is null, count it as missing; otherwise unbox and add.
- Print the total and the number of missing days.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Check yourself
Quick revision
Lesson 10.1 in one screen
- 8 wrappers in
java.lang: Byte, Short, Integer, Long, Float, Double, Character, Boolean. - Why: collections and generics need objects; wrappers can be
null; they carry utility methods and constants. parseInt("85")→ int;valueOf("85")→ Integer. Bad text →NumberFormatException.- Constants:
Integer.MAX_VALUE= 2147483647,MIN_VALUE= -2147483648. Character.isDigit / isLetter / isUpperCase / toUpperCasefor validation.- Integer cache:
valueOfreuses objects for -128..127. Compare values withequals(), never==. - Wrappers are final and immutable.
new Integer(5)is deprecated; usevalueOf.
Interview and viva questions
Why does Java need wrapper classes if it has primitives?
Primitives are fast but aren't objects. Many APIs need objects: collections, generics, methods that take Object, and anything where “no value” (null) must be represented. Wrappers bridge the two worlds and also provide parsing, conversion and comparison helpers.
What is the difference between parseInt() and valueOf()?
Integer.parseInt(String) returns a primitive int. Integer.valueOf(String) (or valueOf(int)) returns an Integer object, using the cache for -128 to 127. Both throw NumberFormatException for invalid text.
Explain the Integer cache.
Integer.valueOf returns pre-created objects for values from -128 to 127 (the upper limit can be raised with the JVM option -XX:AutoBoxCacheMax). Small numbers are very common, so reusing them saves memory. Side effect: == between two Integers is true for 127 but false for 128. Short, Long, Byte and Character (0 to 127) cache too; Float and Double do not.
Are wrapper classes mutable?
No. Each wrapper object holds its value in a private final field. count = count + 1 on an Integer variable creates (or fetches) a different object and points the variable at it.
Why is new Integer(5) deprecated?
A constructor always creates a new object, so it bypasses the cache and wastes memory. Since Java 9 the constructors are deprecated, and since Java 16 marked for removal. Integer.valueOf(5) (or autoboxing) is the recommended way.
Practice problems
Parse text safely, use the wrapper helpers, and avoid the == trap. The last three are business tasks.
Sum two numbers typed as text
Two text boxes contain "45" and "55". Print their sum as a number, not 4555.
"45", "55"
4555 100
Show solution and explanation
public class Main {
public static void main(String[] args) {
String a = "45", b = "55";
System.out.println(a + b);
int sum = Integer.parseInt(a) + Integer.parseInt(b);
System.out.println(sum);
}
}How it works: a + b joins two Strings. Integer.parseInt turns each into an int first, so + adds them.
Print the limits of int and long
Print the largest and smallest values of int and long using wrapper constants.
(none)
int: -2147483648 to 2147483647 long: -9223372036854775808 to 9223372036854775807
Show solution and explanation
public class Main {
public static void main(String[] args) {
System.out.println("int: " + Integer.MIN_VALUE + " to " + Integer.MAX_VALUE);
System.out.println("long: " + Long.MIN_VALUE + " to " + Long.MAX_VALUE);
}
}How it works: each numeric wrapper has MIN_VALUE and MAX_VALUE constants. Use them instead of typing the numbers.
Count digits in a mobile number
Count how many characters in "+91 98765-43210" are digits.
"+91 98765-43210"
Digits: 12
Show solution and explanation
public class Main {
public static void main(String[] args) {
String phone = "+91 98765-43210";
int digits = 0;
for (char c : phone.toCharArray()) {
if (Character.isDigit(c)) {
digits++;
}
}
System.out.println("Digits: " + digits);
}
}How it works: Character.isDigit returns true for 0–9. The +, space and dash are skipped.
Fix the == comparison
This check prints false even though both scores are 250. Fix it so it prints true, and explain why it failed.
Integer s1 = 250, s2 = 250
with == : false equals : true
Show solution and explanation
public class Main {
public static void main(String[] args) {
Integer s1 = Integer.valueOf(250);
Integer s2 = Integer.valueOf(250);
System.out.println("with == : " + (s1 == s2));
System.out.println("equals : " + s1.equals(s2));
}
}How it works: 250 is outside the Integer cache (-128..127), so two objects exist. == compares references; equals compares the values.
Binary, octal and hex of a number
Print 45 in binary, octal and hexadecimal, then read "2d" back from hex.
45
101101 55 2d 45
Show solution and explanation
public class Main {
public static void main(String[] args) {
int n = 45;
System.out.println(Integer.toBinaryString(n));
System.out.println(Integer.toOctalString(n));
System.out.println(Integer.toHexString(n));
System.out.println(Integer.parseInt("2d", 16));
}
}How it works: the toXxxString methods convert to text in another base; parseInt(text, radix) reads text in that base.
Total cart value from text prices
A shopping cart receives prices as text: "499.00", "1299.50", "bad", "75". Add the valid ones and report how many were rejected.
{"499.00", "1299.50", "bad", "75"}Total: 1873.5 Rejected: 1
Show solution and explanation
public class Main {
public static void main(String[] args) {
String[] prices = {"499.00", "1299.50", "bad", "75"};
double total = 0;
int rejected = 0;
for (String p : prices) {
try {
total += Double.parseDouble(p);
} catch (NumberFormatException e) {
rejected++;
}
}
System.out.println("Total: " + total);
System.out.println("Rejected: " + rejected);
}
}How it works: Double.parseDouble reads decimal text. Bad entries throw NumberFormatException, which we count instead of crashing. (For real money, use paise as long or BigDecimal.)
Strong password check
A password is strong if it has at least 8 characters, at least one upper-case letter, one digit and one symbol (not a letter or digit). Check "Riya@2026" and "riya2026".
"Riya@2026", "riya2026"
Riya@2026 -> true riya2026 -> false
Show solution and explanation
public class Main {
static boolean strong(String pw) {
boolean upper = false, digit = false, symbol = false;
for (char c : pw.toCharArray()) {
if (Character.isUpperCase(c)) upper = true;
else if (Character.isDigit(c)) digit = true;
else if (!Character.isLetter(c)) symbol = true;
}
return pw.length() >= 8 && upper && digit && symbol;
}
public static void main(String[] args) {
System.out.println("Riya@2026 -> " + strong("Riya@2026"));
System.out.println("riya2026 -> " + strong("riya2026"));
}
}How it works: one pass over the characters sets three flags using Character helpers. All four rules must hold.
Read settings from a config file
A config has maxUsers=250, debug=true and timeout=abc. Read each into the right type; use a default of 30 if the timeout is invalid.
{"maxUsers=250", "debug=true", "timeout=abc"}maxUsers=250, debug=true, timeout=30
Show solution and explanation
public class Main {
static int intOr(String text, int fallback) {
try {
return Integer.parseInt(text);
} catch (NumberFormatException e) {
return fallback;
}
}
public static void main(String[] args) {
String[] lines = {"maxUsers=250", "debug=true", "timeout=abc"};
int maxUsers = intOr(lines[0].split("=")[1], 100);
boolean debug = Boolean.parseBoolean(lines[1].split("=")[1]);
int timeout = intOr(lines[2].split("=")[1], 30);
System.out.println("maxUsers=" + maxUsers + ", debug=" + debug + ", timeout=" + timeout);
}
}How it works: each line is split at =. A helper parses with a fallback, so one bad setting doesn't stop the application from starting.
Real-world scenario questions (asked in company interviews)
Wrapper questions in interviews usually hide inside bugs: a comparison that “randomly” fails, a crash on empty input, a zero that should have been “missing”.
Order IDs match in testing, not in production
Code checks if (order.getUserId() == session.getUserId()), both returning Integer. It worked for all test users (IDs 1–50) but fails for real users with IDs in the thousands. Why?
The interviewer is checking: do you know about the Integer cache and reference comparison?
Show a strong answer
==on twoIntegerobjects compares references, not values.- Values -128 to 127 come from the cache, so the same object is returned and
==happens to be true. Larger IDs create separate objects, so it's false. - Fix:
Objects.equals(a, b)(null-safe) ora.equals(b), or compare unboxedintvalues if neither can be null. - Add a test with IDs above 127, and a static-analysis rule that flags
==on boxed types.
Avoid: “Java's == is buggy for big numbers.” It's working exactly as designed.
The transfer screen crashes
Users type amounts like 1,500 or leave the box empty, and the app shows a stack trace. The code is int amt = Integer.parseInt(box.getText());. How do you fix it?
The interviewer is checking: safe parsing and input validation.
Show a strong answer
parseIntthrowsNumberFormatExceptionfor commas, spaces and empty text.- Trim the text, remove allowed separators, then parse inside try/catch and show “Enter a valid amount”.
- For money, use
longpaise orBigDecimal, notdouble, and check limits (greater than 0, below the daily limit).
Avoid: catching Exception and silently using 0. A transfer of ₹0 or a hidden error is worse than a clear message.
Absent students show 0 marks
The report card shows 0 for students who were absent, and their class average drops. The entity has private int marks;. What would you change?
The interviewer is checking: when to use a wrapper type for “no value”.
Show a strong answer
- An
intfield can't represent “missing”, so a database NULL becomes 0. - Change it to
Integer marks; null means absent. Show “AB” in the report and skip nulls when averaging. - Be careful when unboxing:
int m = marks;on null throwsNullPointerException(next lesson). Check for null first.
Avoid: using a magic value like -1 for absent. It leaks into averages and charts the moment someone forgets the rule.
A slow loop over ten million numbers
A report sums 10 million values using Long total = 0L; and total += values[i];. A teammate says changing one word makes it several times faster. Which word?
The interviewer is checking: the cost of wrapper objects in hot loops.
Show a strong answer
- Change
Longtolong. Each+=on aLongunboxes, adds, and boxes a newLongobject, creating millions of short-lived objects for the garbage collector. - Use primitives for counters and sums; use wrappers only where an object is needed.
- Prove it with a profiler or a simple timing before and after.
Avoid: “wrappers are always slow, never use them”. They're the right choice in collections and nullable fields.