Чи є у Java змінні типи для Integer, Float, Double, Long?


81

Я потрапив у ситуацію, коли хочу використовувати змінні версії таких речей, як Integer. Чи повинен я використовувати ці класи (нижче), чи Java щось вбудовано?

http://www.java2s.com/Code/Java/Data-Type/Amutableintwrapper.htm


8
Питання в тому, чому ви хочете це зробити?
helpermethod

2
У деяких випадках (наприклад, гра, зберігання шматка їжі з nкалоріями, яку можна виснажити / додати), може бути краще використовувати клас, названий після використання, (наприклад class FoodItem { int calories; }, тому що це зрозуміліше, а методи можуть за потреби буде додано пізніше.
GKFX

7
Лямбди Java 8 працюють лише з фактично кінцевими змінними. Щоб обійти це обмеження, потрібен змінний int.
Олексій

Вам може знадобитися лічильник, який потрібно передавати між методами. Передача an intне працює, ніби його збільшують в одному методі, тоді значення не відображається в іншому методі.
Адам Берлі,

Відповіді:


51

Ні, у Java їх немає вбудованих. І це не просто так. Використання змінних типів небезпечно, оскільки ними легко скористатися. Крім того, це дуже просто реалізувати. Наприклад, commons-lang має MutableInt.


5
Я припускаю, що Java-розробник хотів, щоб Integer "поводився" як int, тобто ... коли у вас є посилання на нього, воно ніколи не змінюється (уникайте плутанини). Але.. мені все ще здається дивним, що у мене немає якось
змінної

35
"Використання змінних типів небезпечно, оскільки ними легко скористатися." Більшість речей можна зловживати. Існують незмінні типи для випадків, коли безпека важлива, хоча їх можна змінити шляхом роздумів. Якщо ці випадки заважають, немає жодної причини заважати людям використовувати змінні типи, коли вони в них потребують.
GKFX

2
Краще кажучи, незмінні типи створюють менше плутанини, наприклад, на картах і наборах. Якби у вас був змінний Integer і змінився його значення там, де він служив ключем, це зіпсувало б колекцію. Однак, якщо вам потрібна якась змінна реалізація Integer, немає нічого простішого, ніж створення класу зі значенням int всередині. І там ви можете проявити творчі здібності - зробіть це, наприклад, Counter або Countdown, а не просто інтерфейс, який дозволяє майже все. Дайте йому деяку логіку (якщо ви не розробляєте в Java EE, яка працює знизу).
Vlasec

Безумовно, давнє запитання, але, сподіваємось, хтось може відповісти, ЯК їх можна зловживати. Що такого небезпечного в їх використанні?
Пухнастий робот

@ user1175807 Як зауважив Vlasec, якщо ви випадково зміните змінну, яку ви використали десь ще, це призведе до дивних помилок. Ще гірше, припустимо, ви пишете програму, яка працює разом із кодом клієнта. Вам потрібно реалізувати метод, який має параметр змінного типу Integer. Тепер, якщо ви зміните змінне ціле число з будь-якої причини, воно також буде змінено в програмі клієнта, що є абсолютно несподіваним, і спричинить важкі помилки.
GregT

90

Ви завжди можете обернути значення в масив, наприклад, int[] mutable = {1};якщо включення коду для змінного класу обгортки занадто громіздке.


30
Розумна, помилка потворна, як гріх.
gvlasov

2
це дуже розумно і майже не займає місця. плюс уникає синхронізації, виконаної за допомогою AtomicInt.
CompEng88

53

Оскільки JDK 1.5 тепер має java java.util.concurrent.atomic.AtomicInteger

Це ціле число, що безпечно змінюється, приклад використання:

final AtomicInteger value = new AtomicInteger(0);

потім пізніше:

value.incrementAndGet();

13
Ця безпека теадів пов'язана із продуктивністю, яка у багатьох випадках не потрібна. Наприклад, звичайним випадком використання для мене є збільшення лічильника, зафіксованого лямбда. Використання атома - надмірне.
Мінас Міна,

12

Ось невеликий клас, який я створив для змінного цілого числа:

public class MutableInteger {
    private int value;
    public MutableInteger(int value) {
        this.value = value;
    }
    public void set(int value) {
        this.value = value;
    }
    public int intValue() {
        return value;
    }
}

Ви можете легко поширити це на будь-який інший примітив. Звичайно, як і всі інші кажуть, ви повинні використовувати його обережно.


1
IMHO - найкращий варіант - він не дає хибних підказок про паралельність, як це робить використання атомного інтержера. І масив, справді я ніколи не зробив би такого поганого у своєму коді ..;)
Snicolas

Може бути гарною ідеєю , щоб забезпечити єдиний універсальний клас обгортку замість так ви не до кінця з MutableInteger, MutableDouble, і MutableStringт.д. , але замість того, щоб мати Mutable<Integer>, Mutable<Double>... Накладні пам'яті (використання Integerбільш intзазвичай не потрапляють в розрахунок. Але ви отримуєте єдиний, готовий до використання клас, який може впоратись з більшістю випадків (якщо ви хочете, щоб ваше ціле число було порівнянним або подібним, все одно вам потрібно підклас).
Qw3ry

Може бути гарною ідеєю зробити так, щоб він подовжував число .
Stijn de Witt

7

Ви можете використовувати nnnn [] як змінний об'єкт для будь-якого примітивного типу, як пропонує @Alexandre, у Java також є AtomicInteger та AtomicLong.

