Should primitive types or non-primitive types be preferred in Java interfaces?
(I thought I once read something about this in a book, but now I'm not sure where to find it. If this question reminds you of some material that you've read, please post a reference!)
What are the pros and the cons开发者_如何转开发 of primitives in interfaces?
In other words, is one of these preferable to the other and why? Perhaps one is preferable to the other in certain contexts?
public interface Foo {
int getBar();
}
or
public interface Foo {
Integer getBar();
}
Similarly:
public interface Boz {
void someOperation(int parameter);
}
or
public interface Boz {
void someOperation(Integer parameter);
}
Obviously there's the issue of having to deal with null
s in the non-primitive case, but are there deeper concerns?
Primitive types should be used for efficiency and simplicity unless there is a specific reason to use the object type (e.g., you need null
). Using object types can lead to various subtle errors, such as mistakenly comparing if two references are to the same object, instead of having the same value. Observe how Java's own libraries use the primitive types except for containers, which take Object
s.
I would say that for the primitives, there is usually little reason to use the primitive wrapper as a return type. One argument is simply the memory requirements. With a primitive return value you only need the X bytes for the return value vs the wrapper where you have the object overhead. The only place where you might save is the cached value for things such as Integer.valueOf(1), but for example with integer this only works for values -128 -> 127.
While lexicore does make a valid point with using null as a special case return value, there are many times where you can do the same with the primitve value (such as something in the API that says "Integer.MIN_VALUE is returned when the result can not be caluclated". Which is viable in many cases for all of the primitives except boolean.
There is also always the option of exceptions as one could argue that an interface should always be well defined for all possible inputs and that an input that would cause a return value to be undetermined is the definition of an exceptional case (and as such perhaps a good case for an IllegalArgumentException).
A final (adimittedly much less elegeant) solution is to add some sort of state checking method to the interface that can be tested after a call to the method that may not execute as desired:
boolean b = (interface).doFoo();
if((interface).wasError()){
//doFoo did not complete normally
}else{
//do something fooish
}
where wasError can clear itself automatically in the style of Thread's interrupt flag (note that this approach will be error prone in multi threaded code).
Except for the rare cases where primitives are troublesome (I've had some "nice" experience with CORBA), I'd suggest using primitives.
I'm thinking of stuff like this too:
Suppose that we have this type:
public interface Foo {
int getID();
}
Then, for whatever reason, an ID type is introduced:
public interface Foo {
FooID getID();
}
Now, suppose that some client was written before the change, and the client contains code like this:
if (A.getID() == B.getID()) {
someBehavior();
}
Where A
and B
are Foos
.
This code would be broken after the change because the primitive equality comparison (==
) between the int
s, which was ok before the change, is now incorrectly comparing reference values rather than invoking equals(Object)
on the identifiers.
Had getID()
produced an Integer
from the start, the correct client code would have been (ok, the correct client code might have been this. Boxing conversions would have been applied with ==
so that would have worked too):
if (A.getID().equals(B.getID())) {
someBehavior();
}
Which is still correct after the software evolved.
Had the change been "the reverse," in other words, had getID()
originally produced some FooID
type, then had it been changed to produce int
, the compiler would have complained about calling equals(Object)
on a primitive and the client code would have been corrected.
There seems to be some feeling of "future proofing" with the non-primitive type. Agree? Disagree?
Use primitives. Auto-boxing/-unboxing will cast your int
s to Integer
s and so on. Primitives are also allocated on the stack, not the heap. By using wrapper classes you are using more memory and incurring more overhead; why would you want to do that?
Yes , The major use you can see is , when you transfer the object over network. ** The use of serialization. **
精彩评论