In Dart, what is the difference between int.parse and int.tryParse, and which should read a guest count typed into a booking form?
answer
- one throws, one returns null
- FormatException on bad input
- int? result forces a null check
- radix 2 to 36, 0x prefix
- trim and range-check user input
basics
~10 sint.parse throws a FormatException when the text is not a valid integer; int.tryParse returns null instead. For user input such as a guest count, use tryParse, handle null, then range-check the value.
solid answer
~40 s`int.parse(source, {radix})` returns an `int` or throws a `FormatException` if the text is not an optionally signed integer literal; `int.tryParse` has the same rules but returns `int?`, giving `null` where `parse` would throw. The SDK documentation itself says to prefer `tryParse` over throwing and immediately catching. For a form field I would trim the text, call `int.tryParse`, show a validation message on `null`, and then check the range, because `'0'` and `'-3'` parse fine. `parse` is right when bad text is a programming error, such as a value your own code wrote. Related details: the radix runs from 2 to 36, without a radix a `0x` prefix is read as hexadecimal, `'3.5'` is not an integer, and `double.tryParse` or `num.tryParse` cover decimals.
code
dart · 14 linesint? readGuests(String input) {
final guests = int.tryParse(input.trim());
if (guests == null || guests < 1 || guests > 12) return null;
return guests;
}
void main() {
print(readGuests(' 3 ')); // 3
print(readGuests('3.5')); // null
print(readGuests('two')); // null
print(int.parse('0x1F')); // 31
print(149.5.toStringAsFixed(2)); // 149.50
// int.parse('two'); // would throw FormatException
}go deeper
State the difference crisply: parse throws a FormatException, tryParse returns null. Pick tryParse for anything a user typed.
Add the details: int? return type, radix range, 0x prefix, decimals rejected, and that parsing does not replace range checks.
Discuss where each belongs: tryParse at trust boundaries, parse for internal invariants where a bug should surface loudly, and integer cents for money.
Frame input parsing as part of a validation layer with consistent error messages across the app, rather than scattered try/catch around parse calls.
## Two functions, one grammar Dart's `int` class has two static parsers that accept exactly the same text: | Function | Return type | On invalid text | |---|---|---| | `int.parse(source, {int? radix})` | `int` | throws `FormatException` | | `int.tryParse(source, {int? radix})` | `int?` | returns `null` | Valid text is a **non-empty sequence of digits**, optionally preceded by `+` or `-`; when no radix is given, a `0x` hexadecimal literal is accepted too. Anything else, including a decimal point, a thousands separator or a word, is invalid. The SDK documentation for `int.parse` recommends `tryParse` over the pattern of throwing and immediately catching the exception. ## Details worth knowing - **Radix.** `radix` must be between 2 and 36. Digits beyond 9 are the letters `a` to `z`, in either case. `int.parse('1f', radix: 16)` is 31. - **Hex prefix.** With no radix given, the default is 10, but text starting with `0x` is read as a hexadecimal literal, so `int.parse('0x1F')` is also 31. - **No decimals.** `int.parse('3.5')` throws, and `int.tryParse('3.5')` is `null`. Use `double.parse`, or `num.parse`, which returns an `int` when it can and a `double` otherwise. - **Whitespace.** `double.parse` is documented to ignore leading and trailing whitespace. Rather than rely on each parser's handling, trim user input yourself before parsing. - **Null safety does the rest.** Because `tryParse` returns `int?`, the compiler will not let you use the result as an `int` until you have handled `null`. ## Inputs and results at a glance | Input | `int.parse` | `int.tryParse` | |---|---|---| | `'42'` | `42` | `42` | | `'-7'` | `-7` | `-7` | | `'0x1F'` | `31` | `31` | | `'1f'` with `radix: 16` | `31` | `31` | | `'3.5'` | throws `FormatException` | `null` | | `'1,200'` | throws `FormatException` | `null` | | `''` | throws `FormatException` | `null` | The table makes the design plain: both functions agree on what is valid, and differ only in how they report what is not. That is why switching from one to the other never changes which inputs succeed. ## Choosing between them 1. **User input or external text** that may legitimately be wrong: use `tryParse`, and treat `null` as a validation error, not an exception. 2. **Values your own code produced**, such as an id you wrote into a file: `parse` is fine. A failure there is a bug, and an exception with a stack trace is the right signal. 3. **Parsing inside a loop over many records**: `tryParse` avoids the cost and noise of exceptions for each bad row. ## Parsing is not validating A successful parse only means the text was an integer. A booking form still has to reject values that parse but make no sense: - `'0'` and `'-2'` parse, but a booking needs at least one guest. - `'999'` parses, but the room has a maximum occupancy. - `' 3 '` with spaces may come from a paste, so trim before parsing. So the usual shape is trim, `tryParse`, null check, range check, and a clear message for each failure. ## Formatting numbers back The reverse direction is `toString()` for plain output and `toStringAsFixed(n)` for a fixed number of decimal places. `149.5.toStringAsFixed(2)` gives `'149.50'`. It converts to `double` first and returns the closest representation with exactly `n` digits after the point, and `n` must be between 0 and 20. Because doubles are binary, a value such as `1.005` is stored slightly below 1.005 and prints as `'1.00'` with two digits, which is why money is often kept in integer cents. Locale-aware formatting with grouping separators and currency symbols is a separate concern handled by a formatting package, not by `dart:core`. ## Answering in an interview Lead with the one-line difference, throw versus `null`, then say which you use for untrusted input and why. Mention that the result of `tryParse` is nullable and that parsing does not replace range validation. Knowing the `0x` prefix, the radix range and that decimals are rejected shows you have used the API rather than read about it.
- How would you parse a nightly price like '149.50' and display it with two decimals?Use `double.tryParse(text.trim())`, handle `null`, and display with `price.toStringAsFixed(2)`. For totals that must add up exactly, many apps store integer cents instead, because binary doubles cannot represent most decimal fractions exactly, and use a formatting package for currency symbols and grouping.
- When is int.parse the better choice?When invalid text means your program has a bug, for example reading back an id your own code wrote. A thrown `FormatException` with a stack trace surfaces that bug, whereas `tryParse` would quietly turn it into `null` that some later code has to explain.
- What does num.parse return for '42' and for '0.5'?An `int` for `'42'` and a `double` for `'0.5'`: `num.parse` produces an integer when the text is an integer literal and a double otherwise. `num.tryParse` does the same and returns `null` for invalid text.
saying these in an interview costs you the question
- int.tryParse returns 0 when the text is not a number
- int.parse('3.5') rounds and returns 3
- Wrapping int.parse in try/catch is the recommended way to validate input
- A value that parses successfully needs no further validation
- int.parse returns null on invalid input under null safety