Сучасна диджитал-освіта для дітей — безоплатне заняття в GoITeens ×
Mazda CX 30
×

Java. Проблема с инициализацией переменной

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті

public static void main(String[] args) {

        int n = 100;
        double[] array = new double[n];
        for (int i = 0; i < array.length; i++) {
            array[i] = Math.random();
        }

        double max = array[0]; // Массив не должен быть пустым
        double min = array[0];
        double avg = 0;
        for (int i = 0; i < array.length; i++) {
            if(max < array[i])
                max = array[i];
            if(min > array[i])
                min = array[i];
            avg += array[i]/array.length;
        }

        System.out.println("max = " + max);
        System.out.println("min = " + min);
        System.out.println("avg = " + avg);
    }

Вот такое вот код,извините меня за дурость конечно,но не могли бы вы мне подсказать ,почему в третьей строчке,компилятор запрашивает инициализацию переменной " array",хотя она уже инициализирована.Еще раз извиняюсь,решил стать на путь Java разработчика....

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
public static void main(String[] args) {
         IntStream arr = new Random().ints(100);
        System.out.println("min = " + arr.min().getAsInt());
        System.out.println("max = " + arr.max().getAsInt());
        System.out.println("avg = " + arr.average().getAsDouble());
}

от тільки ваш код робить 3 проходи по колекції, а у топікстартера за один) єдине, що там змінити — це розрахунок avg, бо можна ділення зробити за циклом. А взагалі для навчання використання таких методів тільки шкодить навчанню, бо люди починають забагато надіятись на те, що все вже написано, можливо і так, але поки людина не розуміє, як воно працює під капотом, я би не радив давати такі поради

для 99.9% проектов лучше в таком случае 3 прохода в угоду удобства чтения кода.
А так да, скорее для фана коммент добавлен

public static void main(String[] args) {
        var stat = new Random().ints(100).summaryStatistics();
        System.out.println("min = " + stat.getMin());
        System.out.println("max = " + stat.getMax());
        System.out.println("avg = " + stat.getAverage());
}

min, max, average терминальные операции, не? После любого из них стрим уже будет закрыт. Ниже выше лучше версия.

Учебные версии в принципе не стоит оптимизировать по функционалу. Человека учат как делать, на основе примитивных операций. В боевом коде обработка данных уже не будет столь простой, равно как и сами данные.

В конце концов, есть те же самые Collections.min, Collections.max... и привет ручное написание компаратора в отдельный класс для данных твоего класса, вместо того чтобы наглядно всё показать в простеньком for each цикле.

С твоим кодом всё норм: ideone.com/KKkbXE
Ищи проблему в другом месте. Возможно, IDE что-то не то пытается собирать.

щаз окажется что компилится совсем другой проект

И вообще, он тебе ошибку даёт, или warning? С ворнингом как раз всё понятно: ты используешь примитивный тип, который не допускает null значений. Подкинь ему Double вместо double как тип массива, и этим упростишь реальный исполняемый код. В любом случае там будет Double, у Java давно уж нет примитивов (разве только в sun.misc.Unsafe, куда ты вряд ли полезешь за всю карьеру).

Что здесь немножко некошерно:
1) Ты не позволяешь компилятору оптимизировать код. Генеря массив от переменной, ты задерживаешь инициализацию до времени исполнения. Ничего особо проблемного, просто ты ещё и чтение кода человеком задерживаешь: ты не хочешь сразу вписать 100 в код (это было бы понятно с ходу), и ты не хочешь дать переменной правильное имя, и сказать const (это тоже понятно, что возможно в дальнейшем ты планируешь откуда-то брать эту переменную, например из аргумента командной строки).

2) Ты обращаешься к array[0], и сам пишешь, что он к тому времени должен быть. Но компилятор в этом не уверен ни разу, потому получай ворнинг. Как правильно:
Double min, max;
И уже в коде ты проверяешь, не null ли они. Почему так? Потому что размерность массива у тебя вынесена в переменную, а там вероятно и за пределы твоего кода. Прилетит 0 — получишь RuntimeException.

3) Сложение строки с числом. Тем более с Double. Как думаешь, сколько будет (1/3)*3? Учи мат.часть по работе с плавающей точкой, и запомни: ВСЕГДА нужно форматировать вывод, если не хочешь чтобы в реальных данных потом торчали краказяблы. Здесь соответственно тоже проверишь на null.

у Java давно уж нет примитивов

так стоп, а це як?

А отак. Все є об′єкти, і double породжується конструктором Double.

String то взагалі досить унікальний клас:
String aziat1 = «Ja kitaec»;
String aziat2 = «Ja kitaec»;
if(aziat1== aziat2) System.out.print («Та вони всі однакові!!!»);

Все є об′єкти, і double породжується конструктором Double.

