| Home > Core Java FAQ
> Miscellaneous FAQ |
| Miscellaneous |
| java.lang
& java.util Package(08) * Sound(14)
* Jar (06) |
| |
|
Q . Why doesn't String's replace method have any effect when I apply it to a string?
|
Ans :
String's
replace method, like other String
methods, doesn't alter the original string; instead, it creates a
new String instance with the
specified properties.
The
String class creates read-only (immutable)
strings. Once you create a String instance, you can
inspect it and use it to build other strings, but you cannot alter
that instance itself. Any String method that sounds
like it would change the string actually creates a new string with
the properties required by the method. The replace
method, for instance, performs character replacement in a new
string copy rather than the original string:
String oldString = "java.lang.Thread";
String newString = oldString.replace('.', '/');
After this code
executes, newString has the value "java/lang/Thread"
and the value of oldString remains unchanged.
Table 11.1 shows all the String
methods that look like they could alter a string (but instead
create a new string with the alterations shown there).
Table
11.1: String Methods with the
Appearance of Mutating a String
| Method |
Creates
new string based on target string by ___ |
| concat(String) |
appending
the argument string |
| replace(char,
char) |
replacing
all occurrences of the first argument character with the
second argument character |
| toLowerCase() |
converting
all uppercase characters to lowercase |
| toUpperCase() |
converting
all lowercase characters to uppercase |
| trim() |
removing
any whitespace from both ends of string |
If
you need editable strings, use the StringBuffer
class—it provides several methods, shown in Table 11.2, that
directly modify a StringBuffer instance.
Table
11.2: StringBuffer Methods
that Modify a StringBuffer
Instance
| Method |
Modifies
the target StringBuffer instance by ___ |
| append
[many varieties] |
appending
a string representation of a primitive type or object |
| insert
[many varieties] |
inserting
a string representation of a primitive type or object at
the specifed buffer location |
| reverse()
[in JDK 1.1] |
reversing
the characters in the buffer |
| setCharAt(int,
char) |
setting
the character at the specified buffer location |
| setLength(int) |
setting
the length of the buffer, possibly truncating characters
stored in the buffer |
|
|
Q .
Does Java provide standard iterator functions for inspecting a collection of objects?
|
Ans
:
Sort of;
the Enumeration
interface in the java.util package
provides a bare-bones framework for stepping once through a
collection of objects.
The Enumeration
interface in the java.util package lets you extract
elements one by one from a collection without needing to know how
the collection is implemented. The interface comprises just two
methods:
/* in Enumeration.java (JDK 1.0.2 and 1.1): */
public interface Enumeration {
boolean hasMoreElements();
Object nextElement();
}
The
hasMoreElements method determines whether the
enumeration has more elements to offer. The nextElement
method returns the next element in the enume-ration, if there is
one. The first invocation of nextElement on a fresh Enumeration
object returns the first element.
Enumerations are consumed as you use
them; each invocation of nextElement should yield a
new element from the underlying collection—one that you haven't
seen yet. To borrow a phrase from probability theory, the nextElement
method constitutes sampling without replacement.
In addition to their simplicity,
enumerations are very flexible. An enumeration can provide all
types of Java objects. The nextElement method is
defined as returning objects of type Object, which
automatically extends to all subclasses of Object as
well as all arrays. What's more, a single enumeration can even
yield objects of different types on different calls to nextElement,
although the usual case is for the elements in an enumeration to
all belong to the same class (or have some common superclass that
is more specific than Object).
The most common way to use an
enumeration is for inspecting the collection of elements returned
from some object. Several collection classes in the standard Java
packages include methods that return an enumeration of the
collection's elements. For example, the keys method
in the Hashtable class (in java.util)
returns an enumeration of all the keys in a given hashtable; you
can loop through this enumeration to print out all the keys as
follows:
Hashtable symbols = ...;
Enumeration symbolKeys = symbols.keys();
System.out.println("Keys in symbol table:");
while (symbolKeys.hasMoreElements()) {
System.out.println(" " + symbolKeys.nextElement());
}
|
|
Q . The Math.random method is too limited for my needs how can I generate random numbers more flexibly?
|
Ans
:
The random
method in the Math class provides
quick, convenient access to (pseudo-)random numbers, but for more
power and flexibility, use the Random
class in the java.util package.
The
core Java packages provide two ways to generate pseudo-random
(that is, nearly or apparently random) numbers. The random
method in the Math class is primarily a convenience
method for easily generating random numbers. It requires no
preparation in advance—you merely invoke Math.random()
each time you want a new random value:
for (int i = 0; i < 10; ++i) {
double doubleVal = Math.random();
System.out.println("doubleVal = " + doubleVal);
}
The random
method returns a double value greater than or equal to 0.0 and
less than 1.0.
If you need greater flexibility,
then consider using the java.util.Random class. The Random
class provides methods returning float, double,
int, and long values; it also provides
random numbers from a Gaussian ("normal," or
"bell-shaped") distribution. Table 11.4 summarizes the
relevant methods.
Table
11.4: Methods in the Random
Class
| Method |
Returns |
| nextFloat |
type
float; 0.0 <= value < 1.0 |
| nextDouble |
type
double; 0.0 <= value < 1.0 |
| nextInt |
type
int; Integer.MIN_VALUE <= value
<= Integer.MAX_VALUE |
| nextLong |
type
long; Long.MIN_VALUE <= value
<= Long.MAX_VALUE |
| nextGaussian |
type
double; has Gaussian ("normal")
distribution with mean 0.0 and standard deviation 1.0 |
Each
(non-Gaussian) random value method returns a value within a
standard range for the data type in question. If you want random
numbers representing some other range, take the output from the
method with the correct return type and scale and shift its
output. For example, the following code fragment generates float
values ranging from -10.0 to just under 10.0
(9.9999...):
Random r = new Random();
for (int i = 0; i < 10; ++i) {
float floatVal = r.nextFloat() * 20 - 10;
System.out.println("floatVal = " + floatVal);
}
The
return value of nextFloat is scaled and shifted as
follows. Multiplying by 20 expands the output range to be from 0.0
to just under 20.0; subtracting 10 then shifts that range to be
from -10.0 to just under 10.0.
If you want to be more precise and
exclude both endpoints, you need to complicate the nextFloat
line a little:
do {
floatVal = r.nextFloat() * 20 - 10;
} while (floatVal == -10.0)
|
|
Q . How random is Random()?
|
Ans
:
It's good enough for games. I wouldn't use it for cryptography.
Unlike most random functions in other libraries the Math.random() method seeds itself with the current time in milliseconds. Thus you do not need to seed it explicitly at the start of your program. If you require a non-random Random() for test purposes or you need more randomness than the current time in milliseconds can provide, then you can use java.util.Random() which has a constructor that lets you specify a seed.
|
|
Q . How do I generate a random integer between a and b?
|
Ans
:
Generate a random double between 0.0 and 1.0, multiply by the number of int values you want to choose from, add the smallest int value you want, round it down to the nearest integer using Math.floor(), and cast the result to an int. For example, the following class simulates a six-sided die by producing random, uniformly distributed ints between 1 and 6.
public class Die {
Random generator = new Random();
public static int roll() {
// get a rcandom number between 0 and 1
double r = generator.nextDouble();
// multiply by 6 so it's now between 0 and 6
r *= 6.0;
// add 1
r += 1.0;
//truncate it to an int
r = Math.floor(r);
// handle one special if unlikely case
if (r == 7.0) r = 6.0;
// convert to an int and return
return (int) r;
}
}
|
|
Q . Make a linked list without pointers?
|
Ans :
Short answer: Use the Vector class in java.util. It can do anything a linked list can do and a little more and saves you a lot of coding which, after all, is the point of OOP and the class library. However it is array based so insertions or deletions from the middle of a Vector are not as efficient as with a true linked list.
Long answer: Object variables in Java are all references. A reference acts like a pointer in most other languages. (Though they're handles, not pointers, in most Java implementations. The notable exception is Microsoft's.) The main difference is that you can't do pointer arithmetic on references. Therefore wherever you'd use a pointer to an object in C++, in Java you should just use the object itself.
On the other hand the primitive data types (int, float, double, char, byte, short, long and boolean) are not references. If you want to get a reference to one of these you need to wrap it in a class first. Java provides ready-made type-wrapper classes in the java.lang package for Boolean, Character, Integer, Double, Float, and Long. Bytes and shorts can be stored in the Integer class as well. Java 1.1 adds Byte, Short, and Void classes too.
|
|
Q . How do I create a Vector of ints?
|
Ans
:
ints are primitive types and hence can't be stored by the Vector
class, which stores objects. You'll need to wrap the ints. Try this:
int i =7;
Vector holdsInts = new Vector(5,1);
holdsInts.addElement(new Integer(i));
int j = ((Integer)holdsInts.elementAt(0)).intValue();
|
|
Q .
Where/why should I use the Enumeration interface?
|
Ans
:
It's a very convenient way to step through some of the library data
structures, such as HashTable, Vector, and ZipFile. It is thread safe.
If you're looking at an element in one thread while another thread is
trying to delete it, it won't half vanish.
Here's how you might look at every file in a ZIP file:
ZipFile z = new ZipFile("foo.zip");
Enumeration e = null;
for (e=z.entries(); e.hasMoreElements(); ) {
ZipEntry ze = (ZipEntry)e.nextElement();
System.out.println("got " + ze.getName() );
}
And here's how you might look at all the tokens in a String:
StringTokenizer tokens = new StringTokenizer (SomeArbitraryString, "\n", false);
Enumeration enum = tokens.elements();
while enum.hasMoreElements()
System.out.println(enum.nextElement());
You should look for opportunities in your own data structures to implement Enumeration anywhere where the structure has repeated
elements.
|
|