How to format a float/double into a String
The method printf() can be used to format a float/double to a output stream. However, it does not return a String. In JDK 1.5, a new static method format() is added to the String class, which is similar to printf(), but returns a String. For example,
String strDouble = String.format("%8.2f", 1.23456);
Alternatively, we could use the java.util.Formatter class.
// Allocate a Formatter on the StringBuilder StringBuilder sb = new StringBuilder(); Formatter formatter = new Formatter(sb); // Send all outputs to StringBuilder // format() has the same syntax as printf() formatter.format("%.2f", totalPrice); // 2 decimal places
How to Clone an Object (Copy by Value)
The easiest way is to write a copy constructor, which takes the object to be cloned, construct a new object by copying all the variables (states). For example,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
public class Circle {
public double radius;
public Circle(double radius) {
this.radius = radius;
}
public Circle() {
this.radius = 0.0;
}
// Copy Constructor
public Circle(Circle another) {
this.radius = another.radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public static void main(String[] args) {
Circle c1 = new Circle(1.1);
System.out.println(c1.getRadius()); // 1.1
Circle c2 = new Circle(c1); // Construct c2 by cloning c1
System.out.println(c2.getRadius()); // 1.1
c2.setRadius(2.2);
System.out.println(c1.getRadius()); // 1.1
System.out.println(c2.getRadius()); // 2.2
Circle c3 = c1; // Assign the reference of c1 to c3
// c1 and c3 points to the same object
System.out.println(c3.getRadius()); // 1.1
c1.setRadius(3.3);
System.out.println(c3.getRadius()); // 3.3
}
}
|
If the object contains object members, you need to do a deep copy, i.e., clone the object members as well.
Cloneable Interface and Object's clone() method
The java.lang.Cloneable interface defines a method called clone(). The java.lang.Object provides a method called clone() to create a clone copy. To use the Object's clone() method, the class shall implement the cloneable interface and invoke the inherited clone() method from Object. the For example,
public class Circle implements Cloneable { .... } Circle c1 = new Circle(1.1); Circle c2 = (Circle)c1.clone(); // Invoke the inherited Object's clone() method. // clone() returns an Object, need to downcast to Circle
However, the Object's clone() method makes a shallow copy, i.e., it copies only the first level of variables and does not do a deep copy for object members. Classes implementing Cloneable interface is recommended to override the inherited Object's clone() method to perform deep copying. Avoid using Object's clone().
How to initialize a static array of objects
Suppose that we have a class called Book, as follows:
public class Book {
private String title;
private float price;
public Book(String title, float price) { // Constructor
this.title = title;
this.price = price;
}
public String getTitle() { return title; }
public float getPrice() { return price; }
}
Suppose that we want to create a static array of Books for global access. We need to use the static initializer as follows:
/** * Book Database * Contain a static array of Book, and static methods for operation. * The array index is used as the bookID. */ public class BookDB { private static Book[] books; static { // static initializer block books = new Book[2]; books[0] = new Book("Java for Dummies", 19.99f); books[1] = new Book("More Java for Dummies", 29.99f); } public static int size() { return books.length; } public static String getTitle(int bookID) { return books[bookID].getTitle(); } public static float getPrice(int bookID) { return books[bookID].getPrice(); } // Testing public static void main(String[] args) { System.out.println(BookDB.size()); System.out.println(BookDB.getTitle(0)); System.out.println(BookDB.getPrice(0)); } }
Why Java Vector and Hashtable are considered obsolete or deprecated?
Vector and Hastable were introduced in ...
Use ArrayList to replace Vector, and HashMap for Hashtable.
Printing Newline with '\n'
Line delimiter (or new line) is platform dependent. Windows uses "\r\n" (\r for carriage return with ASCII code 0DH or decimal 13; \n for line feed with ASCII code 0AH or decimal 10); Unix and Mac OS X uses "\n" alone; Mac OS up to version 9 uses "\r".
The default line separator is kept in system property line.separator. You could print it as follows:
String str = System.getProperty("line.separator");
for (int i = 0; i < str.length(); ++i) {
System.out.printf("%02X(hex) ", (int)str.charAt(i)); // %02X: Pad with 0, 2 spaces, in hex
}
0D(hex) 0A(hex)
Using '\n' in print(), println() and printf() methods to print a line feed (0AH) may result in non-portable codes.
It is recommended to use System.out.println() to print a system-specific new line, or printf() with format specifier "%n", instead of "\n" for system-specific new line.
System Properties
Java maintains a set of system properties for its operations. Each system property is a key-value (String-String) pair such as "java.version"="1.7.0_09". You can retrieve all the system properties via System.getProperties(). You can also retrieve individual property via System.getProperty(key). For example,
import java.util.Properties;
public class PrintSystemProperties {
public static void main(String[] a) {
// List all System properties
Properties pros = System.getProperties();
pros.list(System.out);
// Get a particular System property given its key
// Return the property value or null
System.out.println(System.getProperty("java.home"));
System.out.println(System.getProperty("java.library.path"));
System.out.println(System.getProperty("java.ext.dirs"));
System.out.println(System.getProperty("java.class.path"));
}
}
The important system properties are:
- JRE related:
- java.home: JRE home directory, e.g., "
C:\Program Files\Java\jdk1.7.0_09\jre". - java.library.path: JRE library search path for search native libraries. It is usually but not necessarily taken from the environment variable
PATH. - java.class.path: JRE
CLASSPATH, e.g.,.(for current working directory). - java.ext.dirs: JRE extension library path(s), e.g, "
C:\Program Files\Java\jdk1.7.0_09\jre\lib\ext;C:\Windows\Sun\Java\lib\ext". - java.version: JRE version, e.g.,
1.7.0_09. - java.runtime.version: JRE version,
e.g. 1.7.0_09-b05.
- java.home: JRE home directory, e.g., "
- File related:
- file.separator: symbol for file directory separator such as
d:\test\test.java. The default is\for windows or/for Unix/Mac. - path.separator: symbol for separating path entries, e.g., in
PATHorCLASSPATH. The default is;for windows or:for Unix/Mac. - line.separator: symbol for end-of-line (or new line). The default is
"\r\n"for windows or"\n"for Unix/Mac OS X.
- file.separator: symbol for file directory separator such as
- User related:
- user.name: the user's name.
- user.home: the user's home directory.
- user.dir: the user's current working directory.
- OS related:
- os.name: the OS's name, e.g., "Windows 7".
- os.version: the OS's version, e.g., "6.1".
- os.arch: the OS's architecture, e.g., "x86".
Access to system properties can be restricted by the Java security manager and policy file. By default, Java programs have unrestricted access to all the system properties.
Which JRE?
In system property java.home.
[TODO]
Where are the Java Extension Library Paths?
In system property java.ext.dirs. There could be more than one extension library paths.
[TODO]
Java Security Manager and Policy File
Reference:
- Java Tutorial's "Quick Tour of Controlling Applications".
- Java Tutorial's Trail "Security Features in Java SE".
- Permissions in JDK 7 @ http://docs.oracle.com/javase/7/docs/technotes/guides/security/permissions.html.
Security Manager
Java runtime does NOT automatically install a security manager when it runs Java application. As the result, the Java applications have unrestricted access to all the system. For example, the following Java program (a) read system property "user.home", (b) read from file "in.txt", (c) write to file "out.txt".
import java.util.*;
import java.io.*;
public class TestPermissions {
public static void main(String[] args) throws Exception {
// Read System Property
System.out.println(System.getProperty("user.home"));
// Read File
Scanner in = new Scanner (new File("in.txt"));
int num1 = in.nextInt();
int num2 = in.nextInt();
System.out.println("The 2 numbers are: " + num1 + ", " + num2);
// Write File
Formatter out = new Formatter(new File("out.txt"));
int sum = num1 + num2;
System.out.println("The sum is " + sum);
out.format("%d", sum);
out.close();
}
}
Create the input file "in.txt" with 2 number "1 2". Compile and run the program. Everything shall be fine as Java programs have unrestricted permissions, if security manager is not installed.
To explicitly install a Java security manager, run JRE with option -Djava.security.manager.
java -Djava.security.manager TestPermissions
You shall receive a security exception:
Exception in thread "main" java.security.AccessControlException: access denied ("java.util.PropertyPermission" "user.home" "read")
The security manager, by default, fetches the permissions from <JRE_HOME>\lib\security\java.policy. Take a look at this policy file, it grants read permission to many system properties, but NOT including "user.home".
If you commented out the System.getProperty() line and run the program with security manager, you will receive this error:
Exception in thread "main" java.security.AccessControlException: access denied ("java.io.FilePermission" "out.txt" "write")
You have not write access to "out.txt". However, you do have read access to "in.txt".
Granting Permissions
The security manager, by default, fetches the system policy file from <java.home>\lib\security\java.policy, where <java.home> is the Java system property "java.home", which defaults to JRE home directory.
Let's create a user policy file called "myjava.policy" to grant the permissions needed for the above program. Suppose that the program and the files are location at "d:\myproject".
grant codeBase "file:/D:/myproject/" {
permission java.util.PropertyPermission "user.home", "read";
permission java.io.FilePermission "D:/myproject/out.txt", "write";
};
The codeBase indicates the base directory of the executing program, which shall be a URL beginning with a protocol such as file: for local programs (or http: for applets). A codeBase ends with "/" matches all class files (not JAR files) in the specified directory. A codeBase ends with "/*" matches all class files and JAR files. A codeBase ends with "/-" matches all class files and JAR files in the directory and its subdirectories.
In the above policy file, we grant read permission to system property "user.home", and write file permission to "out.txt".
To include the user policy file (in addition to the system policy files), use command-line option -Djava.security.policy:
D:\myproject> java -Djava.security.manager -Djava.security.policy=myjava.policy TestPermissions
The program shall now complete its execution.
If you use double equal == in assigning policy file, the system policy files will be ignore. That is, only the specified policy file will be used.
D:\myproject> java -Djava.security.manager -Djava.security.policy==myjava.policy TestPermissions
Including User Policy Files
By default, the security manager fetches these policy files, as specified in its property file located at <JRE_HOME>\lib\security\java.security:
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
where "java.home" and "user.home" are Java system properties.
To include user policy file(s), you could either:
- Include it in JRE's command-line option
-Djava.security.policyas in the above example. - Include it in the security properties file
<JRE_HOME>\lib\security\java.security, as follows:policy.url.3=file:/D:/myproejct/myjava.policy
Types of Permission
Each permission has a type (e.g., java.io.FilePermission, java.util.PropertyPermission), a target name (e.g., property name or filename) and a comma-separated list of one or more actions (e.g., read, write).
Permissions can be granted to programs under a codeBase.
The commonly-used permission types are:
- java.security.AllPermission: All the permissions. For example, the default system policy file grants
AllPermissionto all the classes and JAR files in the Java extension paths:grant codeBase "file:${{java.ext.dirs}}/*" { permission java.security.AllPermission; };GrantingAllPermissionpractically disables security manager and shall be done with great care. - java.io.FilePermission: grant permission to file and directory.
A pathname ends with "/*" indicates all files in that directory; "/-" indicates all file in that directory and subdirectories; "*" indicates all file in the current working directory; "-" indicates all files in the current working directory and its subdirectories;<<ALL FILES>>indicates any file.
The actions (comma-separated) include: read, write, delete, and execute (allowRuntime.exec()). - java.net.SocketPermission: permit access to a network via socket.
The target name consists ofhostname:port. A port specification of "n-" indicate port numbernand above; "-n" all port numbernand below.
The actions include:accept,connect,listenandresolve(DNS lookup). When use with localhost,listenis the only meaningful action.
For example, the default system policy file grant listen permission to localhost of port 1024 and above (un-privilege port).permission java.net.SocketPermission "localhost:1024-", "listen";
- java.util.PropertyPermission: The target name is a property name. The actions include:
readandwrite. - java.lang.RuntimePermission: Only target name without action, e.g., the target "
stopThread" permits stopping of threads via calls to theThread'sstop()method. - java.sql.SQLPermission: [TODO]
Signing Code and Granting Permission
[TODO]
Run External Process from Java
You could use either Runtime.getRuntime.exec() or a ProcessBuilder.
exec() method
The API doc for exec() of java.lang.Runtime is:
public Process exec(String command) throws IOException
// Executes the specified string command in a separate process.
// It returns a java.lang.Process object.
The Process object provides a waitFor() method, which "causes the current thread to wait, if necessary, until the process represented by this Process object has terminated." waitFor() returns the exit value of the subprocess (with 0 for normal termination).
Example
public class TestExec {
public static void main(String[] a) {
// Invoke external command via exec(), which returns a Process
Process p = null;
try {
p = Runtime.getRuntime().exec("javac Add2Numbers.java"); // Compile
} catch (java.io.IOException ex) {}
// Wait for the process to complete
try {
int exitValue = p.waitFor();
System.out.println("Process Completed with exit value of " + exitValue);
} catch (InterruptedException ex) {}
}
}
You can optionally specifies an environment (a set of name=value pairs) and an initial working directory.
The Add2Numbers reads 2 integer from System.in and prints their sum to System.out, as follows:
import java.util.Scanner;
public class Add2Numbers {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int num1 = in.nextInt();
int num2 = in.nextInt();
System.out.println(num1 + num2);
}
}
With Input/Output for the Subprocess
By default, the subprocess' standard input, output and error will be piped from/to the parent process. You can access the standard input via stream obtained from subprocess' getOutputStream() (output stream of the parent process is piped into the subprocess' standard input). Similarly, you can obtain the standard output stream of the subprocess via getInputStream() (input to parent process); and standard error via getErrorStream(). For example,
import java.io.*;
public class TestExecRedirect {
public static void main(String[] a) {
try {
Process p = Runtime.getRuntime().exec("java Add2Numbers"); // Execute with input/output
// Write into the standard input of the subprocess
PrintStream pin = new PrintStream(new BufferedOutputStream(p.getOutputStream()));
// Read from the standard output of the subprocess
BufferedReader pout = new BufferedReader(new InputStreamReader(p.getInputStream()));
// Pump in input
pin.print("1 2");
pin.close();
// Save the output in a StringBuffer for further processing
StringBuffer sb = new StringBuffer();
int ch;
while ((ch = pout.read()) != -1) {
sb.append((char)ch);
}
System.out.println(sb);
int exitValue = p.waitFor();
System.out.println("Process Completed with exit value of " + exitValue);
} catch (IOException ex) {
} catch (InterruptedException ex) {}
}
}
ProcessBuilder
JDK 1.5 introduces a new ProcessBuilder class in java.lang, which manages command, environment, initial working directory, as well as standard input, output and error of a process. To use the ProcessBuilder, construct an instance and invoke its start() method. start() returns a Process object.
Example
public class TestProcessBuilder {
public static void main(String[] a) {
try {
// Allocate a ProcessBuilder for the command
ProcessBuilder pb = new ProcessBuilder("javac", "Add2Numbers.java"); // Compile (no standard input)
// Start the process
Process p = pb.start();
// Wait for the process to complete
int exitValue = p.waitFor();
System.out.println("Process Completed with exit value of " + exitValue);
} catch (java.io.IOException ex) {
} catch (InterruptedException ex) {}
}
}
Redirecting Input/Output of the Subprocess to Files
Same as exec(), by default, subprocess reads input from a pipe and write output and error to a pipe of the parent process. In ProcessBuilder, you can conveniently redirect the subprocess' input, output and error to a file (as of JDK 1.7), as follows:
import java.io.File;
public class TestProcessBuilderRedirect {
public static void main(String[] a) {
try {
ProcessBuilder pb = new ProcessBuilder("java", "Add2Numbers"); // Execute (with standard input and output)
File log = new File("error.log");
// pb.redirectErrorStream(true); // merge output and error streams
pb.redirectInput(ProcessBuilder.Redirect.from(new File("in.txt")));
pb.redirectOutput(ProcessBuilder.Redirect.to(new File("out.txt")));
pb.redirectError(ProcessBuilder.Redirect.appendTo(new File("error.log")));
Process p = pb.start();
int exitValue = p.waitFor();
System.out.println("Process Completed with exit value of " + exitValue);
} catch (java.io.IOException ex) {
} catch (InterruptedException ex) {}
}
}
However, the redirect methods work only for files. For other IO streams, you need to access via Process' getOutputStream() and getInputStream() (as in the exec() section's example).
How to Redirect Standard Input, Output and Error Streams
You can re-direct the standard input (System.in), standard output (System.out) and standard error (System.err) to another IO stream (such as file or network socket) via static methods System.setIn(), System.setOut() and System.setErr(). The signature of the methods are:
public static void setIn(InputStream in) public static void setOut(PrintStream out) public static void setErr(PrintStream err)
For example,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import java.io.*;
import java.util.*;
public class TestRedirect {
public static void main(String[] args) throws IOException {
PrintStream sysout =
new PrintStream(
new BufferedOutputStream(
new FileOutputStream("out.txt", true))); // append outputs to file
InputStream sysin =
new BufferedInputStream(
new FileInputStream("in.txt"));
// Redirect to file
System.setIn(sysin);
System.setOut(sysout);
System.setErr(sysout); // merge error and output streams
// Test inputting/outputting
Scanner in = new Scanner(System.in);
System.err.println("Let's begin...");
System.out.print("Enter two integers: ");
int num1 = in.nextInt();
int num2 = in.nextInt();
int sum = num1 + num2;
System.out.println("The sum is " + sum);
sysout.flush();
sysout.close();
sysin.close();
}
}
|
[TODO] Check on FileWriter and FileReader, instead of FileInputStream and FileOutputStream.
How to Append to a File
Use these constructors of the FileOutputStream and FileWriter, which take a second boolean argument to indicate append:
FileWriter(File file, boolean append) FileWriter(String fileName, boolean append) FileOutputStream(File file, boolean append) FileOutputStream(String name, boolean append)
See "How to Redirect Standard Input, Output and Error Streams" for example.
Array Miscellaneous
The java.util.Arrays Class
The java.util.Arrays contains various methods for manipulating arrays (such as sorting and searching). It also contains a static factory that allows arrays to be viewed as lists.
It contains static methods:
Arrays.toString(anArray): to print the given array. It is overloaded to support all primitive-element array likeint[],double[], etc.Arrays.copyOf(srcArray, length): Return a copy of thesrcArraytruncate/pad to the givenlength. [You can also useanArray.clone()to create a copy of an array.]
Assign an Array to Another
For example,
int[] a1 = {1, 2, 3};
int[] a2 = a1; // assign a2 to the same reference as a1
System.out.println(Arrays.toString(a2)); // [1, 2, 3]
In Java, arrays are reference object.
Compound Assignment (e.g., +=) has an implicit cast
For example,
int n = 1; n = n + 1.5; // error: incompatible types: possible lossy conversion from double to int n += 1.5; // no error!
The compound assignment does not produce a compilation error because a implicit cast is added, as follows:
int n = 1;
n += 1.5; // same as n = (int)(n + 1.5)
Hence, x += y is not really x = x + y, but x = (typeOfX)(x + y).
What is =+?
a =+ b is actually a = (+b). a =- b is a = (-b). a =*b produces an error.
REFERENCES & RESOURCES
- [TODO]