Scanner
Scanner is the complement of Formatter. It reads formatted input and converts it into its binary form. Scanner can be used to read input from the console, a file, a
string, or any source that implements the Readable
interface or ReadableByteChannel.
For example, you can use Scanner to
read a number from the keyboard and assign its value to a variable. As you will
see, given its power, Scanner is
surprisingly easy to use.
The Scanner Constructors
Scanner defines the constructors shown in Table 19-15.
In general, a Scanner can be created for a String, an InputStream,
a File, or any object that
implements the Readable or ReadableByteChannel interfaces. Here
are some examples.
The
following sequence creates a Scanner
that reads the file Test.txt:
FileReader fin = new
FileReader("Test.txt");
Scanner src = new Scanner(fin);
This
works because FileReader implements
the Readable interface. Thus, the
call to the constructor resolves to Scanner(Readable).
This
next line creates a Scanner that
reads from standard input, which is the keyboard by default:
Scanner conin = new
Scanner(System.in);
This
works because System.in is an object
of type InputStream. Thus, the call
to the constructor maps to Scanner(InputStream).
The next
sequence creates a Scanner that
reads from a string.
String instr = "10 99.88
scanning is easy.";
Scanner conin = new
Scanner(instr);
Scanning Basics
Once you
have created a Scanner, it is a
simple matter to use it to read formatted input. In general, a Scanner reads tokens from the underlying source that you specified when the Scanner was created. As it relates to Scanner, a token is a portion of input
that is delineated
by a set
of delimiters, which is whitespace by default. A token is read by matching it
with a particular regular expression,
which defines the format of the data. Although Scanner allows you to define the specific type of expression that
its next input operation will match, it includes many predefined patterns,
which match the primitive types, such as int
and double, and strings. Thus, often
you won’t need to specify a pattern to match.
In
general, to use Scanner, follow this
procedure:
Determine if a specific type of input is available by calling one
of Scanner’s hasNextX methods, where X is the type of data desired.
If input is available, read it by calling one of Scanner’s nextX methods.
Repeat the process until input is exhausted.
Close the Scanner by
calling close( ).
As the
preceding indicates, Scanner defines
two sets of methods that enable you to read input. The first are the hasNextX methods, which are shown in Table 19-16. These methods determine
if the specified type of input is available. For example, calling hasNextInt( ) returns true only if the next token to be read
is an integer. If the desired data is available, then you read it by calling
one of Scanner’s nextX
methods, which are shown in Table 19-17.
Method Description
boolean
hasNext( ) Returns true if another
token of any type is available to be read. Returns false otherwise.
boolean
hasNext(Pattern pattern) Returns true
if a token that matches the pattern passed in pattern is available to be read.
Returns false otherwise.
boolean
hasNext(String pattern) Returns true
if a token that matches the pattern passed in pattern is available to be read.
Returns false otherwise.
boolean
hasNextBigDecimal( ) Returns true
if a value that can be stored in a BigDecimal object is available to be read.
Returns false otherwise.
boolean
hasNextBigInteger( ) Returns true if a
value that can be stored in a BigInteger object is available to be read.
Returns false otherwise. The default radix is used. (Unless changed, the
default radix is 10.)
boolean
hasNextBigInteger(int radix) Returns
true if a value in the specified radix that can be stored in a BigInteger
object is available to be read. Returns false otherwise.
boolean
hasNextBoolean( ) Returns true if a
boolean value is available to be read. Returns false otherwise.
boolean
hasNextByte( ) Returns true if a
byte value is available to be read. Returns false otherwise. The default radix is
used. (Unless changed, the default radix is 10.)
boolean
hasNextByte(int radix) Returns true
if a byte value in the specified radix is available to be read. Returns false
otherwise.
boolean
hasNextDouble( ) Returns true if a
double value is available to be read. Returns false otherwise.
boolean
hasNextFloat( ) Returns true if a
float value is available to be read. Returns false otherwise.
boolean
hasNextInt( ) Returns true if an int
value is available to be read. Returns false otherwise. The default radix is
used. (Unless changed, the default radix is 10.)
boolean
hasNextInt(int radix) Returns
true if an int value in the specified radix is available to be read. Returns
false otherwise.
boolean
hasNextLine( ) Returns true if a line of
input is available. boolean hasNextLong( ) Returns
true if a long value is available to be read. Returns false otherwise. The
default radix is used. (Unless changed, the default radix is 10.)
boolean
hasNextLong(int radix) Returns true
if a long value in the specified radix is available to be read. Returns false
otherwise.
boolean
hasNextShort( ) Returns true if a
short value is available to be read.
Returns false otherwise. The
default radix is used.
(Unless changed, the default
radix is 10.)
boolean hasNextShort(int
radix) Returns true if a short value
in the specified radix is available to be read. Returns false otherwise.
String
next( ) Returns the next token of
any type from the input source.
String
next(Pattern pattern) Returns the next
token that matches the pattern passed in pattern from the input source.
String
next(String pattern) Returns the next
token that matches the pattern passed in pattern from the input source.
BigDecimal
nextBigDecimal( ) Returns the next
token as a BigDecimal object.
BigInteger
nextBigInteger( ) Returns the next token
as a BigInteger object. The default radix is used. (Unless changed, the default
radix is 10.)
BigInteger
nextBigInteger(int radix) Returns the next
token (using the specified radix) as a BigInteger object.
boolean
nextBoolean( ) Returns the next token as a
boolean value.
byte
nextByte( ) Returns the next token as a
byte value. The default radix is used. (Unless changed, the default radix is
10.)
byte
nextByte(int radix) Returns the
next token (using the specified radix) as a byte value.
double
nextDouble( ) Returns the next token as
a double value.
float
nextFloat( ) Returns the next token as a
float value.
int
nextInt( ) Returns the next token
as an int value. The default radix is used. (Unless changed, the default radix
is 10.)
int
nextInt(int radix) Returns the next
token (using the specified radix) as an int value.
String
nextLine( ) Returns the next line
of input as a string.
long
nextLong( ) Returns the next token as a long
value. The default radix is used. (Unless changed, the default radix is 10.)
long
nextLong(int radix) Returns the
next token (using the specified radix) as a long value.
short
nextShort( ) Returns the next
token as a short value. The default radix is used. (Unless changed, the default
radix is 10.)
short
nextShort(int radix) Returns the next
token (using the specified radix) as a short value.
Table 19-17 The Scanner next Methods
For
example, to read the next integer, call nextInt(
). The following sequence shows how to read a list of integers from the
keyboard.
Scanner conin = new
Scanner(System.in); int i;
// Read a list of integers.
while(conin.hasNextInt()) {
i = conin.nextInt(); // ...
}
The while loop stops as soon as the next
token is not an integer. Thus, the loop stops reading integers as soon as a
non-integer is encountered in the input stream.
If a next method cannot find the type of
data it is looking for, it throws an
InputMismatchException. A NoSuchElementException is thrown if no more input is available. For this reason, it is best
to first confirm that the desired type of data is available by calling a hasNext method before calling its
corresponding next method.
Some Scanner Examples
Scanner makes what could be a tedious task into an easy
one. To understand why, let’s look
at some examples. The following program averages a list of numbers entered at
the keyboard:
// Use Scanner to compute an
average of the values.
import java.util.*;
class AvgNums {
public static void
main(String args[]) {
Scanner conin = new
Scanner(System.in);
int count = 0; double sum =
0.0;
System.out.println("Enter
numbers to average.");
// Read and sum numbers.
while(conin.hasNext()) {
if(conin.hasNextDouble()) {
sum += conin.nextDouble();
count++;
}
else {
String str = conin.next();
if(str.equals("done"))
break; else {
System.out.println("Data
format error."); return;
}
}
}
conin.close();
System.out.println("Average
is " + sum / count);
}
}
The
program reads numbers from the keyboard, summing them in the process, until the
user enters the string "done". It then stops input and displays the
average of the numbers. Here is a sample run:
Enter numbers to average. 1.2
2 3.4 4
done
Average is 2.65
The
program reads numbers until it encounters a token that does not represent a
valid double value. When this
occurs, it confirms that the token is the string "done". If it is,
the program terminates normally.
Otherwise, it displays an error.
Notice
that the numbers are read by calling nextDouble(
). This method reads any number that can be converted into a double value, including an integer
value, such as 2, and a floating-point value like 3.4. Thus, a number read by nextDouble( ) need not specify a
decimal point. This same general principle applies to all next methods. They will match and read any data format that can
represent the type of value being requested.
One
thing that is especially nice about Scanner
is that the same technique used to read from one source can be used to read
from another. For example, here is the preceding program reworked to average a
list of numbers contained in a text file:
// Use Scanner to compute an
average of the values in a file.
import java.util.*;
import java.io.*;
class AvgFile {
public static void
main(String args[]) throws IOException {
int count = 0; double sum =
0.0;
// Write output to a file.
FileWriter fout = new
FileWriter("test.txt");
fout.write("2 3.4 5 6
7.4 9.1 10.5 done");
fout.close();
FileReader fin = new
FileReader("Test.txt");
Scanner src = new
Scanner(fin);
// Read and sum numbers.
while(src.hasNext()) {
if(src.hasNextDouble()) { sum
+= src.nextDouble(); count++;
}
String str = src.next();
if(str.equals("done")) break; else {
System.out.println("File
format error."); return;
}
}
}
src.close();
System.out.println("Average
is " + sum / count);
}
}
Here is
the output:
Average is 6.2
The
preceding program illustrates another important feature of Scanner. Notice that the file reader referred to by fin is not closed directly. Rather, it
is closed automatically when src
calls close( ). When you close a Scanner, the Readable associated with it is also closed (if that Readable implements the Closeable interface). Therefore, in
this case, the file referred to by fin
is automatically closed when src is
closed.
Beginning
with JDK 7, Scanner also implements
the AutoCloseable interface. This
means that it can be managed by a try-with-resources
block. As explained in Chapter 13, when try-with-resources
is used, the scanner is automatically closed when the block ends. For example, src in the preceding program could have
been managed like this:
try (Scanner src = new Scanner(fin))
{
// Read and sum numbers.
while(src.hasNext()) {
if(src.hasNextDouble()) {
sum += src.nextDouble();
count++;
}
else {
String str = src.next();
if(str.equals("done"))
break; else {
System.out.println("File
format error."); return;
}
}
}
}
To
clearly demonstrate the closing of a Scanner,
the following examples will call close(
) explicitly. (Doing so also allows them to be compiled by versions of Java
prior to JDK 7.) However, the try-with-resources
approach is more streamlined and can help prevent errors. Its use is
recommended for new code.
One
other point: To keep this and the other examples in this section compact, I/O
exceptions are simply thrown out of main(
). However, your real-world code will normally handle I/O exceptions itself.
You can
use Scanner to read input that
contains several different types of data—even if the order of that data is
unknown in advance. You must simply check what type of data is available before
reading it. For example, consider this program:
// Use Scanner to read
various types of data from a file.
import java.util.*;
import java.io.*;
class ScanMixed {
public static void
main(String args[]) throws IOException {
int i; double d; boolean b;
String str;
// Write output to a file.
FileWriter fout = new
FileWriter("test.txt");
fout.write("Testing
Scanner 10 12.2 one true two false");
fout.close();
FileReader fin = new
FileReader("Test.txt");
Scanner src = new
Scanner(fin);
// Read to end.
while(src.hasNext()) {
if(src.hasNextInt()) { i =
src.nextInt();
System.out.println("int:
" + i);
}
else if(src.hasNextDouble())
{ d = src.nextDouble();
System.out.println("double:
" + d);
}
else if(src.hasNextBoolean())
{ b = src.nextBoolean();
System.out.println("boolean:
" + b);
}
else {
str = src.next();
System.out.println("String: " + str);
}
}
src.close();
}
Here is
the output:
String: Testing String:
Scanner int: 10
double: 12.2 String: one
boolean: true String: two boolean: false
When
reading mixed data types, as the preceding program does, you need to be a bit
careful about the order in which you call the next methods. For example, if the loop reversed the order of the
calls to nextInt( ) and nextDouble( ), both numeric values would
have been read as doubles, because nextDouble( ) matches any numeric
string that can be represented as a double.
Setting Delimiters
Scanner defines where a token starts and ends based on
a set of delimiters. The default delimiters
are the whitespace characters, and this is the delimiter set that the preceding
examples have used. However, it is possible to change the delimiters by calling
the useDelimiter( ) method, shown
here:
Scanner
useDelimiter(String pattern) Scanner
useDelimiter(Pattern pattern)
Here, pattern is a regular expression that
specifies the delimiter set.
Here is
the program that reworks the average program shown earlier so that it reads a
list of numbers that are separated by commas, and any number of spaces:
//Use Scanner to compute an average a list of
//comma-separated values.
import java.util.*; import
java.io.*;
class SetDelimiters {
public static void
main(String args[]) throws IOException {
int count = 0; double sum =
0.0;
// Write output to a file.
FileWriter fout = new
FileWriter("test.txt");
// Now, store values in
comma-separated
list. fout.write("2,
3.4, 5,6, 7.4, 9.1, 10.5, done"); fout.close();
FileReader fin = new
FileReader("Test.txt");
Scanner src = new
Scanner(fin);
//Set delimiters to space and comma.
src.useDelimiter(", *");
//Read and sum numbers.
while(src.hasNext()) {
if(src.hasNextDouble()) { sum
+= src.nextDouble(); count++;
}
else {
String str = src.next();
if(str.equals("done"))
break; else {
System.out.println("File
format error."); return;
}
}
}
src.close();
System.out.println("Average
is " + sum / count);
}
}
In this
version, the numbers written to test.txt
are separated by commas and spaces. The use of the delimiter pattern ", * " tells Scanner to match a comma and zero or
more spaces as delimiters. The output is the same as before.
You can
obtain the current delimiter pattern by calling delimiter( ), shown here: Pattern delimiter( )
Other Scanner Features
Scanner defines several other methods in addition to
those already discussed. One that is particularly
useful in some circumstances is findInLine(
). Its general forms are shown here:
String
findInLine(Pattern pattern)
String
findInLine(String pattern)
This
method searches for the specified pattern within the next line of text. If the
pattern is found, the matching token is consumed and returned. Otherwise, null
is returned. It operates independently of any delimiter set. This method is
useful if you want to locate a specific pattern. For example, the following
program locates the Age field in the input string and then displays the age:
// Demonstrate findInLine().
import java.util.*;
class FindInLineDemo {
public static void
main(String args[]) { String instr = "Name: Tom Age: 28 ID: 77";
Scanner conin = new
Scanner(instr);
// Find and display age.
conin.findInLine("Age:");
// find Age
if(conin.hasNext())
System.out.println(conin.next());
else
System.out.println("Error!");
conin.close();
}
}
The
output is 28. In the program, findInLine( ) is used to find an
occurrence of the pattern "Age". Once found, the next token is read,
which is the age.
Related
to findInLine( ) is findWithinHorizon( ). It is shown here:
String
findWithinHorizon(Pattern pattern,
int count)
String
findWithinHorizon(String pattern, int
count)
This
method attempts to find an occurrence of the specified pattern within the next count characters. If successful, it
returns the matching pattern. Otherwise, it returns null. If count is zero,
then all input is searched until either a match is found or the end of input is
encountered.
You can
bypass a pattern using skip( ),
shown here:
Scanner
skip(Pattern pattern)
Scanner
skip(String pattern)
If pattern is matched, skip( ) simply advances beyond it and returns a reference to the
invoking object. If pattern is not found, skip(
) throws NoSuchElementException.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2024 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.