Java Cookbook, Second Edition
Problem
You need to pass a number like an int into a routine and get back the routine's updated version of that value in addition to the routine's return value. This often comes up in working through strings; the routine may need to return a boolean, say, or the number of characters transferred, but also needs to increment an integer array or string index in the calling class. It is also useful in constructors, which can't return a value but may need to indicate that they have "consumed" or processed a certain number of characters from within a string, such as when the string will be further processed in a subsequent call. Solution
Use a specialized class such as the one presented here. Discussion
The Integer class is one of Java's predefined Number subclasses, mentioned in the Introduction to Chapter 5. It serves as a wrapper for an int value and also has static methods for parsing and formatting integers. It's fine as it is, but you may want something simpler. Here is a class I wrote, called MutableInteger , that is like an Integer but specialized by omitting the overhead of Number and providing only the set, get, and incr operations, the latter overloaded to provide a no-argument version that performs the increment (++) operator on its value, and also a one-integer version that adds that increment into the value (analogous to the += operator). Since Java doesn't support operator overloading, the calling class has to call these methods instead of invoking the operations syntactically, as you would on an int. For applications that need this functionality, the advantages outweigh this minor syntactic restriction. First, let's look at an example of how it might be used. Assume you need to call a scanner function called, say, parse( ) and get back both a Boolean (indicating whether a value was found) and an integer value indicating where it was found: import com.darwinsys.util.*; /** Show use of MutableInteger to "pass back" a value in addition * to a function's return value. */ public class StringParse { /** This is the function that has a return value of true but * also "passes back" the offset into the String where a * value was found. Contrived example! */ public static boolean parse(String in, char lookFor, MutableInteger whereFound) { int i = in.indexOf(lookFor); if (i == -1) return false; // not found whereFound.setValue(i); // say where found return true; // say that it was found } public static void main(String[] args) { MutableInteger mi = new MutableInteger( ); String text = "Hello, World"; char c = 'W'; if (parse(text, c, mi)) { System.out.println("Character " + c + " found at offset " + mi + " in " + text); } else { System.out.println("Not found"); } } } Now many OO purists argue convincingly that you shouldn't do this, and that you can always rewrite it so there is only one return value. Either return and have the caller interpret a single value (in this case, return the offset in the return statement, and let the user know that -1 indicates not found), or define a trivial wrapper class containing both the integer and the Boolean. However, there is precedent in the standard API: this code is remarkably similar to how the ParsePosition class (see Recipe 6.5) is used. Anyway, this functionality is requested often enough that I feel justified in showing how to do it, accompanied by this disclaimer: try to avoid doing it this way in new code! Having said all that, here is the MutableInteger class: package com.darwinsys.lang; /** A MutableInteger is like an Integer but mutable, to avoid the * excess object creation involved in * c = new Integer(c.getInt( )+1) * which can get expensive if done a lot. * Not subclassed from Integer, since Integer is final (for performance :-)) */ public class MutableInteger { private int value = 0; public MutableInteger( ) { } public MutableInteger(int i) { value = i; } public void incr( ) { value++; } public void incr(int amt) { value += amt; } public void decr( ) { value--; } public void setValue(int i) { value = i; } public int getValue( ) { return value; } public String toString( ) { return Integer.toString(value); } public static String toString(int val) { return Integer.toString(val); } public static int parseInt(String str) { return Integer.parseInt(str); } } See Also
As mentioned, this use of MutableInteger could be replaced with ParsePosition. However, MutableInteger has other uses: it makes a fine in-memory counter in a servlet or other application. |