Return-Path: Received: from pacific-carrier-annex.mit.edu by po10.mit.edu (8.9.2/4.7) id MAA27882; Tue, 4 Dec 2001 12:34:19 -0500 (EST) Received: from hermes.sun.com (hermes.sun.com [64.124.140.169]) by pacific-carrier-annex.mit.edu (8.9.2/8.9.2) with SMTP id MAA29139 for ; Tue, 4 Dec 2001 12:34:18 -0500 (EST) Date: Tue, 4 Dec 2001 17:34:19 GMT+00:00 From: "JDC Tech Tips" To: alexp@mit.edu Message-Id: <61366481106493798@hermes.sun.com> Subject: JDC Tech Tips December 4, 2001 Precedence: junk Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: Beyond Email J D C T E C H T I P S TIPS, TECHNIQUES, AND SAMPLE CODE WELCOME to the Java Developer Connection(sm) (JDC) Tech Tips, December 4, 2001. This issue covers: * Accessing the Environment from Java(tm) Applications * Working With Number Bases These tips were developed using Java(tm) 2 SDK, Standard Edition, v 1.3. You can view this issue of the Tech Tips on the Web at http://java.sun.com/jdc/JDCTechTips/2001/tt1204.html - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ACCESSING THE ENVIRONMENT FROM JAVA APPLICATIONS If you've used UNIX or Windows systems very much, you're probably familiar with what are called environment variables. These variables are a group of settings that exist outside of applications, but are available within those applications. On UNIX systems, these settings are typically maintained by the shell and transmitted to programs that the shell invokes. An example of environment variable settings on a UNIX system might be: HOME=/home/aname USER=aname You can access these variables inside a C program by using the standard library function getenv. Such settings are used to personalize an application. The System class in java.lang has a method getenv for accessing environment variables. Here's a simple example that uses the method: public class EnvDemo1 { public static void main(String args[]) { String s = System.getenv("USER"); System.out.println(s); } } The getenv method is deprecated, so you'll get a warning when you compile the program. You'll also get an exception if you try to run it. Why this behavior? The fundamental reason is simply that the concept of environment variables is not portable. There's no guarantee that a given operating system supports them, and even if it does, the settings might not be uniform. For example, a particular Windows system might not have a USER variable, but instead have a USERNAME one. So assuming the presence of USER in a Java application will not work in a system that doesn't support it. If you must have access to environment variables, there are a couple of ways to do that. You could use the Java Native Interface to access a small C function that calls getenv. This approach works but is not portable. Another approach is to pass the value of the environment variable into your Java application when the application is invoked. Here's a short program that illustrates this technique: public class EnvDemo2 { public static void main(String args[]) { String s = System.getProperty("localuser"); System.out.println("localuser = " + s); } } If you issue the commands: javac EnvDemo2.java java -Dlocaluser=$USERNAME EnvDemo2 the result is: localuser = username where "username" is replaced with the value of the USERNAME environment variable on your system. Of course, this assumes that your system includes the USERNAME environment variable. System properties are the Java equivalent to environment variables. The -D flag and the call to System.getProperty are a mechanism to pass property values into a Java application when the application is launched. This approach works, but it's still dependent on environment variables. There is however a better way. In this approach, you use standard system properties. For example, to get the name of the current user, you can say: public class EnvDemo3 { public static void main(String args[]) { String s = System.getProperty("user.name"); System.out.println(s); } } user.name is one of a set of standard properties that are guaranteed to be defined in your Java system. To get a list of all the property settings that your local system knows about, you can run this program: import java.util.Properties; public class EnvDemo4 { public static void main(String args[]) { Properties p = System.getProperties(); p.list(System.out); } } On a Windows system, part of the output should look something like this: -- listing properties -- file.separator=\ java.vendor.url.bug= http://java.sun.com/cgi-bin/bugreport... sun.cpu.endian=little sun.io.unicode.encoding=UnicodeLittle user.region=US sun.cpu.isalist=pentium i486 i386 Note that the file.separator is set to \, indicating that this is a Windows system rather than a UNIX one. Java applications must account for such environment variations or else they will have portability problems. When you're working with properties, there are some utility methods you can use to simplify the programming. Here's one example: public class EnvDemo5 { public static void main(String args[]) { Integer size = Integer.getInteger("size"); System.out.println("size = " + size); } } Integer.getInteger is a method that looks up a system property and returns its Integer value, or null if the property does not exist. For example, if you say: javac EnvDemo5.java java -Dsize=59 EnvDemo5 the result is: size = 59 There is another aspect of properties to look at. You might customize an application by passing property settings to it with the -D option. However, you can also define your own property files, and save and restore a group of properties with a single operation. Here is an example of this technique. This first program is used to write the property file: import java.io.*; import java.util.Properties; public class EnvDemo6 { public static void main(String args[]) throws IOException { FileOutputStream fos = new FileOutputStream("test.prop"); BufferedOutputStream bos = new BufferedOutputStream(fos); Properties p = new Properties(); p.setProperty("key1", "value1"); p.setProperty("key2", "value2"); p.store(bos, "Testing"); bos.close(); } } The demo program sets up two properties as key-value pairs, and stores these in a file named test.prop. The file looks something like this: #Testing #Thu Nov 15 14:11:43 MST 2001 key2=value2 key1=value1 You can then run the following program to read this properties file into a Properties object, and access the properties: import java.io.*; import java.util.Properties; public class EnvDemo7 { public static void main(String args[]) throws IOException { FileInputStream fis = new FileInputStream("test.prop"); BufferedInputStream bis = new BufferedInputStream(fis); Properties p = new Properties(); p.load(bis); bis.close(); System.out.println( "key1=" + p.getProperty("key1")); System.out.println( "key2=" + p.getProperty("key2")); } } The result is: key1=value1 key2=value2 A final point about Java programming and environment access has to do with the Runtime.exec method. This method is used to call a subprogram. The subprogram can access environment variables. Sometimes you might want to control the variables passed to the subprogram. Here's an example of how you do this: import java.io.*; public class EnvDemo8 { public static void main(String args[]) throws IOException { // invoke subprogram Runtime rt = Runtime.getRuntime(); String env[] = null; //String env[] = new String[]{"test=456"}; Process p = rt.exec("genv", env); // set up to read subprogram output InputStream is = p.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); // read output from subprogram // and display it String s; while ((s = br.readLine()) != null) { System.out.println(s); } br.close(); } } This demo invokes a subprogram genv, that displays the current value of the environment variable test. genv is a C program, written like this: /* genv.c */ #include #include int main() { printf("test=%s\n", getenv("test")); } If the second argument to the Runtime.exec method is null, then the subprogram inherits the environment of the calling process, that is, the Java program launcher. In the Windows environment, you set the environment variable "test" by saying: set test=123 You then run the Java program by saying: java EnvDemo8 In UNIX environments, you say: env test=123 java EnvDemo8 The result is: test=123 But if you comment the first "env[] = " line in EnvDemo8, and uncomment the second one, the result is: test=456 In the first case, the environment is set on the command line when the Java launcher is invoked. It is then passed through to the subprogram. But in the second case, the environment is overridden within the EnvDemo8 program, and then passed to the subprogram. For more information about accessing the environment from Java applications, see Section 18.1.2, System Properties, and Section 18.2.2, Process Environments, in "The Java(tm) Programming Language Third Edition" by Arnold, Gosling, and Holmes http://java.sun.com/docs/books/javaprog/thirdedition/. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - WORKING WITH NUMBER BASES There are many applications where you need to manipulate integer values using a base or radix other than 10. You might, for example, be performing logical manipulations using binary (base-2) values, or interpreting memory addresses in hexadecimal (base-16). All Java integer arithmetic is done using two's-complement binary operations. However, you can display and convert values using any base from 2 to 36. In this tip you'll see some of the facilities that are available for working with numeric bases. Integer.parseInt is used to convert a string to an integer. You can specify the base when you call this method. Here's a simple example of using the method: public class BaseDemo1 { public static void main(String args[]) { int ival = Integer.parseInt("10101", 2); System.out.println( "value of 10101 as decimal = " + ival); } } When you run the program, the result is: value of 10101 as decimal = 21 The binary string 10101 has been converted to the decimal value 21. You can reverse this process with the Integer.toString method: public class BaseDemo2 { public static void main(String args[]) { int ival = 123456; String s = Integer.toString(ival, 29).toUpperCase(); System.out.println( "123456 in base-29 = " + s); } } The result here is: 123456 in base-29 = 51N3 This says that 51N3 base-29 is the same as 123456 base-10. Higher bases will result in more compact string representations for the same number. For example, a base-32 number has only 20% as many digits as a base-2 number, simply because each base-32 digit is equivalent to five base-2 digits. If you are working with a base greater than 10, then the letter values a-z are also used as digits. Note that lowercase letters are used. If you want an uppercase result, then you need to call the toUpperCase method. The Integer class also provides the methods toBinaryString, toOctalString, and toHexString. These are shortcuts you can use in place of the toString method. For positive values, the operation is identical, but for negative values, the value of the sign is encoded in the bit pattern. For example, Integer.toHexString(-1) results in: ffffffff This result is the hexadecimal two's-complement representation of -1. In other words, negative values are treated as unsigned quantities. When you use parseInt to convert strings to numbers, a prefix such as "0x" for hexadecimal is not accepted. It will trigger an exception. If you want to convert strings that have this kind of prefix, you need to use Integer.decode, like this: public class BaseDemo3 { public static void main(String args[]) { //int ival = Integer.parseInt( // "0x123456", 16); Integer in = Integer.decode("0x123456"); int ival = in.intValue(); System.out.println( Integer.toString(ival, 16)); in = Integer.decode("0123456"); ival = in.intValue(); System.out.println( Integer.toString(ival, 8)); } } When you run this program, the result is: 123456 123456 The list of prefixes accepted by the decode method is: 0x, 0X, # hexadecimal 0 octal You can also specify bases other than 10 when you use the BigInteger class. This is a class that supports arbitrary-precision arithmetic. Here's an example: import java.math.BigInteger; public class BaseDemo4 { public static void main(String args[]) { String num = "111111111111111111111111111111"; BigInteger bi = new BigInteger(num, 2); BigInteger res = bi.multiply(bi); System.out.println("product in base-2 = "); System.out.println(res.toString(2)); System.out.println(); System.out.println( "product in base-10 = "); System.out.println(res.toString(10)); System.out.println(); System.out.println( "product in base-16 = "); System.out.println(res.toString(16)); } } In this program, a large binary number is multiplied by itself, and then the result printed in bases 2, 10, and 16. The output of the program is: product in base-2 = 111111111111111111111111111110000000000000000000 000000000001 product in base-10 = 1152921502459363329 product in base-16 = fffffff80000001 A final issue in working with bases concerns the conversion of individual digits to or from an integer value. For example, if you have the digit 'e' in base-16, what is the numeric value of this digit? Or if you have the value 29 in base-36, what is the corresponding digit? There are a couple of methods in the Character class that you can use to perform these conversions. Let's look at an example: public class BaseDemo5 { public static void main(String args[]) { System.out.println( "value of \'e\' in base-16 = " + Character.digit('e', 16)); System.out.println( "digit for 29 in base-36 = " + Character.forDigit(29, 36)); } } When you run this program, the result is: value of 'e' in base-16 = 14 digit for 29 in base-36 = t So the number "e" in base-16 is equivalent to decimal 14, and the digit "t" in base-36 has the value 29. Using these methods is cleaner than trying to come up with your own conversion scheme. For more information about working with number bases, see Section 11.1.5, The Integer Wrappers, in "The Java(tm) Programming Language Third Edition" by Arnold, Gosling, and Holmes http://java.sun.com/docs/books/javaprog/thirdedition/. . . . . . . . . . . . . . . . . . . . . . . . IMPORTANT: Please read our Terms of Use and Privacy policies: http://www.sun.com/share/text/termsofuse.html http://www.sun.com/privacy/ * FEEDBACK Comments? Send your feedback on the JDC Tech Tips to: jdc-webmaster@sun.com * SUBSCRIBE/UNSUBSCRIBE - To subscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), choose the newsletters you want to subscribe to and click "Update". - To unsubscribe, go to the subscriptions page, (http://developer.java.sun.com/subscription/), uncheck the appropriate checkbox, and click "Update". - To use our one-click unsubscribe facility, see the link at the end of this email: - ARCHIVES You'll find the JDC Tech Tips archives at: http://java.sun.com/jdc/TechTips/index.html - COPYRIGHT Copyright 2001 Sun Microsystems, Inc. All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA. This document is protected by copyright. For more information, see: http://java.sun.com/jdc/copyright.html This issue of the JDC Tech Tips is written by Glen McCluskey. JDC Tech Tips December 4, 2001 Sun, Sun Microsystems, Java, and Java Developer Connection are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. To use our one-click unsubscribe facility, select the following URL: http://sunmail.sun.com/unsubscribe?61366481106493798