I'm getting a Long value as a result of some method. Now, when I want to add 1 to that number, the compiler warns me about the value being boxed / unboxed to perform the sum.
public Long getLongValue() {return new Long(5L);}
// ...
Long val = getLongValue();
val++; // Warning: The expression of type Long is unboxed into long
val = val + 1L; // Warning: The expression of type Long is unboxed into long
Since Long class doesn't seem to have an "add" method, is there any way to avoid this autoboxing behaviour?
(Note: I know I can just #suppressWarnings or manually box / unbox the values instead of using the Autoboxing feature. What I'm trying to achieve is to totally avoid boxing / unboxing)
Since, as you noted, Long does not have have any add() method (or any other arithmetic methods) you have no choice but to unbox (manually or automatically) it to do calculations with it and then box (manually or automatically) the result.
It will likely be more performant if you unbox before any calculations, do all the calculations, and rebox at the end rather than boxing and unboxing during each calculation (and sub-calculation).
Do it this way
long val = getLongValue();
val++;
val = val + 1L;
it's more efficient and there will be no warnings
Related
I'm using the Java 8 Stream API like this:
private Function<Long, Float> process; // Intermediate step (& types)
private long getWeekFrequency(final ScheduleWeek week) {
return week.doStreamStuff().count(); // Stream<>.count() returns long
}
#Override
public float analyse(final Schedule sample) {
return (float) sample // cast back to float
.getWeeks()
.stream()
.mapToLong(this::getWeekFrequency) // object to long
.mapToDouble(process::apply) // widen float to double
.sum();
}
#Override
public String explain(final Schedule sample) {
return sample
.getWeeks()
.stream()
.map(this::getWeekFrequency) // change stream type?
.map(String::valueOf)
.collect(Collectors.joining(", "));
}
Questions
I assume there is overhead when changing between object/primitive Stream types... How does this compare to the boxing overhead if I stick to Stream<>?
What about if I later change back?
Concretely:
In analyst, should I use .map(...).mapToDouble(...)?
In explain, should I use .mapToLong(...).mapToObj(...)?
So let's break this down:
.mapToLong(this::getWeekFrequency)
gives you a primitive long.
.mapToDouble(process::apply)
This primitive long is boxed to a Long because the process function requires it. process returns a Float which is mapped to a primitive double (via Float.doubleValue()).
These are summed and the sum is cast to a primitive float (narrowing, but you say safe) which is then returned.
So how can we get rid of some of the autoboxing? We want a FunctionalInterface which exactly matches our process function, without using any box classes. There isn't one we can use off-the-shelf, but we can easily define it like so:
#FunctionalInterface
public interface LongToFloatFunction
{
float apply(long l);
}
Then we change our declaration to:
private LongToFloatFunction process;
and keep everything else the same which will prevent any auto-boxing. The primitive float returned by the function will be automatically widened to a primitive double.
Well it seems from your definition that process looks sort of like this:
double process (long value) {
// do something
}
As such if you do : map(...).mapToDouble you would be creating an Object of type Long every time, only to unbox it immediately after to be used in process. I would leave the code as it is to use the primitive implementation that would avoid this.
The second one uses String#valueOf. In case of long, String.valueOf(l) will be called, which works on the primitive: Long.toString(l).
In case of Object the same method will be called, but with the caveat that first boxing happens. So, I would change it to mapToLong
I can implicitly conver int to long and long to Long. Why is it not possible to implicitly convert int to Long? Why can't Java do the implicit conversion on the last line of the example?
int i = 10; //OK
long primitiveLong = i; //OK
Long boxedLong = primitiveLong; //OK
boxedLong = i; //Type mismatch: cannot convert from int to Long
Long and Integer are objects. Boxing/unboxing only works with primitives.
Doing Long boxedLong = i is like Long boxedLong = new Integer(10), that's a no no !
Plus, remember that there is no inheritance between Long and Integer so even Integer i = new Long() is not valid
Boxing only works with primitives. That's why.
Try this: Long.valueOf(int);
Documentation
the biggest difference I see between long and Long in this context is that Long may be null. If there's a possibility you might have missing values the Long object will be helpful as the null can indicate missing values. If you're using primitives you'll have to use some special value to indicate missing, which is probably going to be a mess. Speed or size is not likely to be an issue unless you're planning on making an array of a million of these things and then serializing. (When to use Long vs long in java?)
In truth, there is no practical reason. Except that int is a primitive, long is a primitive, but Long is not.
I suggest you use Long.valueOf()
So like this:
Long longValue = Long.valueOf(InsertIntHere);
Can someone please explain why you would ever use widening or narrowing conversion? I've read a lot about these but no one ever gives me a practical example. Thanks!
(Java) Widening and Narrowing Conversions have to do with converting between related Types. Take, for example, the relationship between an abstract (super) class and its (child) subclass; let's use the java.lang.Number Class (abstract) and a direct subclass Integer. Here we have:
(superclass) Number
__________/\__________
/ | | \
(concrete subclasses) Integer Long Float Double
Widening Conversion: occurs if we take a specific type (subclass) and attempt to assign it to a less specific type (superclass).
Integer i = new Integer(8);
Number n = i; // this is widening conversion; no need to cast
Narrowing Conversion: occurs when we take a less specific type (superclass) and attempt to assign it to a more specific type (subclass), which requires explicit casting.
Number n = new Integer(5); // again, widening conversion
Integer i = (Integer) n; // narrowing; here we explicitly cast down to the type we want - in this case an Integer
There are certain issues that you need to be aware of such as ClassCastExceptions:
Integer i = new Integer(5);
Double d = new Double(13.3);
Number n;
n = i; // widening conversion - OK
n = d; // also widening conversion - OK
i = (Integer) d; // cannot cast from Double to Integer - ERROR
// remember, current n = d (a Double type value)
i = (Integer) n; // narrowing conversion; appears OK, but will throw ClassCastException at runtime - ERROR
One way to handle this is to use an if statement with the instanceof keyword:
if( n instanceof Integer) {
i = (Integer) n;
}
Why would you want to use this? Let's say you are making a hierarchy of personnel for some program and you have a generic superclass called "Person" which takes a first and last name as parameters, and subclasses "Student", "Teacher", "Secretary", etc.. Here you can initially create a generic person, and assign it (through inheritance) to, say, a Student which would have an additional variable field for studenID set in it's constructor. You can use a single method that takes the more generic (wider) type as a parameter and handle all subclasses of that type as well:
public static void main(String[] args) {
Person p = new Student("John", "Smith", 12345);
printInfo(p);
}
// this method takes the wider Person type as a parameter, though we can send it a narrower type such as Student if we want
public static void printInfo(Person p) {
System.out.println("First: " + p.getFirstName());
System.out.println("Last: " + p.getLastName());
if (p instanceof Student) {
System.out.println( (Student)p).getStudentID() ); // we cast p to Student with Narrow Conversion which allows us to call the getStudentID() method; only after ensuring the p is an instance of Student
}
}
I realize this may not be the ideal way to handle things, but for the sake of demonstration I thought it served to show some of the possibilities.
If some code returns an int containing a true/false value, you could shorten it yourself to a bool which is what it properly represents.
You can also do the opposite.
You can widen a char to int to do some comparisons with ascii values.
You can take an instance of Dog and widen it to IAnimal to pass it to a function.
You can shorten a IAnimal to Dog when you know the type of animal in a List<IAnimal> in a factory or elsewhere for whatever reason.
You use implicit conversions to do math with numerical values of different types. For example, if now() returns a timestamp in seconds as a long:
long t = now()
long nextMinute = t + 60
you have done an implicit widening conversion of 60 (an int) to a long so you can add it to t. Being able to do such conversions makes math much easier to code.
One canonical example of widening and narrowing conversions is how certain file I/O libraries work. Often, a file processing library will have a function / method that reads a single character from a file. If there is a character to read, the function should return that character, and if no characters are left it should return a sentinel value EOF to signal this.
Because any character can appear in a file, typically the function / method would have this signature:
int readCharacter();
Here, the function returns an int that holds a char value if a character was read and which holds EOF as a sentinel otherwise. EOF is typically chosen as an integer that is too big to hold in a char. That way, you can do this:
while (true) {
int ch = readCharacter();
if (ch == EOF) break;
char actualCharValue = (char) ch;
/* process actualCharValue here */
}
Hope this helps!
Take this...
Conversion - Specialized -> Generalized, then it is known as Widening, when you are becoming more general.
Such as Surgeon -> Medico. In this case, you do not need a casting. Because, a surgeon is a Medico by default. So, it is natural that a surgeon can perform all those stuffs that a Medico can do.
While on the other hand,
Conversion - Generalized -> Specialized, then it is known as narrowing, when you are becoming more specialized.
Such as Medico -> Surgeon. Well, in this case, you must have to add casting. Because, a medico can be a surgeon or a physician or a nurse. Think of it, if you ask a nurse to operate on you...
Horrible, right ???
Hope you got the idea.
With autounboxing, this statement will automatically work:
int myPrimitive = (Integer) doIt();
But if I want to explicitly convert from an Integer to an int here in a single line, where do I have to put the parentheses?
You could do this :
int myPrimitive = (int) (Integer) doIt();
But as you said, auto-unboxing will get that for you.
A bad example to show that chain casts work (don't ever use this code) :
Map notReallyAMap = (Map) (Object) new String();
The thing with chain casts, is that wherever you use it, either the cast is legit, and you can remove intermediaries; or the cast will simply cause a ClassCastException. So you should never use it.
Either the compiler unboxes the Integer for you, or you do it yourself - this cannot be avoided.
So you need to either do
int myPrimitive = ((Integer) doIt()).intValue();
or more simply, change doIt() to return an int since you seem to want to deal with ints rather than (null-able) Integers.
Running this code:
public class SomeSet {
public static void main(String[] args) {
Set<Short> s = new HashSet<Short>();
for (short i = 0; i < 100; i++) {
s.add(i);
s.remove(i - 1);
}
System.out.println(s.size());
}
}
Will print the value 100.
Why does it print this value?
s.remove(i - 1);
The line above will attempt to remove Integer objects from the set, because all integer calculations in Java have int (or long) results. Since the set contains Short objects, the remove() method will not have any effect.
This (and similar problems) is the main reason why you should almost never use short (and, more so, Short). Using a Set implementation to contain autoboxed numbers incurs a massive (easily 1000%) overhead, so it's rather pointless to try and save space by using Short rather than Integer.
The problem is that remove(i-1) calls the remove method with an Integer object, since i-1 is of type int (which gets auto-boxed into an Integer).
To make sure that you call remove with a Short object use this:
s.remove((short) (i - 1));
The type of i - 1 is int, so it gets autoboxed to an Integer.
Normally you'd expect a generic collection to prevent you performing operations which have arguments of the wrong type, but the interface to Set<E> is a bit loose.
Because the remove method of Set<E> takes an Object rather than an E, the compiler doesn't warn you that you're removing a different type to what the set contains.
To force it to be a Short, cast the numeric value to (short). (casting to (Short) isn't allowed, and you'd have to cast the numeric value to use Short.valueOf)
Note that the add method is generically typed boolean add(E o) so in your case of Set the add method will take a short, whereas the remove method is not generically typed boolean remove(Object o) so i - 1 autoboxes to a Integer. For any value of i new Short(i).equals(new Integer(i)) will always be false.
Note that if you try s.add(i - 1); you will get a compiler error because i - 1 becomes an instance of Integer and the types Integer and Short do not match.