IMHO int, як правило, кращий вибір, ніж Integer, і його можна змінювати.

Чи можете ви отримати більш детальну інформацію про те, навіщо вам потрібен багаторазовий об’єкт, можливо, існує інший спосіб досягти того самого.


7
intзавжди змінюється, якщо тільки це також не булоfinal
Пітер Лорі

18
Неправда казати, що примітивний тип є змінним . Його можна змінити, але так само може змінити кожен нефінальний об’єкт, якщо ви просто вказуєте на новий об’єкт. Наприклад, Integer a = 4;тоді a = 5;дійсний код, але Integerйого не можна змінити.
mjaggard

Я згоден, що Integerекземпляри не можна змінювати, навіть якщо посилання на них є, але це інший тип.
Пітер Лорі

Хіба це не хороший спосіб мати посилальний параметр int? Наприклад, функція, яка повертає пагінований Список елементів (з бази даних), але також загальну кількість записів. У такому випадку AtomicInteger або MutableInteger видаються корисними. Звичайно, іншим способом було б мати властивість getTotalRecords замість того, щоб повертати його тим самим методом.
msanjay

1
intне змінюється, тому що якщо ви передасте його методу, метод не зможе змінити своє значення і відобразити нове значення у виклику методу
Адам Берлі

5

AtomicIntegerвже згадувалося. Змінювані Doubles можна емулювати AtomicReference<Double>. Вже згадані попередження застосовуються, і це поганий стиль, але іноді у вас є такий код

double sum=0
for (Data data:someListGenerator())
  sum+=data.getValue()

і хочете його переформатувати у функціональному стилі Java 8. Якщо код слідує цьому шаблону, але додає йому значної складності, може бути найбільш розумним перетворенням

AtomicReference<Double> sumref=new AtomicReference<>(0d);
someStreamGenerator().forEach(data->
  sumref.set(sumref.get().doubleValue()+data.getValue()));
double sum=sumref.get().doubleValue();

Звичайно, це принаймні сумнівний стиль. Але я неодноразово потрапляв у ситуацію із скрученою петлею над ResultSetобчисленням і частково накопичуючи з неї три різні відомості. Це ускладнює перетворення коду у належний функціональний стиль. Перетворення кумулятивних частин за вищенаведеною схемою здалося мені розумним компромісом між чистим кодом та спрощеним рефакторингом.


Вам слід реально подумати над своїм формулюванням: Навіть якщо ви використовуєте лямбда, ваш приклад не працює , оскільки це забороняє побічні ефекти. Якщо ви дійсно написати це функціональний, вам не потрібно mutables: someStreamGenerator().mapToDouble(Data::getValue).sum(). Навіть для накопичення трьох різних відомостей існує функціональний спосіб, використовуючи Stream.reduceабо Stream.collect. Я не бачу причин переробляти кожен цикл на функціональний фрагмент коду, але якщо ви хочете піти таким шляхом, вам слід пройти його до кінця.
Тобіас Лієфке,

Як я вже писав: Це не належний стиль, і для кожного нового коду він не повинен використовуватися. Але при рефакторингу 400 000+ рядків коду, який еволюціонував протягом 15+ років, ви знайдете конструкції, де правильне перезапис у справді функціональні конструкції може бути надзвичайно складним. Тоді перепис на такий гібридний стиль може бути розумним компромісом, оскільки ви вирівняєте хоча б базову структуру. forі foreachможуть бути частинами складних фреймворків, які функціонально переписуються, тому вам доведеться якось вирівняти решту коду навколо них.
Дірк Хілбрехт,

Ви плутаєте лямбди та функціональне програмування. У вашому прикладі ви не переписали його як "функціональний". І який сенс переписувати все за допомогою лямбда, коли ви втрачаєте читабельність, але не отримуєте переваг функціонального програмування? Чому взагалі потрібно намагатися позбутися кожного циклу в складних рамках за допомогою таких гібридів?
Тобіас Ліефке,

У вашому коді 1000 місць із певною ідіомою. Ідіомою керується бібліотека або будь-яка інша глобальна структура. Ви замінюєте цю глобальну структуру новою на основі функціонального підходу та лямбда. 998 з 1000 місць можна чисто перетворити у функціональний стиль. Решта 2 надзвичайно важко перетворити належним чином. У таких випадках я завжди мандрую перетворення нового стилю за допомогою таких гібридних конструкцій. Тільки тоді ви можете позбутися будь-яких старих глобальних структур, які були в коді. Хоча і не ідеальний, загальна якість коду зростає.
Дірк Хілбрехт,

2

Ви можете імпортувати пакет org.omg.CORBA (або просто потрібний вам клас), і в ньому ви можете використовувати класи Holder.

Наприклад, у ньому є "IntHolder", де поле, де воно зберігає ціле число, є загальнодоступним, що надає доступ до його модифікації.

public static void triple(IntHolder x){
    x.value = 3 * x.value;
}

IntHolder mutableInt = new IntHolder(10);
triple(mutableInt);     
System.out.println(mutableInt.value);

У ньому також є "LongHolder" та "DoubleHolder" та безліч інших, якими ви можете скористатися. Використовуйте з обережністю.

Ось API для нього: https://docs.oracle.com/javase/7/docs/api/org/omg/CORBA/package-summary.html


2
Хоча це дуже розумний спосіб вирішити проблему, оскільки Java9 з’являється, ви, мабуть, не хочете використовувати це - це імпортувало б цілий модуль CORBA лише для власника int.
Агостон Горват,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.