В настоящее время я работаю над диссертацией бакалавра о том, как написать эффективный Java-код. Следующие четыре фрагмента кода являются частью теста JMH, который будет выполнять каждый метод по 1 миллиону раз каждый.Как Java определяет, какой оператор в математическом выражении должен быть (un) в штучной упаковке?
public final static int primitiveOnly(int dummy, int add1, int add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
public final static int primitiveToWrapper(int dummy, int add1, Integer add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
public final static int wrapperToPrimitive(Integer dummy, Integer add1, int add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
public final static Integer wrapperToWrapper(Integer dummy, Integer add1, Integer add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
Результаты для этого четырех методов:
- primitiveOnly: 1,7 мс/операции
- primitiveToWrapper: 2.2 мс/операция
- wrapperToPrimitive: 47,5 мс/операции
- wrapperToWrapper: 48,2 мс/операция
Причиной такого поведения было бы то, что во время операции в primitiveToWrapper значение Integer просто должно быть unboxed, где в операции в wrapperToPrimitive должен быть установлен первый операнд в Integer, что приводит к дорогостоящему созданию объекта.
Есть ли определенная причина, по которой Java ведет себя так? Я прочитал The Java Language Specification, но не смог найти ответ на этот вопрос.
UPDATE:
Для решения точки относительно возвращаемых значений (спасибо Phil Anderson) я обновил свой код. Кроме того, я изменил все переменные Integer в классе тестов на int. Это новая версия:
public final static int primitiveOnly(int dummy, int add1, int add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
public final static int primitiveToWrapperIntDummy(int dummy, int add1, Integer add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
public final static Integer primitiveToWrapperIntegerDummy(Integer dummy, int add1, Integer add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
public final static int wrapperToPrimitiveIntDummy(int dummy, Integer add1, int add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
public final static Integer wrapperToPrimitiveIntegerDummy(Integer dummy, Integer add1, int add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
public final static int wrapperToWrapperIntDummy(int dummy, Integer add1, Integer add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
public final static Integer wrapperToWrapperIntegerDummy(Integer dummy, Integer add1, Integer add2) {
for(int i = 0; i < 10; i++) {
dummy += (add1 + add2);
}
return dummy;
}
Результаты в среднем 10 итераций (1 итерация = 1 миллион выполнений каждого метода выше).
- primitiveOnly: 0,783
- primitiveToWrapper (интермедиат фиктивный): 0,735
- primitiveToWrapper (целое число фиктивный): 24,999
- WrapperToPrimitive (интермедиат фиктивный): 0,709
- WrapperToPrimitive (целое число фиктивный): 26,782
- WrapperToWrapper (int dummy): 0.764
- WrapperToWrapper (Integer dummy): 27.301
Окончательные результаты теперь более интуитивно понятны. Спасибо всем за то, что помогли мне.
Весь эталон содержит в общей сложности 4 метода для каждой возможной комбинации int и Integer. Я отредактирую его. – whatTheFox
Обратите внимание, что даже с JMH результаты должны быть взяты с солью. Из-за размера фиксированной петли и «фиктивности» операций вы почти никогда не знаете, что на самом деле делает JIT. – Marco13