www.youtube.com/watch?v=kxHkvnPc47I

String то взагалі досить унікальний клас:

че, открыл для себя стринг пул?

да ладно, не стоит себя так критиковать, у всех ошибки случаются. Зря ты на себя так

Ну зі стрінгами ясно, тут все ок.
Але з Double все одно не шарю.

у Java давно уж нет примитивов

- А з якої версії вже нема? Бо я на 8 пишу

Примітиви є в мові, але їх нема в самій JVM, притому дууже давно, значно довше за 8. Якщо цікаво, візьми reflect та подивися, що насправді чим є. Якщо не цікаво, просто знай, що примітиви є де-факто полями відповідних об′єктів. Інакше б це не дозволило з ними ефективно працювати самій JVM. Колись дуже давно ця наявність примітивних типів навіть створила серйозну проблему безпеки.

Зараз краще за все не використовувати примітиви зовсім, хіба що int в ітераторах, якщо так хочеться робити олдскульні цикли, які звично виглядають. Але для всього іншого — погодься, краще мати null там де ти забув дати значення чи допустив помилку (і NullPointerException відповідно), замість того щоб мати чесний 0 та пропустити помилку в дані.

Коли тобі насправді буде потрібен рефлект:
— коли ти робиш свою трансляцію даних, наприклад, хочеш щоб дані із одного формата із завданими полями — стали відповідними полями класа, і ти не хочеш все це переписувати щоразу.
— коли тобі треба міняти обмеження доступу до полів об′єкта, наприклад, зняти заборону запису даних в поле.
— коли тобі потрібно створювати клас прямо з коду.

Вивчати його до того вигоди особливої нема, десь половина програмістів на java ніколи з ним не матимуть справу й за 10 років досвіду. Але про наявність цієї технології варто знати, що замість геморойних get та set можна працювати із об′єктами через reflect.

Основна вигода — коли треба мати справу із класами, які створив не ти, але тобі аж ніяк не хочеться декомпилити та заново компилити сторонні бібліотеки. Особливо корпоративні. Наприклад, улюблена «фіча» корпоративних кодерів великих компаній — приховати інформацію про реально помилку, замінивши її на дибільний номер, який нічого не значить — і от тоді ти можеш влізти напряму в чужий код, і замінити поведінку лише одного метода так, щоб він працював як тобі треба. Або ж коли якесь поле прихованих опцій роблять приватним з «магічним» значенням, а тобі конче потрібно ним керувати.

Хм, цікаво.
Про рефлексію знав і пробував юзати на рівні аля «написати 1 POJO і просто подивитись, що ж вона вміє робити з ним».
Дякую за інфу!

Я так і сказав: рефлексія потрібна в досить небагатьох випадках. Але може бути дуууже корисною при написанні тестів.

Ну і вишенька на тортику — рефлексія вміє працювати з анотаціями, а це дозволяє творити досить цікавий синтаксичний цукор.

смешать в кучу рефлексию и примитивы это надо точно сидеть на чем-то забористом

Да не слушай ты его. Чувак, похоже, вообще не понимает о чем говорит

Якого *** тут відбувається? Це ти тіпа тролиш, шкодиш чи реально тупий?

double НЕ породжується конструктором Double.

Код 1:

public class A {
    public static void main(String[] args) {
        double x = 1.1;
        x += 10;
        System.out.println(x);
    }
}

Дає такий байткод:

Compiled from "A.java"
public class A {
  public A();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc2_w        #7                  // double 1.1d
       3: dstore_1
       4: dload_1
       5: ldc2_w        #9                  // double 10.0d
       8: dadd
       9: dstore_1
      10: getstatic     #11                 // Field java/lang/System.out:Ljava/io/PrintStream;
      13: dload_1
      14: invokevirtual #17                 // Method java/io/PrintStream.println:(D)V
      17: return
}
Нема ніякого виклику конструкторів Double. Нема!

Код 2:

public class A {
    public static void main(String[] args) {
        Double x = 1.1;
        x += 10;
        System.out.println(x);
    }
}
Дає такий байткод:
Compiled from "A.java"
public class A {
  public A();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc2_w        #7                  // double 1.1d
       3: invokestatic  #9                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
       6: astore_1
       7: aload_1
       8: invokevirtual #15                 // Method java/lang/Double.doubleValue:()D
      11: ldc2_w        #19                 // double 10.0d
      14: dadd
      15: invokestatic  #9                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
      18: astore_1
      19: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
      22: aload_1
      23: invokevirtual #27                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      26: return
}

Поясню що відбувається: для ініціалізації об’єкту Double примітивне значення 1.1 передається в Double.valueOf (а не конструктор). Потім з цього ж об’єкту викликається x.doubleValue() щоб перетворити в примітивне значення, потім до нього додається примітивна 10.0, потім це примітивне значення назад перетворюється в Double і зберігається в x.

