We have this code in many places where we swap integers if one value is higher than the other. Is there a way to re-factor this code, so it can be re-used?
int numerator2 = <some random number>;
int denominator2 = <some random number>;
if (numerator2 > denominator2)开发者_如何学编程 {
int temp = denominator2;
denominator2 = numerator2;
numerator2 = temp;
}
What your question boils down to is that you want a neat and reusable way to swap swap the values of a pair of bare variables. (I know you want to do this conditionally, but it is easier to explain for the unconditional case.)
Unfortunately, there is no way to do this in Java. The various programming language mechanisms that hypothetically could be used to do this are not available in Java. Here's a summary:
In some languages, you would do this using call by reference (e.g. FORTRAN) or INOUT parameter passing (e.g. ObjectiveC):
int a = 1; int b = 2; swap(a, b);
In some languages you can simulate call by reference by passing addresses (e.g. C and C++):
int a = 1; int b = 2; swap(&a, &b);
In some languages, there is a tuple assignment statement (e.g. Perl):
int a = 1; int b = 2; a, b = {b, a}; // or ... a, b = swap(b, a); // where swap returns an explicit or implicit tuple.
In some languages, procedures / methods can return multiple results and there is a special syntax to assign individual results to a different variable (e.g. Mesa ... and I'm sure there are less obscure examples):
int a = 1; int b = 2; a, b = swap(b, a);
Unfortunately, none of these mechanisms are available in Java. The best you can do is use some kind of mutable wrapper class instead of bare primitive types; e.g.
IntHolder a = new IntHolder(1);
IntHolder b = new IntHolder(2);
swap(a, b);
FOLLOWUP
One could use existing types like AtomicType
or Apache Commons' MutableInteger
as the wrapper class. I'd recommend the latter since it is marginally faster. Besides, using AtomicType
instances doesn't mean you can implement the swap
method atomically.
Create a class containing the two numbers as member variables. It can accept these in the constructor.
Then create a method on that class that returns a new instance of the same class with the members swapped if they need to be.
Won't the primitive types be the fastest way? Primitives are created on the stack and why engender objects?
A short version of @Emil's answer is
public static void swap(AtomicInteger i,AtomicInteger j) {
j.set(i.getAndSet(j.get()));
}
However, when dealing with a lot of data often arrays, Collections or Objects are used. In these situations you don't need an additional object just to swap values.
You can use an AtomicInteger or you can write your own MutableInteger
instead of using primitive int
.
Code:
void swap(AtomicInteger i,AtomicInteger j){
int tmp=i.get();
i.set(j.get());
j.set(tmp);
}
You can use AtomicInteger, or any user created custom wrapper object that will hold the int
value. Then you can write a swap
method.
I'd suggest sticking with the primitive version.
Reasons:
- Better performance by avoiding wrappers
- It's such a common idiom that you can mentally parse the swap code easily
- Saving 30 characters or so of typing does not justify IMHO adding an extra layer of abstraction. If you include conversion to wrapper types you possibly haven't even saved any typing at all.
- You can easily write the swap in one line if you are worried about vertical space
e.g.
if (numerator2 > denominator2) {
int t = denominator2; denominator2 = numerator2; numerator2 = t;
}
If you like fun hacks, here is also a way of doing it in a single expression by exploiting the order of operations:
numerator2= denominator2+ (0&(denominator2=numerator2));
Of course this is not really recommended if you care about readability/maintenance :-)
精彩评论