Тут дофіга більше роботи.

Мало того, з точки зору компілятора:

        double x;
        Double X;
        System.out.println(x instanceof double);  // 1
        System.out.println(x instanceof Double);  // 2
        System.out.println(X instanceof double);  // 3
        System.out.println(X instanceof Double);  // 4
(1), (2), і (3) не мають сенсу. (1) і (3):
        System.out.println(x instanceof double);
                                        ^
  required: class or array
  found:    double
(2):
        System.out.println(x instanceof Double);
                           ^
  required: reference
  found:    double

Тобто тобі сам компілятор каже що x це не reference на об’єкт, а тупо примітив (double).

Може замість того щоб сіяти дезінформацію іди краще літкод порішай. На тобі промокод на −25%: LIBEDAY.

Ну тільки на літ-код і є надія, бо без нього тут щось дивне відбувається. Тут або:
1. Олексій ідіот і тоді літкод не нашкодить
2. це навмисний тролінг/дезінформація, тоді завдяки літкоду просто не буде створювати шуму
3. це ми всі ідіоти, а Олексій має якісь супер глибокі і унікальні знання внутрішностей і оптимізацій JVM, згідно якими JVM може там примітивні типи перетворювати в об’єкти.

От якась імовірність (3) є, але взагалі практично нереально мала:

примітиви є де-факто полями відповідних об′єктів

це неправда, які на*** поля в тих прикладах, що я приводив?

Або аналогічно він вважає що різниця між

for (int i = 0; i < 10; i ++) {
і
for (Integer i = 0; i < 10; i ++) {
всього лиш в тому, що
Буков больше.

що взагалі тривіально провіряється:

    public static void main(String[] args) {
        long sum = 0;
        for (Integer i = 0; i < 1000000000; i++) {
            sum += i;
        }
        System.out.println(sum);
    }
в 6+ раз повільніше за:
    public static void main(String[] args) {
        long sum = 0;
        for (int i = 0; i < 1000000000; i++) {
            sum += i;
        }
        System.out.println(sum);
    }

я надеюсь что он таки просто идиот. Хуже если это троллинг, т.к. начитаются джуны вот такого а потом на собесе ляпнут и останутся без офера. Желание сделать другим людям плохо это хуже чем быть просто идиотом

у Java давно уж нет примитивов
class Scratch {
    public static void main(String[] args) {
        final Foo foo = new Foo();
        for (Field field : foo.getClass().getDeclaredFields()) {
            System.out.println(field.getName() + " has type: " + field.getType());
        }
    }


    static class Foo {
        double a = 0.0;
        Double b = 0.0;
    }
}
Если примитивов нет, то почему результатом выполнения будет?
a has type: double
b has type: class java.lang.Double

И что это меняет. В JVM это всё равно объекты. Реализация примитивов полностью объектная, грубо говоря, это эмуляция.
А ещё в JVM нет массивов, надеюсь для тебя тоже не будет новостью, что массивы — полноценные объекты, с которыми можно делать вполне объектные чудеса на кшталт прототипирования новых классов на их основе, скажем, с ленивым поведением. Или добавлением статик-методов. А то и подменой классов (салют создателям JRebel)

Я правильно понял, что в использовании double нет никаких преимуществ ни по памяти, ни по скорости по сравнению с Double?

нет, неправильно. Чувак несет полнейшую чушь. Вопрос. Какая разница между этими двумя кусками кода:

 
 for (int i = 0; i < 10; i ++) {
            // do something
        }

и
 
for (Integer i = 0; i < 10; i ++) {
            // do something
        }

ясно. Модель организации памяти в JVM точно не твое, мы уже поняли. Заканчивай уже

Ни разницы. Конечно, теоретики «по учебнику» будут не согласны, но факт остаётся фактом: за переменной типа double стоит объект типа Double.

Чувак, реально, не порти людям прохождение собеседований. Ты говоришь глупости. Хоть бы почитал документацию что ли

Очень надеюсь, что мсье не относит себя к «теоретикам „по учебнику“». Предложу еще немного практики. Дано два класса

public class Primitive {
    public static void main(String[] args) {
        double[] array = new double[1000000];
        for (int i = 0; i < array.length; i++) {
            array[i] = 1.0 * i;
        }
        System.out.println("Ok");
    }
}

public class Reference {
    public static void main(String[] args) {
        Double[] array = new Double[1000000];
        for (int i = 0; i < array.length; i++) {
            array[i] = 1.0 * i;
        }
        System.out.println("Ok");
    }
}
И два вызова
java -Xmx16m -Xms16m Primitive.java
java -Xmx16m -Xms16m Reference.java

Вопрос: что произойдет в каждом из вызовов и почему?
Если jdk < 11, то запускать классы чуть по-другому надо. Но практик, думаю, разберется)

Слушай, ты хочешь чтоб никто из этих людей не прошел собеседование?

Вот здесь ты прав, на собесе нужно отвечать «по учебнику», потому что те кто спрашивает, зачастую сами не умеют, но учат. Перед собесом надо всегда повторять теорию, особенно практикам. Уже только по той причине, что теория и практика дают сильно разно звучащие ответы на один и тот же вопрос.

сами не умеют, но учат.

о, хорошо что ты о себе написал. Теперь мне все понятно зачем ты тут столько глупостей понаписывал

Проверь написание. Может где русскую а вставил или ещё какой примитивный косяк. По написанию всё правильно. Действительно, перечитай сообщение ошибки, или сюда кинь.

Кстати, мне вассаби предлагают переписать на j2ee. Что скажешь?

Если у тебя куча время-денег, можешь писать что хочешь. Если мало — ищи слабые места и начинай с них. В твоём случае слабым местом является гуманитарная часть продукта, то есть ты вообще ещё не нашёл ДЛЯ КОГО ты пишешь, КТО является потребителем, а потому и вопрос ЧТО писать — не имеет ответа. Так какая разница на чём?

Сделай сначала чучело, в смысле код, каждый раз возвращающий одно и то же. Прототип. И уже с ним играйся. А уже тогда напишешь логику, и перепишешь её столько раз, сколько надо. Потому что переписывать проще, чем писать с нуля: на каждом этапе отсеивается куча мусора.

Как по мне, ты вообще с продуктом упускаешь очевидный путь. Ты считаешь, что должен сделать всё сам, своими ресурсами. В то время как успешные продукты вполне себе делаются совместно. Пока ты не научился работать совместно, работа самостоятельно не принесёт тебе ничего кроме усталости и депрессии. НАЙДИ продукт с теми технологиями, которые хочешь выучить, НАУЧИСЬ делать то, что там надо, и войди в разработку. Проще всего найти медленно развивающийся или не сильно популярный (до 1000 юзеров) продукт — там тебя не будут сильно пинать, у тебя будет время и возможность прокачать скиллы.

Почему так? Жизнь короче, чем ты думаешь. Нет смысла учиться делать всё и браться за всё. Да, у тебя получится. Но насколько лучше других у тебя получится? Сколько времени ты потратишь безвозвратно? Кому ты потом нужен на том уровне, до какого у тебя получилось? Куда дороже ценится ОПЫТ РАБОТЫ в команде. Потому что он даёт больше профита за единицу времени.

Если коротко, то нет, j2ee достаточно геморная для изучения штука, с кучей маразма внутри, и всё это моментально забывается если его не используешь по назначению. А назначение у него — бизнес-логика, столь же тупая и невообразимо нелогичная. Именно приведение нелогичности в бюрократические рамки бизнес-логики и есть программирование на энтерпрайз-фреймворках и платформах. Когда оно тебе будет НАДО — особой сложности не будет. Опять же, когда ты ПОЧИТАЕШЬ чужой код завершённых проектов, прежде чем писать свой. Именно завершённых, а не учебные кусочки, по кусочкам ты эту дуристику не поймёшь.

Я с тобой потому общаюсь, что ты читаешь мои мысли. Я еще не успел задать вопрос, а ты уже ответ дал. Вот ты не веришь, а телепатия такого рода возможна. Я умею замечать такие вещи. Общаются два человека постами. И один другому пишет короткие вопросы, а другой ему в ответ простыни. И вот первый я — начинаю читать простыню и у меня формируется вопрос. И вдруг бах! я уже в этой же простыне читаю ответ. Ок. И я читаю дальше и снова у меня появляется вопрос. И вдруг — да, да, в той же простыне новый ответ. Словно тот другой — ты, телепат. Тебе часто такое говорят? Иначе не платили бы столько. Хотя это выглядит словно ты перерабатываешь — не даешь мне возможности сначала задать тебе вопрос. Такое знаешь как выглядит? Словно ты из какой-то паралельной реальности прочитал мой вопрос, где я его все таки успел отправить раньше.
Все это легко, если учитывать поведение информации во всех 4 измерениях. Это знание древнее, оно либо утрачено либо скрыто.

Что касается j2ee и вассаби спасибо за развернутый ответ. Твои советы очень ценные для меня. Я всегда ищу провидцев и следую их советам. По крайней мере стараюсь.

В мене теж все працює.
Яка в вас версія JDK?
І скиньте повний стектрейс, щоб краще розібратись

1) stackoverflow.com/questions/tagged/java

2) Просит ли? www.tutorialspoint.com/compile_java_online.php выдает
$javac HelloWorld.java $java -Xmx128M -Xms16M HelloWorld max = 0.9969690961547211 min = 5.236547651865653E-4 avg = 0.5112746316201295

Підписатись на коментарі