Страницы

Поиск по вопросам

Показаны сообщения с ярлыком java-faq. Показать все сообщения
Показаны сообщения с ярлыком java-faq. Показать все сообщения

вторник, 31 декабря 2019 г.

В чем разница между методами map и flatMap в Java 8?

#java #потоки_данных #java_8 #java_stream #java_faq


Чем отличаются методы Stream.map и Stream.flatMap друг от друга?
    


Ответы

Ответ 1



И map и flatMap могут быть применены к стриму Stream и оба возвращают стрим Stream. Разница заключается в том, что операция map создает одно выходное значение для каждого входного значения, тогда как операция flatMap создает произвольное число(ноль или больше) значений для каждого входного значения. Операция map(О работе map на русском) в качестве аргумента принимает Function(например, лямбду), которая вызывается для каждого значения входного стрима(который ), преобразует это значение в другое значение, и посылает получившееся значение в выходной стрим(который ). Т.е. map для каждого объекта в стриме возвращает по 1 объекту, потом преобразует все объекты в итоговый стрим. Операция flatMap(О работе flatMap на русском) принимает функцию (которая преобразует каждое значение входного стрима в стрим), применяет ее к каждому элементу, и на выходе возвращает стрим с одним, несколькими или ни c одним из элементов для каждого элемента входящего стрима. Т.е., flatMap возвращает по стриму для каждого объекта в первоначальном стриме, а затем результирующие потоки объединяются в исходный стрим. Пример для map: есть одномерный массив array с числами. Нужно получить массив из первоначального массива, в котором к каждому числу прибавлена 1. Решение: array = Arrays.stream(array) //преобразовываем массив в стрим .map(i -> i+1) //преобразовываем каждый элемент стрима .toArray(); //преобразовываем стрим в массив map к каждому значению стрима прибавляет 1, потом все новые значения преобразует в итоговый стрим. Пример для flatMap: есть двухмерный array с числами, надо получить одномерный массив с числами. Решение: secondArray = Arrays.stream(array) .flatMapToInt(i -> Arrays.stream(i)) //преобразовываем Stream в Stream .toArray(); // преобразовываем Stream в int[] В этом примере создается стрим состоящий из каждого элемента первоначального массива - т.е. стрим из массивов. Потом с помощью i -> Arrays.stream(i) преобразовываем каждый элемент(который является массивом) стрима в стрим с числами. После этого flatMap собирает все получившееся стримы в один итоговый стрим.

Лямбды в Java 8, что лучше использовать - Function.identity() или t->t?

#java #java_8 #lambda #java_faq


Вопрос по использованию Function.identity() метода. 

Допустим, есть следующий код:

Arrays.asList("a", "b", "c")
          .stream()
          .map(Function.identity()) // <- Этот кусок
          .map(str -> str)          // <- равен этому.
          .collect(Collectors.toMap(
                       Function.identity(), // <-- А этот
                       str -> str));        // <-- равен этому.


Должен ли я использовать Function.identity() вместо str->str(или наоборот)? Я думаю,
что второй вариант более читабелен и понимаем(допустим, если новый человек не знает
что делает identity). Но есть ли «реальная» причина, из-за которой следует отдать предпочтение
одному из способов?
    


Ответы

Ответ 1



Первоначально кажется, что у этих двух способов нет отличия, ведь реализация identity() такова: static Function identity() { return t -> t; } Однако Function.identity() всегда будет возвращать один и тот же экземпляр(обоснование этого решения), в то время как t -> t не только будет создавать новый экземпляр, но даже будет иметь отдельный класс реализации. Для более подробной информации смотрите здесь. Причина в том, что компилятор генерирует синтетический метод, содержащий тело лямбда выражений(случае t -> t это будет return t;) и указывает среде выполнения создать реализацию функционального интерфейса, вызывающего этот метод. Поэтому использование Function.identity() вместо t -> tможет сэкономить немного памяти, но совсем небольшое количество, поэтому это не должно влиять на ваше решение, если вы считаете, что t -> t более читабельно, чем Function.identity(). Также в некоторых методах нельзя вызвать Function.identity(). Допустим, есть такой список: List list ... ... Код ниже отлично скомпилируется: int[] arrayOK = list.stream().mapToInt(i -> i).toArray(); Но если попытаться скомпилировать следующий код, то будет ошибка компиляции: int[] arrayProblem = list.stream().mapToInt(Function.identity()).toArray(); Она произойдет из-за того что mapToInt ожидает ToIntFunction, которая не связана с Function. Также у ToIntFunction нет метода identity().

понедельник, 30 декабря 2019 г.

Чем отличается sleep от wait?

#java #многопоточность #java_faq


Чем отличается TimeUnit.SECONDS.sleep(1); от this.wait(1000)?
    


Ответы

Ответ 1



wait может быть "разбужен" другим потоком с использованием notify, sleep не может. Так же wait (иnotify) должны в быть synchronized блоке. Object obj = ...; synchronized (obj) { obj.wait(); } Пока текущий (выполняющийся) поток - ожидает waits и releases, другой поток может сделать synchronized (obj) { obj.notify(); } (на том же obj) и первый поток проснётся. Можно так же вызвать notifyAll, если более одного потока ожидают - это разбудит их всех. Тем не менее, только один из потоков сможет захватить монитор (т.к. wait в synchronized блоке). Ещё одно различие в том, что wait вызывается на Object, в то время как sleep вызывается на Thread. Если суммировать, то используйте sleep() для time-syncronization и wait() для multi-thread-synchronization.

воскресенье, 15 декабря 2019 г.

Как работать с ресурсами проекта?

#java #intellij_idea #java_faq


Как в Intellij IDEA 14 работать с ресурсами приложения?

В моём случае это картинки для приложения.

Я создал папку с ресурсами в проекте, а как использовать их — не знаю.
    


Ответы

Ответ 1



вне зависимости от используемого ide — работать с ресурсами вы будете на языке java. мой вольный перевод справки по ссылке: Retrieving Resources — получение ресурсов используйте метод getResource для чтения ресурсов из jar-файла. к примеру, этот код получает изображения из *jar-файла: // получить текущий classloader ClassLoader cl = this.getClass().getClassLoader(); // создать изображения Icon saveIcon = new ImageIcon(cl.getResource("images/save.gif")); Icon cutIcon = new ImageIcon(cl.getResource("images/cut.gif")); в примере подразумевается, что следующие файлы присутствуют в jar-файле: images/save.gif images/cut.gif а вот как именно добавить каталоги/файлы с ресурсами в jar-файл — зависит от используемого ide. подробности должны быть описаны в соответствующей справке.

пятница, 13 декабря 2019 г.

Как работает цикл foreach в Java?

#java #foreach #java_faq


Есть коллекция и цикл foreach:

List someList = new ArrayList();
//add "monkey", "donkey", "skeleton key" to someList

for(String item : someList) 
  System.out.println(item);


Как выглядит цикл for, эквивалентный циклу foreach выше? Как работает цикл foreach
внутри? В чем отличия циклов for и foreach?
    


Ответы

Ответ 1



Цикл foreach - это синтаксический сахар. Внешне прежде всего отличается от for отсутствием явного счетчика. Единственное практическое различие между ними заключается в том, что в случае индексируемых объектов у вас нет доступа к индексу. Цикл foreach позволяет выполнять итерации по двум типам объектов: T[] //массивы любого типа Объекты, реализующие интерфейс Iterable. Цикл for, работающий с объектами Iterable Код из вопроса for(String item : someList) System.out.println(item); равен коду ниже for (Iterator i = someIterable.iterator(); i.hasNext();) { String item = i.next(); System.out.println(item); } Этот код работает для любого объекта, реализующего интерфейс Iterable. В цикле foreach нельзя использовать метод remove(index). Вместо этого следует использовать iterator.remove(). Пример: for (Iterator iterator = list.iterator(); iterator.hasNext(); ) if (iterator.next() > 10) iterator.remove(); Если писать for без использования итератора, то вот примерная реализация foreach: for(int i = 0; i < list.size(); i++) System.out.println(list.get(i)); Циклы foreach и for, работающие с массивами String[] fruits = new String[] { "Orange", "Apple", "Pear", "Strawberry" }; for (String fruit : fruits) { // fruit is an element of the `fruits` array. } по сути эквивалентно for (int i = 0; i < fruits.length; i++) { String fruit = fruits[i]; // fruit is an element of the `fruits` array. } foreach против for - производительность При доступе к коллекции, foreach значительно быстрее, чем for. Однако при доступе к массивам - по крайней мере с массивами примитивов и оболочек - доступ через индексы(т.е. используя for) быстрее. Также при вложенных циклах foreach наблюдаются проблемы с производительностью из-за создания большого количество объектов Iterator. В Java 8 представили потоки, которые в целом работают лучше. (хоть эта информация напрямую и не относится к вопросу, но это может быть полезно) Для работы с коллекций: someList.stream().forEach(System.out::println); Для работы с массивом: Arrays.stream(someArray).forEach(System.out::println); Документация Oracle по foreach. UPD: Измерение производительности на JDK9 (не стоит серьезно его оценивать, т.к. мне не кажется, что я все правильно измерил) Для замера производительности я использовал код из этого вопроса: public static void main(String[] args) { System.out.println(getTime()); } private static void testMethod() { //Код, время выполнения которого нужно узнать } /** * Метод для измерения времени выполнения метода testMethod * https://stackoverflow.com/a/2404378/7150209 */ private static double getTime() { for (int i = 0; i < 20; i ++) { //прогрев JVM testMethod(); } int count = 1000; //первоначальное кол-во повтора выполнения testMethod while(true) { long begin = System.nanoTime(); for (int i = 0; i < count; i ++) testMethod(); long end = System.nanoTime(); if ((end - begin) < 1000000000) { //Прогон тестов пока суммарное выполнения count раз count *= 100000; //testMethod`a не будет равно несколько секунд continue; } return (double)(end - begin) / count; } } Как работает метод getTime() - в цикле for метод с тестируемым кодом запускается count раз. Перед началом запусков засекается время, после всех запусков из конечного времени вычитается начальное - получается время запуска count раз тестового метода. После этого время делится на count - получается усредненное время одного запуска тестового метода. Если время запуска count раз тестового метода < 10 секунд, то count увеличивается, и замер происходит заново. В тестовом методе в циклах for и foreach я использовал: переменная = list.get(i)/array[i] для for и переменная = i; для foreach. В лямбде я использовал Arrays.stream(array).map(l -> l+1).collect(Collectors.toList()); и list.stream().map(l -> l+1).collect(Collectors.toList()), т.е. изменение элементов коллекции и создание новой коллекции, поэтому выполнение лямбд заняло больше времени. В таблице видно, что выполнение в лямбде заняло примерно одинаковое время для коллекций и массивов. Время выполнения кода с массивом примерно в 1.5 раза быстрее, чем с коллекцией. Время выполнения цикла for и foreach для всех одинаковое. P.S. Пример код for и foreach для коллекции(n - просто переменная): for(int i = 0; i < list.size(); i++) n = list.get(i); и for(int i : list) n = i;

четверг, 12 декабря 2019 г.

Что такое упаковка и распаковка(boxing/unboxing)?

#java #java_faq


Что это вообще такое упаковка и распаковка (boxing/unboxing) и зачем она нужна?

Был бы рад примерам.
    


Ответы

Ответ 1



Работа с объектами неизбежно влечет за собой накладные расходы по памяти и быстродействию. Чтобы избежать этого, используются переменные примитивных типов. Это, по сути, простые переменные, как в C или С++. byte занимает 1 байт памяти, int и float - по 4 байта, long и double - по 8 байт и т.д. В отличие от операций с объектами, операции с переменными примитивных типов не требуют выделения/освобождения памяти и выполняются быстро - они в в большинстве случаев в конечном счете компилируются в простые процессорные инструкции, что позволяет программам на Java часто работать со скоростью, сравнимой с программами, написанными на простых компилируемых (непосредственно в машинный код) языках (типа тех же C, С++). Неудобство с ними в том, что с ними нельзя делать то, что можно делать со всеми объектами - они не имеют методов. Нельзя, например написать int a = 5; ArrayList list = new ArrayList(); String s = a.toString(); // Ошибка list.add(a)) // Можно, но произойдет автоупаковка // и в коллекцию будет помещен Integer их нельзя помещать в коллекции и прочее. Для того, чтобы обойти это неудобство, для всех примитивных типов существуют соответствующие классы-оболочки, объекты которых могут хранить значения примитивных типов, но обладает всеми свойствами нормальных объектов: Integer a = 5; ArrayList list = new ArrayList(); String s = a.toString(); // OK list.add(a)) // OK Создание объекта-оболочки из переменной примитивного типа называется упаковкой (boxing), а получение значения примитивного типа из объекта-оболочки -- распаковкой (unboxing). Объектам-оболочкам можно присваивать значения примитивных типов, а переменным примитивных типов - значения переменных-оболочек, при этом при необходимости автоматически создаются объекты-оболочки с соответствующими значениями (автоупаковка) или наоборот, примитивные значения извлекаются из оболочек (автораспаковка): int a = 5; Integer b = 10; a = b; // OK, атораспаковка b = a * 123; // OK, автоупаковка В тех случаях, когда по контексту требуются объекты (присваивание, вызов метода с передачей параметров), а мы используем значения примитивных типов (переменные или выражения типа 2 * 3), всегда происходит автоупаковка. Все объекты-оболочки - неизменяемые (immutable) типы, т.е. когда мы присваиваем им новое значение, фактически на замену прежнему объекту создается новый.

Ответ 2



В версиях ниже JDK 1.5 было не легко преобразовывать примитивные типы данных, такие как int, char, float, double в их классы оболочки Integer, Character, Float, Double. Начиная с версии JDK 5 эта функция, преобразования примитивных типов в эквивалентные объекты, реализована автоматически. Это свойство известно как Автоупаковка(Autoboxing). Обратный процесс соответственно – Распаковка(Unboxing) т.е. процесс преобразования объектов в соответствующие им примитивные типы. Пример кода для автоупаковки и распаковки представлен ниже: Автоупаковка 1 Integer integer = 9; Распаковка 1 int in = 0; 2 in = new Integer(9); Когда используется автоупаковка и распаковка? Автоупаковка применяется компилятором Java в следующих условиях: Когда значение примитивного типа передается в метод в качестве параметра метода, который ожидает объект соответствующего класса-оболочки. Когда значение примитивного типа присваивается переменной, соответствующего класса оболочки. Cсылка на источник

Ответ 3



Для понимания смысла упаковки-распаковки нужно понимать, как работает исполняемая среда и ваша программа на уровне процессора, а так же понимать, что термин ООП это всего лишь надстройка над классическим структурным программированием. Промежуточный байт-код во время выполнения программы преобразуется исполняемой средой в команды конкретного микропроцессора. Есть 3 основных способа хранения, обработки данных и их взаимодействия с программой: процессор-регистр, процессор-стек, и процессор-память. Команды работы с регистрами самые короткие и быстрые, со стеком - короткие, но выполняются на большее число тактов процессора, а команды работы с памятью - самые длинные и медленные. При этом в большинстве случаев простые типы данных хранятся и обрабатываются в регистрах процессора и в стеке, классы и более сложные типы данных хранятся в так называемой "куче" - динамической памяти, которая контролируется исполняемой средой. Механизм кучи достаточно сложен и работа с кучей по времени всегда дольше. Связка стек-регистры максимально эффективна при циклических алгоритмах, где в каждой итерации имеются длинные сложные вычисления, при этом циклический фрагмент кода с регистровой адресацией выполняется в сотни, а то и в десятки тысяч раз быстрее, чем если бы данные хранились в куче:) зато хранение данных в памяти упрощает программу и уменьшает ее размер, а также позволяет использовать все прелести ООП. Упаковку-распаковку придумали для того, чтобы избежать потери производительности программного обеспечения - если критически важна скорость - распаковываем свои данные в простой компактный формат, если скорость не критична - упаковываем в объектный тип и упрощаем программу. Кроме скорости возможна ситуация со значительными затратами ресурсов - к примеру, вам необходимо создать массив из миллиона однобайтовых элементов: что лучше использовать - примитивный однобайтовый тип или упакованный размером в несколько десятков байт?

среда, 4 декабря 2019 г.

Как правильно писать микро-тесты в Java?

#java #производительность #jvm #java_faq


Как лучше писать микро-тесты/тесты на производительность в Java? Какие основные пункты,
на которые стоит обратить внимание?
    


Ответы

Ответ 1



Ключевые моменты: Правило 0: правильно сформулируйте задачу и что именно вы хотите проверить. Плохо поставленная задача: Я хочу проверить, что быстрее ArrayList или LinkedList? Лучше: В моём приложении вставка чаще всего происходит в середину списка. Что для моей задачи будет лучше ArrayList или LinkedList? Ещё лучше: В моём приложении вставка чаще всего происходит в середину списка, а при чтении мне нужно, как правило, за раз просматривать несколько элементов подряд. Что для моей задачи будет лучше ArrayList или LinkedList? Правило 1: почитайте авторитетные статьи про различные JVM и микро-бенчмарки. Например, Brian Goetz, 2005. Но не ожидайте чудес от замеров. Все бенчмарки замеряют ограниченный набор метрик в рамках контекста. Правило 2: всегда включайте фазу прогрева jvm, прогоняющую ваши тесты для полной инициализации и компиляции перед фазой самих замеров. (По-хорошему, нужно провести несколько десятков тысяч итераций). Правило 3: Запускайте всегда с флагами -XX:+PrintCompilation, -verbose:gc и т.п., чтобы быть уверенными, что компилятор и другие части jvm не будут выполнять незапланированных операций во время фазы замеров. Правило 4: имейте в виду разницу между -client и -server, а также OSR (On Stack Replacement) и регулярной компиляцией. Предпочитайте сервер клиенту и регулярную компиляцию вместо OSR. Правило 5: помните об эффекте инициализации. Не выводите ничего в консоль впервые в фазе замеров, так как вывод инициализирует классы. Не загружайте новый классы вне фазы прогрева, если, конечно, вы не тестируете саму загрузку классов. Правило 6: помните об эффектах деоптимизации и перекомпиляции. Не допускайте, чтобы какие-то ветки коды впервые использовались во время фазы замеров, потому что компилятор может перекомпилировать код на основе более раннего оптимистического предположения о том, что этот путь не будет использоваться вообще. Правило 2 - это ваша первая линия защиты от таких эффектов. Правило 7: используйте соответствующие инструменты, чтобы читать кишки компилятора, и ожидайте, что будете удивлены от произведённого кода. Осмотрите код самостоятельно, прежде чем формировать теории о том, что же замедляет его. Правило 8: уменьшите шум в ваших измерениях. Запустите свой тест на машине в спокойном состоянии. Запустите его несколько раз, отбросив выбросы. Используйте -Xbatch для сериализации компилятора с приложением и рассмотрите возможность установки -XX:CICompilerCount=1 для предотвращения параллельной работы компилятора с самим собой. Правило 9: используйте уже готовые библиотеки для замеров. Например: JMH, Caliper или Bill and Paul's Excellent UCSD Benchmarks for Java. Правило 10: если пишите, всё же, сами, то используйте System.nanoTime(), т.к. с System.currentTimeMillis() могут быть проблемы. На Linux системах при использовании NTP демона разность двух последовательных System.currentTimeMillis() может быть отрицательной. Или можно воспользоваться StopWatch классами из тех же Apache commons или Guava. Правило 11: будет полезно вызывать System.gc() между тестами (но не между итерациями!). Полезные статьи: Dynamic compilation and performance measurement от IBM. 5 things you didn't know about Java performance monitoring от IBM. Avoiding Benchmarking Pitfalls on the JVM.

среда, 27 ноября 2019 г.

Как и какими средствами находить ошибки в коде Java?


При написании кода он, порой, не работает так, как я задумал или не работает в принципе. Я сижу и гадаю: что и где не так?

Немного посмотрев на код - иду на ресурсы профессионалов, например Stack Overflow и публикую вопрос  "Где здесь ошибка?" или "Почему не работает?"

В итоге очень часто проблема мелкая: дурацкая опечатка, ошибка в синтаксисе и подобное. Профессионалом так не стать, если по каждой мелочёвке бегать по ресурсам. А я хочу им быть.

Вопрос: какие есть способы, чтобы найти ошибки в Java коде? Какие есть инструменты, методы, пути и пр.? 
    


Ответы

Ответ 1



Вчера всё работало, а сегодня не работает / Код не работает как задумано или Debugging (Отладка) В чем заключается процесс отладки? Что это такое? Процесс отладки состоит в том, что мы останавливаем выполнения скрипта в любом месте смотрим, что находится в переменных, в функциях, анализируем и переходим в другие места; ищем те места, где поведение отклоняется от правильного. Заметка: Отладка производится как правило в IDE (Интегрированная среда разработки). Что это такое можно чуть подробнее ознакомиться в вопросе Какие есть способы предупреждения ошибок, их нахождения и устранения? В данном случае будет рассмотрен пример с Intellij IDEA, но отладить код можно в любой другой IDE. Подготовка Достаточно иметь в наличии IDE, например Intellij IDEA Запуск Для начала в левой части панели с кодом на любой строке можно кликнуть ЛКМ, тем самы поставив точку останова (breakpoint - брейкпойнт). Это то место, где отладчик автоматически остановит выполнение Java, как только до него дойдёт. Количество breakpoint'ов не ограничено. Можно ставить везде и много. Отладка запускается сочетанием Shift+F9 или выбором в верхнем меню Run → Debug или нажатием зеленого "жучка": В данном случае, т.к. функция вызывается сразу на той же странице, то при нажати кнопки Debug — отладчик моментально вызовет метод, выполнение "заморозится" на перво же брейкпойнте. В ином случае, для активации требуется исполнить действие, при котором произойдет исполнение нужного участка кода (клик на кнопку в UI, передача POST запроса с данными и прочие другие действия) Цифрами обозначены: Стэк вызовов, все вложенные вызовы, которые привели к текущему месту кода. Переменные. На текущий момент строки ниже номера 24 ещё не выполнилась, поэтому определена лишь data и numsStringArr Показывает текущие значения любых переменных и выражений. В любой момент здесь можн нажать на +, вписать имя любой переменной и посмотреть её значение в реальном времени Например data или nums[0], а можно и nums[i] и item.test.data.name[5].info[key[1]] и т.д. На текущий момент строки ниже номера 24 ещё не выполнилась, поэтому sum и output во вкладке Watchers обозначены красным цветом с надписью "cannot find local variable". Процесс Для самого процесса используются элементы управления (см. изображение выше, выделен зеленым прямоугольником) и немного из дополнительно (см. изображение выше, выделено оранжевым прямоугольником) Show Execution Point (Alt+F10) — переносит в файл и текущую линию отлаживаемого скрипта Например если файлов много, решили посмотреть что в других вкладках, а потом забыли где у вас отладка :) Step Over (F8) — делает один шаг не заходя внутрь функции. Т.е. если на текущей лини есть какая-то функция, а не просто переменная со значением, то при клике данной кнопки, отладчик не будет заходить внутрь неё. Step Into (F7) — делает шаг. Но в отличие от предыдущей, если есть вложенный вызов (например функция), то заходит внутрь неё. Step Out (Shift+F8) — выполняет команды до завершения текущей функции. Удобна, есл случайно вошли во вложенный вызов и нужно быстро из него выйти, не завершая при этом отладку. Rerun (Ctrl+F5) — Перезапустить отладку Resume Program(F9) — Продолжает выполнения скрипта с текущего момента. Если больш нет других точек останова, то отладка заканчивается и скрипт продолжает работу. В ином случае работа прерывается на следующей точке останова. Stop (Ctrl+F2) — Завершить отладку View Breakpoints (Ctrl+Shift+F8) — Посмотреть все установленные брейкпойнты Mute Breakpoints — Отключить брейкпойнты. ... Итак, в текущем коде видно значение входного параметра: data = "23 24 11 18" — строка с данными через пробел numsStringArr = {"23", "24", "11", "18"} — массив строк, который получился из входной переменной. Если нажмем F8 2 раза, то окажемся на строке 27; во вкладках Watches и Variable и в самой странице с кодом увидим, что переменная sum была инициализирована и значение равно 0, а также nums инициализирована и в ней лежит массив целых чисел {23, 24, 11, 18} . Если теперь нажмем F8, то попадем внутрь цикла for и нажимая теперь F8 пока не окончитс цикл, можно будет наблюдать на каждой итерации, как значение num и sum постоянно изменяются. Тем самым мы можем проследить шаг за шагом весь процесс изменения любых переменных и значений на любом этапе, который интересует. Дальнейшие нажатия F8 переместит линию кода на строки 31, 32 и, наконец, 36. Дополнительно Если нажать на View Breakpoints в левой панели, то можно не только посмотреть вс брейкпойнты, но в появившемся окно можно еще более тонко настроить условие, при котором на данной отметке надо остановиться. В методе выше, например, нужно остановиться только когда sum превысит значение 20. Это удобно, если останов нужен только при определённом значении, а не всегда (особенно в случае с циклами). Больше информации об отладке можно посмотреть в http://learn.javajoy.net/debug-intellij-idea, а также в официальной документации к IDE

Ответ 2



Алексей всё правильно написал, но по доброте своей допустил некоторое упрощение которое я сейчас постараюсь исправить. IDE не обязательна как для разработки, так и для отладки! (Можете быть уверены, в этом месте я зловеще захохотал) Исходный код можно писать в любом текстовом редакторе, а компиляцию и отладку можн осуществлять консольными утилитами JDK. Для большей ̶ ̶г̶р̶о̶т̶е̶с̶к̶н̶о̶с̶т̶и̶ восхитительности происходящего будем считать, что работа осуществляется под управлением Windows 7 x64. Прежде всего, для удобства использования инструментов JDK, добавим их в переменну окружения PATH. А чтобы в полной мере пройти тропой древних, исходный текст будем писать не выходя из консоли. Запускаем командную строку cmd, набираем copy con App.java, вводим код и нажимаем Ctrl+Z Для компиляции вводим команду javac -g App.java. Ключ -g нужен для включения отладочной информации в class-файл. И наконец запускаем отладчик командой jdb App Как видно на скриншоте, первым делом я установил точку останова на метод main командо stop on App.main и запустил выполнение командой run. Отладчик, в соответствии с точкой останова, остановил выполнение на 8-й строке программы и показал её. Аналогично командам доступным в IDE можно: Посмотреть текущую позицию отладки командой list Выполнить следующую строку командой step "Перешагнуть" вызов метода командой next "Шагнуть" из метода командой step up Вернуться к выполнению программы командой cont Вывести список локальный переменных командой locals или вывести значение какой-либо конкретной переменной командой print <имя переменной> Самая полезная команда - это help или ?, позволяющая получить справку по всем командам. И конечно же команда без которой не обойтись - quit.

понедельник, 25 ноября 2019 г.

Книги и учебные ресурсы по Java


Собираем подборку качественной литературы по Java. 

Дописывайте, если есть что добавить в общий ответ.




  Данный перечень входит в поддерживаемый сообществом Сборник учебных ресурсов по программированию.

    


Ответы

Ответ 1



Core Java Начинающим: Head First Java (2nd Edition). Kathy Sierra, Bert Bates. Русский перевод: Изучаем Java. Кэти Сиерра, Берт Бейтс. Как это обычно бывает в книгах Head First, вас весело и в картинках обучат основа программирования на Java. У опытных программистов книга может вызвать ухмылку, однако для действительно начального уровня она вполне хороша. Java: A Beginner's Guide. Herbert Schildt. Русский перевод: Java. Руководство для начинающих. Герберт Шилдт. Core Java Volume I: Fundamentals (9th Edition), Core Java Volume II: Advanced Features (9th Edition). Русский перевод: Java. Библиотека профессионала. Том 1. Основы; Java. Библиотек профессионала. Том 2. Расширенные средства программирования. Кей С. Хорстманн, Гари Корнелл. Книги Хорстманна написаны достаточно сухим языком и вываливают на читателя горы документаци по API и километры листингов с полным кодом примеров. Читать их последовательно может быть довольно тяжко, зато книги станут отличным настольным справочником и сборником рецептов. Java™ Platform, Standard Edition 7 API Specification. Онлайн-документация по стандартным библиотекам JAVA SE. Онлайн-курсы, учебники Уроки Java для начинающих на itproger.com Самоучитель по Java с нуля - vertex-academy.com Java Tutorial (англ.) на Javatpoint Курсы на Stepik.org: Java. Базовый курс Computer Science Center (CS центр) Летняя Java школа Adaptive Java (англ.) JetBrains Hyperskill (англ.) - сайт с учебными проектами для обучения программированию на Java, Kotlin, Python JavaRush Средний уровень: Thinking in Java (4th Edition). Bruce Eckel. Русский перевод: Философия Java. Брюс Эккель. Классический фолиант джавистов. Для комфортного чтения требуются базовые познани в языке, т.к. книга не ставит своей задачей научить писать на Java с нуля, а научить писать идиоматично. Java 8: The Complete Reference. Herbert Schildt. Русский перевод: Java 8. Полное руководство. Герберт Шилдт. Effective Java (2nd Edition). Joshua Bloch. Русский перевод: Java. Эффективное программирование. Джошуа Блох. Джошуа Блох в некотором смысле продолжает идею книги Thinking in Java: еще сильнее углубляясь в особенности языка и стандартных библиотек, учит писать красивый код. The Well-Grounded Java Developer: Vital techniques of Java 7 and polyglot programming. Benjamin J Evans, Martijn Verburg. Русский перевод: Java. Новое поколение разработки. Бенджамин Эванс, Мартин Вербург. Java Puzzlers: Traps, Pitfalls, and Corner Cases. Joshua Bloch, Neal Gafter. Java Puzzlers дает возможность тем, кто уже "выучил язык" проверить себя. В книг собраны 95 задачек с подвохом: очевидные на первый взгляд фрагменты кода, таящие каверзный баг. Какие-то из рассматриваемых примеров могут показаться надуманными и нежизненными, однако они в полной мере раскрывают тонкие нюансы программирования на Java. Java Concurrency in Practice. Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, Doug Lea. Подробнейшее пособие по написанию многопоточного кода на Java. Каждая тема рассматриваетс с разных сторон на нескольких примерах, так что к концу главы будет полное понимание осуждаемого предмета. Немаловажно, что один из соавторов (Doug Lea) является автором стандартной библиотеки concurrent-примитивов (java.util.concurrent). Java Performance. Charlie Hunt, Binu John. Must read по оптимизации java Программ, тюнингу JVM и сборщика мусора, бенчмаркингу и профилированию. Core Java for the Impatient. Cay Horstmann. Книга для нетерпеливых, как следует из названия. Позволяет погрузиться в мир язык Java, рассказывается всё, что на самом деле может пригодиться Java-разработчику. Отдельно внимание уделено новшествам восьмой версии языка. В конце каждой главы есть задания для более плотного усвоения материала. (Хорстманн не очень любит язык C++, иногда шутит по этому поводу, вроде того: String[] badWords = {"sex", "drugs", "C++"};, от этого читать становится не так скучно). Java SE 8 for the Really Impatient. Cay Horstmann. Русский перевод: Java SE 8. Вводный курс Кей С. Хорстманна Является продолжением книги Core Java for the Impatient, однако здесь всё внимани уделяется новшествам восьмой версии языка, покрывает очень многие аспекты, будь то лямбда-выражения, работа со Stream API или многопоточность. После каждой главы также присутствуют задания для усвоения материала. Head First Design Patterns.Eric Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra. Русский перевод: Паттерны проектирования. Эрик Фримен, Элизабет Фримен Отличная книга от издательства O'Reilly, в веселой форме обучит вас основным шаблонам проектирования на языке Java. Java 8 Lambdas. Richard Warburton. Русский перевод: Лямбда-выражения в Java 8. Ричард Уорбэртон Обычно в учебниках по Java мало внимания уделяют или не уделяют вовсе теме использования лямбд и стримов. Учебник Уорбэртона восполняет этот недостаток. Экспертный уровень: The Java Language Specification. James Gosling, Bill Joy, Guy L. Steele Jr., Gilad Bracha, Alex Buckley. The Java Virtual Machine Specification. Tim Lindholm and Frank Yellin. Oracle JRockit: The Definitive Guide. Marcus Hirt, Marcus Lagergren. Java EE Java™ Servlet Specification 3.1 Исчерпывающая официальная документация о работе и жизненном цикле сервлетов. Beginning Java EE 7. Antonio Gonsalves. Русский перевод: Изучаем Java EE 7. Энтони Гонсалвес Java EE 7. Основы Арун Гупта Head First Servlets and JSP, 2nd Edition. Bryan Basham, Kathy Sierra, Bert Bates Java Servlet and JSP Cookbook. Bruce W. Perry Русский перевод: Java сервлеты и JSP. Сборник рецептов. Брюс У. Перри Spring Spring Projects Официальная документация о каждом проекте Spring. Описано подробно, но довольно сложно и много, поэтому для первого обучения рекомендую начать с Spring Guides. Spring Guides Очень простые и наглядные пошаговые уроки (на английском) разных возможностей проекто Spring, с возможностью сразу скачать результат и проверить на своем компьютере. Наиболее актуальные туториалы по Spring, которые есть в интернете, так как постоянно обновляются сообществом. Для более детального изучения - смотрите официальную документацию. Spring в действии. Крейг Уоллс Несмотря на то, что в книге описана уже немолодая 3-я версия Spring, книга стои ознакомления, так как очень просто и подробно знакомит читателя с фреймворком. Spring 5 для профессионалов. Юлиана Козмина, Роб Харроп, Крис Шефер, Кларенс Хо Многолетний бестселлер, считающийся наиболее исчерпывающим и авторитетным руководством по Spring. Hibernate Beginning Hibernate. Joseph B. Ottinger, Dave Minter, Jeff Linwood Несмотря на то, что в названии книги стандарт JPA не упоминается, бóльшая часть книги посвящена именно его реализации в Hibernate. Java Persistence with Hibernate. C. Bauer, G. King, G. Gregory Исчерпывающее описание Hibernate и Java Persistence. Swing SWING: Эффективные пользовательские интерфейсы. Иван Портянкин. Swing. A Beginner's Guide. Sсhildt H. Русский перевод: Swing. Руководство для начинающих. Шилдт Г. Swing Hacks. Tips and Tools for Killer GUIs. Joshua Marinacci, Chris Adamson. JavaFX JavaFX 2.0 Разработка RIA-приложений. Тимур Машнин. В ней есть вся нужная информация относительно компонентов и оформления их с помощь fxcss, работы с анимацией, воспроизведения видео и аудио, и конечно относительно работы с FXML. Learn JavaFX 8. Kishori Sharan. Учебник на английском, в нем подробно описываются все основные элементы JavaFX, особенност их поведения и взаимодействия, описываются наблюдаемые свойства и связывания (properties and bindings), и другие полезные возможности, как вывод на печать и подробное описание обработки событий. Руководство по JavaFX на metainit.com Справочники Java 8 Pocket Guide. Robert Liguori. Русский перевод: Java 8. Карманный справочник. Роберт Лигуори. Отличный справочник, с помощью которого можно моментально найти ответы на вопросы по стандартной библиотеке Java, лямбда-выражениям и т. д. Онлайн-ресурсы Российская Java User Group. В архиве очень много докладов по Java, Spring и так далее. Доклады в основном на русском, рассчитаны на опытных разработчиков. Awesome Java - поддерживаемый список лучших библиотек, фреймворков и приложений в мире Java. Useful java links - альтернативный список лучших библиотек, фреймворков и приложений в мире Java. Есть русская версия. Useful java links (video) - поддерживаемый список русскоязычных видео с докладо и конференций по категориям.

воскресенье, 24 ноября 2019 г.

Что из себя представляет null?



null - это экземпляр чего-то?
К какому типу принадлежит null?
Что такое null?
Как он представлен в памяти?

    


Ответы

Ответ 1



null - это экземпляр чего-то? Нет такого типа, которому бы соответствовал instanceof от null. 15.20.2 Type Comparison Operator instanceof RelationalExpression: RelationalExpression instanceof ReferenceType В рантайме результат оператора instanceof будет true, если значение RelationalExpression не null и ссылка может быть приведена к ReferenceType без получения исключения ClassCastException. Иначе результат будет false. Это означает, что для любого типа E и R, для любого E o, где o == null, o instanceof R будет всегда false. К какому типу принадлежит null? JLS 4.1 The Kinds of Types and Values. Есть также специальный тип - null, тип выражения null, у которого нет имени. И т.к. тип null не имеет имени, невозможно объявить переменную с типом null или привести переменную к типу null. null ссылка - единственное возможное значение выражение типа null . null всегда можно привести к любому ссылочному типу. В действительности, можно игнорировать тип null и притвориться, что null - это просто специальный литерал, который может быть любым ссылочным типом. Что такое null? Как сказано в цитате из JLS выше, можно считать, что "null - это просто специальный литерал, который может быть любым ссылочным типом". В Java null == null (что верно не для всех языков). Из описания java.lang.Object: public boolean equals(Object obj) Для любой не null переменной x, x.equals(null) должно возвращать false. null также является значением по умолчанию для всех ссылочных типов. JLS 4.12.5 Initial Values of Variables: Любой экземпляр класса, переменная или элемент массива специализируются значением по умолчанию: Для всех ссылочных типов (§4.3), дефолтное значение - null. Вы можете использовать это свойства для отложенной инициализации, когда поле буде иметь начальное значение null до тех пор, пока оно фактически не будет использовано, где будет заменено "реальным" значением (вычисление которого может быть дорогостоящим). Есть и другие применения. Если посмотреть на java.lang.System: public static Console console() Returns: The system console, if any, otherwise null. Это очень распространённая практика: null используется для обозначения несуществующего объекта. Другой пример - java.io.BufferedReader: public String readLine() throws IOException Returns: A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached. readLine() будет возвращать instanceof String для каждой строки, пока не получи null, обозначающий конец. Это позволяет обрабатывать каждую строку следующим образом: String line; while ((line = reader.readLine()) != null) { process(line); } Примечание: пустая строка - не проблема, т.к. "" != null. Давайте рассмотри java.util.Map: V get(Object key) Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. If this map permits null values, then a return value of null does not necessaril indicate that the map contains no mapping for the key; it's also possible that the map explicitly maps the key to null. The containsKey operation may be used to distinguish these two cases. Здесь мы видим, что использование null может усложнить дело. Тут говорится, что если такого ключа нет, будет возвращён null. Второе утверждение гласит, что даже если элемент по такому ключу есть, всё равно может вернуться null. К примеру, java.util.Hashtable делает вещи проще путём запрета null в ключах и значениях так что, если V get(Object key) вернёт null это однозначно говорит о том, что под таким ключом ничего нет. Операции автоматического боксинга/анбоксинга на null выбросят java.lang.NullPointerException: Integer i = null; // при анбоксинге null в integer будет выброшен NullPointerException int a = i; Если резюмировать, то null используется как специальное значение для обозначения: Не инициализированного состояния. Терминальное условие Несуществующий объект. Неизвестное значение. Как null представлен в памяти? Из спецификации JVM: The Java Virtual Machine specification does not mandate a concrete value encoding null. Небольшое дополнение Интересная цитата C.A.R Hoare: I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. Так же можно посмотреть презентацию про ошибку на миллиард долларов.

Как сравнивать строки в Java?


В своей программе я использовал оператор == для сравнения строк. Но я наткнулся на баг, и при замене == на equals он пропал.​​​​​​​​​​

Следует избегать оператора ==? Когда его можно использовать, а когда нет? В чём разница?
    


Ответы

Ответ 1



Оператор == сравнивает ссылки. Метод equals сравнивает значения. Следовательно, если вы хотите сравнить строки на равенство, следует использовать equals. Однако в некоторых случаях строки гарантированно представлены одним и тем же объекто благодаря пулу строк (string interning). Эти случаи явно описаны в спецификации языка Java. Оператор == используется для проверки, что две строки указывают на один и тот же объект. // Эти строки имеют одно и тоже же значение new String("test").equals("test") // --> true // ...но это разные объекты new String("test") == "test" // --> false // ...эти строки тоже разные объекты new String("test") == new String("test") // --> false // ...но эти строки указывают на один и тот же объект, // потому что компилятор добавляет все литералы в пул. "test" == "test" // --> true // Конкатенация литералов тоже происходит на стадии компиляции, // поэтому они указывают на один объект "test" == "te" + "st" // --> true // но вызов substring() происходит во время выполнения, // в результате получаются разные объекты. "test" == "!test".substring(1) // --> false // Строки из пула могут быть получены с помощью вызова intern(). "test" == "!test".substring(1).intern() // --> true Надо отметить, что == заметно быстрее, чем equals (сравнение ссылки вместо вызов метода и посимвольного сравнения, если строки разной длины), поэтому, если вы работаете со строками из пула (или системного, или своего), замена equals на == может привести к заметному ускорению. Но это случается очень редко. Остерегайтесь вызова equals на null! Оператор == прекрасно сравнивает строки, есл одна или более из них равна null, но вызов метода equals на строке, равной null, приведёт к исключению. Для сравнения строк, которые могут быть равны null, вы можете воспользоваться следующим методом: public static boolean equals(String str1, String str2) { return str1 == null ? str2 == null : str1.equals(str2); } Он присутствует в некоторых сторонних библиотеках, например, в Apache Commons. Если вы пользуетесь современными средами разработки, то они предупредят, если в попытаетесь сравнить строки с помощью оператора ==. Всегда обращайте внимание на подобные предупреждения.

Ответ 2



Если быть коротко, то == сравнивает ссылки на объект, если ссылки указывают на оди и тот же объект, то это тру, иначе false, в случае с примитивными типами == сравнивает значения. equals () используется в String так, он берет и сравнивает посимвольно каждый String но это только со String, если брать остальные объекты (Вы создали объекты Яблоко и Груша), при этом в этих классах не прописан метод equals,то оно как и == сравнивает ссылки на объект, если это один и тот же объект, то тру иначе false. В String прописан метод equals (), который сравнивает посимвольно, поэтому со String нужно юзать equals ()

Что такое stack trace, и как с его помощью находить ошибки при разработке приложений?


Иногда при запуске своего приложения я получаю подобную ошибку:

Exception in thread "main" java.lang.NullPointerException
       at com.example.myproject.Book.getTitle(Book.java:16)
       at com.example.myproject.Author.getBookTitles(Author.java:25)
       at com.example.myproject.Bootstrap.main(Bootstrap.java:14)


Мне сказали, что это называется «трассировкой стека» или «stack trace». Что тако
трассировка? Какую полезную информацию об ошибке в разрабатываемой программе она содержит?



Немного по существу: довольно часто я вижу вопросы, в которых начинающие разработчики
получая ошибку, просто берут трассировки стека и какой-либо случайный фрагмент код
без понимания, что собой представляет трассировка и как с ней работать. Данный вопрос предназначен специально для начинающих разработчиков, которым может понадобиться помощь в понимании ценности трассировки стека вызовов.

Перевод вопроса: «What is a stack trace, and how can I use it to debug my application errors?» @Rob Hruska
    


Ответы

Ответ 1



Простыми словами, трассировка стека – это список методов, которые были вызваны до момента, когда в приложении произошло исключение. Простой случай В указанном примере мы можем точно определить, когда именно произошло исключение. Рассмотрим трассировку стека: Exception in thread "main" java.lang.NullPointerException at com.example.myproject.Book.getTitle(Book.java:16) at com.example.myproject.Author.getBookTitles(Author.java:25) at com.example.myproject.Bootstrap.main(Bootstrap.java:14) Это пример очень простой трассировки. Если пойти по списку строк вида «at…» с самог начала, мы можем понять, где произошла ошибка. Мы смотрим на верхний вызов функции. В нашем случае, это: at com.example.myproject.Book.getTitle(Book.java:16) Для отладки этого фрагмента открываем Book.java и смотрим, что находится на строке 16: public String getTitle() { System.out.println(title.toString()); <-- line 16 return title; } Это означает то, что в приведенном фрагменте кода какая-то переменная (вероятно title) имеет значение null. Пример цепочки исключений Иногда приложения перехватывают исключение и выбрасывают его в виде другого исключения. Обычно это выглядит так: try { .... } catch (NullPointerException e) { throw new IllegalStateException("A book has a null property", e) } Трассировка в этом случае может иметь следующий вид: Exception in thread "main" java.lang.IllegalStateException: A book has a null property at com.example.myproject.Author.getBookIds(Author.java:38) at com.example.myproject.Bootstrap.main(Bootstrap.java:14) Caused by: java.lang.NullPointerException at com.example.myproject.Book.getId(Book.java:22) at com.example.myproject.Author.getBookIds(Author.java:35) ... 1 more В этом случае разница состоит в атрибуте "Caused by" («Чем вызвано»). Иногда исключени могут иметь несколько секций "Caused by". Обычно необходимо найти исходную причину, которой оказывается в самой последней (нижней) секции "Caused by" трассировки. В нашем случае, это: Caused by: java.lang.NullPointerException <-- root cause at com.example.myproject.Book.getId(Book.java:22) <-- important line Аналогично, при подобном исключении необходимо обратиться к строке 22 книги Book.java, чтобы узнать, что вызвало данное исключение – NullPointerException. Еще один пугающий пример с библиотечным кодом Как правило, трассировка имеет гораздо более сложный вид, чем в рассмотренных выш случаях. Приведу пример (длинная трассировка, демонстрирующая несколько уровней цепочек исключений): javax.servlet.ServletException: Произошло что–то ужасное at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388) at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418) at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) at org.mortbay.jetty.Server.handle(Server.java:326) at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943) at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756) at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218) at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228) at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582) Caused by: com.example.myproject.MyProjectServletException at com.example.myproject.MyServlet.doPost(MyServlet.java:169) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166) at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30) ... 27 more Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity] at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822) at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268) at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321) at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689) at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344) at $Proxy19.save(Unknown Source) at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below) at com.example.myproject.MyServlet.doPost(MyServlet.java:164) ... 32 more Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1 duplicate value(s) for column(s) MY_COLUMN in statement [...] at org.hsqldb.jdbc.Util.throwError(Unknown Source) at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source) at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105) at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57) ... 54 more В этом примере приведен далеко не полный стек вызовов. Что вызывает здесь наибольши интерес, так это поиск функций из нашего кода – из пакета com.example.myproject. В предыдущем примере мы сначала хотели отыскать «первопричину», а именно: Caused by: java.sql.SQLException Однако все вызовы методов в данном случае относятся к библиотечному коду. Поэтом мы перейдем к предыдущей секции «Caused by» и найдем первый вызов метода из нашего кода, а именно: at com.example.myproject.MyEntityService.save(MyEntityService.java:59) Аналогично предыдущим примерам, необходимо обратить внимание на MyEntityService.java строка 59: именно здесь появилась ошибка (в данном случае ситуация довольно очевидная, так как об ошибке сообщает SQLException, но в этом вопросе мы рассматриваем именно процедуру отладки с помощью трассировки). Перевод ответа: «What is a stack trace, and how can I use it to debug my application errors?» @Rob Hruska

Что такое Null Pointer Exception и как его исправить?


Что из себя представляет исключение Null Pointer Exception (java.lang.NullPointerException) и почему оно может происходить?

Какие методы и средства использовать, чтобы определить причину возникновения этого исключения, приводящего к преждевременному прекращению работы приложения?

Перевод вопроса «What is a Null Pointer Exception, and how do I fix it?» @Ziggy.
    


Ответы

Ответ 1



Когда вы объявляете переменную ссылочного типа, на самом деле вы создаете ссылк на объект данного типа. Рассмотрим следующий код для объявления переменной типа int: int x; x = 10; В этом примере переменная x имеет тип int и Java инициализирует её как 0. Когда в присвоите переменной значение 10 (вторая строка), это значение сохранится в ячейке памяти, на которую ссылается x. Но когда вы объявляете ссылочный тип, процесс выглядит иначе. Посмотрим на следующий код: Integer num; num = new Integer(10); В первой строке объявлена переменная num, ее тип не относится к встроенному, следовательно значением является ссылка (тип этой переменной, Integer, является ссылочным типом). Поскольку вы еще не указали, на что собираетесь ссылаться, Java присвоит переменной значение Null, подразумевая «Я ни на что не ссылаюсь». Во второй строке, ключевое слово new используется для создания объекта типа Integer Этот объект имеет адрес в памяти, который присваивается переменной num. Теперь, с помощью переменной num вы можете обратиться к объекту используя оператора разыменования .. Исключение, о котором вы говорите в вопросе, возникает, если вы объявили переменную но не создали объект, то есть если вы попытаетесь разыменовать num до того, как создали объект, вы получите NullPointerException. В самом простом случае, компилятор обнаружит проблему и сообщит, что num may not have been initialized Что говорит: «возможно, переменная num не инициализирована». Иногда исключение вызвано именно тем, что объект действительно не был создан. К примеру, у вас может быть следующая функция: public void doSomething(Integer num){ // Работаем с num } В этом случае создание объекта (переменная num) лежит на вызывающем коде, то ест вы предполагаете, что он был создан ранее – до вызова метода doSomething. К сожалению, следующий вызов метода вполне возможен: doSomething(null); В этом случае значение переменной num будет null. Лучшим способом избежать данног исключения будет проверка на равенство нулю. Как результат, функция doSomething должна быть переписана следующим образом: public void doSomething(Integer num){ if (num != null) { // Работаем с num } } Как альтернативный вариант предыдущему примеру вы можете сообщить вызывающему коду что метод был вызван с неверными параметрами, например, с помощью IllegalArgumentException. public void doSomething(Integer num){ if (num == null) throw new IllegalArgumentException("Num не должен быть null"); // Работаем с num } Также, обратите внимание на вопрос «Что такое stack trace и как с его помощью находить ошибки при разработке приложений?». Перевод ответа «What is a Null Pointer Exception, and how do I fix it?» @Vincen Ramdhanie.

Ответ 2



В java8 был добавлен класс Optional для предотвращения NullPointerException, хот использовать его по назначению не всегда удается правильно. Вот ссылка с рекомендациями как использовать Optional Типичное решение с проверкой на null Article article = getFirstJavaArticle(); if (article == null) { article = fetchLatestArticle(); } А теперь решение с использованием Optional. Представим что getFirstJavaArticle() возвращает Optional
getFirstJavaArticle() .orElseGet(this::fetchLatestArticle); Решение с Optional позволяет нам избежать кода с проверками на null и работать в функциональном стиле. Стоит заметить что Optional не является панацеей от всех бед Так же для предотвращения NullPointerException используется паттерн NullObject Абстрактный Entity class public abstract class AbstractCustomer { protected String name; public abstract String getName(); } Реальная реализация public class RealCustomer extends AbstractCustomer { public RealCustomer(String name) { this.name = name; } @Override public String getName() { return name; } } Реализация NullObject public class NullCustomer extends AbstractCustomer { @Override public String getName() { return "Not Available in Customer Database"; } } Использование (как пример) public class CustomerFactory { public static final String[] names = {"Rob", "Joe", "Julie"}; public static AbstractCustomer getCustomer(String name){ for (int i = 0; i < names.length; i++) { if (names[i].equalsIgnoreCase(name)){ return new RealCustomer(name); } } return new NullCustomer(); } } Вместо возвращения null мы возвращаем экземпляр класс NullCustomer и не падаем NullPointerException. Но как мне кажется присутствует небольшой Overhead: необходимо создавать иерархию наследования.

Ответ 3



Это Exception , который встречается тогда, когда ты ссылаешься на объект, которы = null(не инициализирован) или пытаешься вызвать методы/обратиться к переменным объекта, который = null. Решение этой проблемы: Проверка на null, if(Твой объект==null){//Your code} try{}catch(NullPointerException e){//Your code} Когда тебе выбрасывает нулл,то обычно указывает "иерархию строчек"(что, как вызывалось что привело тебя к нулл). И там ты можешь посмотреть, где у тебя объект не инициализирован, там и можно сразу исправить ошибку. Может встречаться в массивах/списках, когда вызываешь объект под номер n, при том, что объекта туда предварительно не записан. Вроде, все))

Ответ 4



Советую использовать Optional для предотвращения NPE. Этот класс был введене в java 8. К примеру @Entity public class Car { @Id @GeneratedValue private Long id; @Column(name = "name") @NotNull private String name; } Репозиторий: public interface CarRepository extends JpaRepository { Optional findById(Long id); } Сервис: @Service public class CarService { private CarRepository carRepository; @Autowired public CarService(CarRepository carRepository) { this.carRepository = carRepository; } public Car findById(Long id) { Car car = carRepository.findById(id).orElseThrow(() -> new RuntimeException("Requested entity was not found")); car.getHolder().setPassword(null); return car; } } Контроллер: @RestController @RequestMapping("/api") public class CarController { private CarService carService; @Autowired public CarController(CarService carService) { this.carService = carService; } @RequestMapping(value = "/cars/{id}", method = RequestMethod.GET) public ResponseEntity getCar(@PathVariable Long id) { try { Car carToFind = carService.findById(id); return ResponseEntity.status(HttpStatus.OK).body(carToFind); } catch (Exception ex) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); } } } В таком случае, если репозиторий не сможет найти машину, он не выкинет NPE. Optional помогает избежать проверок на null и сократить код и улучшить его читаемостью.

среда, 19 декабря 2018 г.

Чем отличается sleep от wait?

Чем отличается TimeUnit.SECONDS.sleep(1); от this.wait(1000)?


Ответ

wait может быть "разбужен" другим потоком с использованием notify, sleep не может. Так же wait (иnotify) должны в быть synchronized блоке.
Object obj = ...; synchronized (obj) { obj.wait(); }
Пока текущий (выполняющийся) поток - ожидает waits и releases, другой поток может сделать
synchronized (obj) { obj.notify(); }
(на том же obj) и первый поток проснётся. Можно так же вызвать notifyAll, если более одного потока ожидают - это разбудит их всех. Тем не менее, только один из потоков сможет захватить монитор (т.к. wait в synchronized блоке).
Ещё одно различие в том, что wait вызывается на Object, в то время как sleep вызывается на Thread
Если суммировать, то используйте sleep() для time-syncronization и wait() для multi-thread-synchronization.

пятница, 2 ноября 2018 г.

Как правильно писать микро-тесты в Java?

Как лучше писать микро-тесты/тесты на производительность в Java? Какие основные пункты, на которые стоит обратить внимание?


Ответ

Ключевые моменты:
Правило 0: правильно сформулируйте задачу и что именно вы хотите проверить.
Плохо поставленная задача:
Я хочу проверить, что быстрее ArrayList или LinkedList?
Лучше:
В моём приложении вставка чаще всего происходит в середину списка. Что для моей задачи будет лучше ArrayList или LinkedList?
Ещё лучше:
В моём приложении вставка чаще всего происходит в середину списка, а при чтении мне нужно, как правило, за раз просматривать несколько элементов подряд. Что для моей задачи будет лучше ArrayList или LinkedList?
Правило 1: почитайте авторитетные статьи про различные JVM и микро-бенчмарки. Например, Brian Goetz, 2005. Но не ожидайте чудес от замеров. Все бенчмарки замеряют ограниченный набор метрик в рамках контекста.
Правило 2: всегда включайте фазу прогрева jvm, прогоняющую ваши тесты для полной инициализации и компиляции перед фазой самих замеров. (По-хорошему, нужно провести несколько десятков тысяч итераций).
Правило 3: Запускайте всегда с флагами -XX:+PrintCompilation, -verbose:gc и т.п., чтобы быть уверенными, что компилятор и другие части jvm не будут выполнять незапланированных операций во время фазы замеров.
Правило 4: имейте в виду разницу между -client и -server, а также OSR (On Stack Replacement) и регулярной компиляцией. Предпочитайте сервер клиенту и регулярную компиляцию вместо OSR.
Правило 5: помните об эффекте инициализации. Не выводите ничего в консоль впервые в фазе замеров, так как вывод инициализирует классы. Не загружайте новый классы вне фазы прогрева, если, конечно, вы не тестируете саму загрузку классов.
Правило 6: помните об эффектах деоптимизации и перекомпиляции. Не допускайте, чтобы какие-то ветки коды впервые использовались во время фазы замеров, потому что компилятор может перекомпилировать код на основе более раннего оптимистического предположения о том, что этот путь не будет использоваться вообще. Правило 2 - это ваша первая линия защиты от таких эффектов.
Правило 7: используйте соответствующие инструменты, чтобы читать кишки компилятора, и ожидайте, что будете удивлены от произведённого кода. Осмотрите код самостоятельно, прежде чем формировать теории о том, что же замедляет его.
Правило 8: уменьшите шум в ваших измерениях. Запустите свой тест на машине в спокойном состоянии. Запустите его несколько раз, отбросив выбросы. Используйте -Xbatch для сериализации компилятора с приложением и рассмотрите возможность установки -XX:CICompilerCount=1 для предотвращения параллельной работы компилятора с самим собой.
Правило 9: используйте уже готовые библиотеки для замеров. Например: JMH, Caliper или Bill and Paul's Excellent UCSD Benchmarks for Java.
Правило 10: если пишите, всё же, сами, то используйте System.nanoTime(), т.к. с System.currentTimeMillis() могут быть проблемы. На Linux системах при использовании NTP демона разность двух последовательных System.currentTimeMillis() может быть отрицательной. Или можно воспользоваться StopWatch классами из тех же Apache commons или Guava
Правило 11: будет полезно вызывать System.gc() между тестами (но не между итерациями!).
Полезные статьи:
Dynamic compilation and performance measurement от IBM. 5 things you didn't know about Java performance monitoring от IBM. Avoiding Benchmarking Pitfalls on the JVM

пятница, 26 октября 2018 г.

Как работать с ресурсами проекта?

Как в Intellij IDEA 14 работать с ресурсами приложения?
В моём случае это картинки для приложения.
Я создал папку с ресурсами в проекте, а как использовать их — не знаю.


Ответ

вне зависимости от используемого ide — работать с ресурсами вы будете на языке java
мой вольный перевод справки по ссылке:
Retrieving Resources — получение ресурсов
используйте метод getResource для чтения ресурсов из jar-файла
к примеру, этот код получает изображения из *jar-файла:
// получить текущий classloader ClassLoader cl = this.getClass().getClassLoader(); // создать изображения Icon saveIcon = new ImageIcon(cl.getResource("images/save.gif")); Icon cutIcon = new ImageIcon(cl.getResource("images/cut.gif"));
в примере подразумевается, что следующие файлы присутствуют в jar-файле
images/save.gif images/cut.gif

а вот как именно добавить каталоги/файлы с ресурсами в jar-файл — зависит от используемого ide. подробности должны быть описаны в соответствующей справке.

вторник, 2 октября 2018 г.

Что из себя представляет null?

null - это экземпляр чего-то? К какому типу принадлежит null? Что такое null? Как он представлен в памяти?


Ответ

null - это экземпляр чего-то?
Нет такого типа, которому бы соответствовал instanceof от null
15.20.2 Type Comparison Operator instanceof
RelationalExpression: RelationalExpression instanceof ReferenceType В рантайме результат оператора instanceof будет true, если значение RelationalExpression не null и ссылка может быть приведена к ReferenceType без получения исключения ClassCastException. Иначе результат будет false
Это означает, что для любого типа E и R, для любого E o, где o == null, o instanceof R будет всегда false
К какому типу принадлежит null?
JLS 4.1 The Kinds of Types and Values
Есть также специальный тип - null, тип выражения null, у которого нет имени. И т.к. тип null не имеет имени, невозможно объявить переменную с типом null или привести переменную к типу null. null ссылка - единственное возможное значение выражение типа null . null всегда можно привести к любому ссылочному типу. В действительности, можно игнорировать тип null и притвориться, что null - это просто специальный литерал, который может быть любым ссылочным типом.
Что такое null?
Как сказано в цитате из JLS выше, можно считать, что "null - это просто специальный литерал, который может быть любым ссылочным типом".
В Java null == null (что верно не для всех языков). Из описания java.lang.Object
public boolean equals(Object obj) Для любой не null переменной x, x.equals(null) должно возвращать false.
null также является значением по умолчанию для всех ссылочных типов.
JLS 4.12.5 Initial Values of Variables
Любой экземпляр класса, переменная или элемент массива специализируются значением по умолчанию: Для всех ссылочных типов (§4.3), дефолтное значение - null.
Вы можете использовать это свойства для отложенной инициализации, когда поле будет иметь начальное значение null до тех пор, пока оно фактически не будет использовано, где будет заменено "реальным" значением (вычисление которого может быть дорогостоящим).
Есть и другие применения. Если посмотреть на java.lang.System
public static Console console() Returns: The system console, if any, otherwise null.
Это очень распространённая практика: null используется для обозначения несуществующего объекта.
Другой пример - java.io.BufferedReader
public String readLine() throws IOException Returns: A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached.
readLine() будет возвращать instanceof String для каждой строки, пока не получит null, обозначающий конец. Это позволяет обрабатывать каждую строку следующим образом:
String line; while ((line = reader.readLine()) != null) { process(line); }
Примечание: пустая строка - не проблема, т.к. "" != null
Давайте рассмотри java.util.Map
V get(Object key) Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. If this map permits null values, then a return value of null does not necessarily indicate that the map contains no mapping for the key; it's also possible that the map explicitly maps the key to null. The containsKey operation may be used to distinguish these two cases.
Здесь мы видим, что использование null может усложнить дело. Тут говорится, что, если такого ключа нет, будет возвращён null. Второе утверждение гласит, что даже если элемент по такому ключу есть, всё равно может вернуться null
К примеру, java.util.Hashtable делает вещи проще путём запрета null в ключах и значениях; так что, если V get(Object key) вернёт null это однозначно говорит о том, что под таким ключом ничего нет.
Операции автоматического боксинга/анбоксинга на null выбросят java.lang.NullPointerException
Integer i = null;
// при анбоксинге null в integer будет выброшен NullPointerException int a = i;
Если резюмировать, то null используется как специальное значение для обозначения:
Не инициализированного состояния. Терминальное условие Несуществующий объект. Неизвестное значение.
Как null представлен в памяти?
Из спецификации JVM
The Java Virtual Machine specification does not mandate a concrete value encoding null
Небольшое дополнение
Интересная цитата C.A.R Hoare
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
Так же можно посмотреть презентацию про ошибку на миллиард долларов

понедельник, 1 октября 2018 г.

Как сравнивать строки в Java?

В своей программе я использовал оператор == для сравнения строк. Но я наткнулся на баг, и при замене == на equals он пропал.​​​​​​​​​​
Следует избегать оператора ==? Когда его можно использовать, а когда нет? В чём разница?


Ответ

Оператор == сравнивает ссылки.
Метод equals сравнивает значения.
Следовательно, если вы хотите сравнить строки на равенство, следует использовать equals
Однако в некоторых случаях строки гарантированно представлены одним и тем же объектом благодаря пулу строк (string interning). Эти случаи явно описаны в спецификации языка Java
Оператор == используется для проверки, что две строки указывают на один и тот же объект.
// Эти строки имеют одно и тоже же значение new String("test").equals("test") // --> true
// ...но это разные объекты new String("test") == "test" // --> false
// ...эти строки тоже разные объекты new String("test") == new String("test") // --> false
// ...но эти строки указывают на один и тот же объект, // потому что компилятор добавляет все литералы в пул. "test" == "test" // --> true
// Конкатенация литералов тоже происходит на стадии компиляции, // поэтому они указывают на один объект "test" == "te" + "st" // --> true
// но вызов substring() происходит во время выполнения, // в результате получаются разные объекты. "test" == "!test".substring(1) // --> false
// Строки из пула могут быть получены с помощью вызова intern(). "test" == "!test".substring(1).intern() // --> true
Надо отметить, что == заметно быстрее, чем equals (сравнение ссылки вместо вызова метода и посимвольного сравнения, если строки разной длины), поэтому, если вы работаете со строками из пула (или системного, или своего), замена equals на == может привести к заметному ускорению. Но это случается очень редко
Остерегайтесь вызова equals на null! Оператор == прекрасно сравнивает строки, если одна или более из них равна null, но вызов метода equals на строке, равной null, приведёт к исключению.
Для сравнения строк, которые могут быть равны null, вы можете воспользоваться следующим методом:
public static boolean equals(String str1, String str2) { return str1 == null ? str2 == null : str1.equals(str2); }
Он присутствует в некоторых сторонних библиотеках, например, в Apache Commons.
Если вы пользуетесь современными средами разработки, то они предупредят, если вы попытаетесь сравнить строки с помощью оператора ==. Всегда обращайте внимание на подобные предупреждения.

Что такое stack trace, и как с его помощью находить ошибки при разработке приложений?

Иногда при запуске своего приложения я получаю подобную ошибку:
Exception in thread "main" java.lang.NullPointerException at com.example.myproject.Book.getTitle(Book.java:16) at com.example.myproject.Author.getBookTitles(Author.java:25) at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Мне сказали, что это называется «трассировкой стека» или «stack trace». Что такое трассировка? Какую полезную информацию об ошибке в разрабатываемой программе она содержит?

Немного по существу: довольно часто я вижу вопросы, в которых начинающие разработчики, получая ошибку, просто берут трассировки стека и какой-либо случайный фрагмент кода без понимания, что собой представляет трассировка и как с ней работать. Данный вопрос предназначен специально для начинающих разработчиков, которым может понадобиться помощь в понимании ценности трассировки стека вызовов.
Перевод вопроса: «What is a stack trace, and how can I use it to debug my application errors?» @Rob Hruska


Ответ

Простыми словами, трассировка стека – это список методов, которые были вызваны до момента, когда в приложении произошло исключение.
Простой случай
В указанном примере мы можем точно определить, когда именно произошло исключение. Рассмотрим трассировку стека:
Exception in thread "main" java.lang.NullPointerException at com.example.myproject.Book.getTitle(Book.java:16) at com.example.myproject.Author.getBookTitles(Author.java:25) at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Это пример очень простой трассировки. Если пойти по списку строк вида «at…» с самого начала, мы можем понять, где произошла ошибка. Мы смотрим на верхний вызов функции. В нашем случае, это:
at com.example.myproject.Book.getTitle(Book.java:16)
Для отладки этого фрагмента открываем Book.java и смотрим, что находится на строке 16
public String getTitle() { System.out.println(title.toString()); <-- line 16 return title; }
Это означает то, что в приведенном фрагменте кода какая-то переменная (вероятно, title) имеет значение null
Пример цепочки исключений
Иногда приложения перехватывают исключение и выбрасывают его в виде другого исключения. Обычно это выглядит так:
try { .... } catch (NullPointerException e) { throw new IllegalStateException("A book has a null property", e) }
Трассировка в этом случае может иметь следующий вид:
Exception in thread "main" java.lang.IllegalStateException: A book has a null property at com.example.myproject.Author.getBookIds(Author.java:38) at com.example.myproject.Bootstrap.main(Bootstrap.java:14) Caused by: java.lang.NullPointerException at com.example.myproject.Book.getId(Book.java:22) at com.example.myproject.Author.getBookIds(Author.java:35) ... 1 more
В этом случае разница состоит в атрибуте "Caused by" («Чем вызвано»). Иногда исключения могут иметь несколько секций "Caused by". Обычно необходимо найти исходную причину, которой оказывается в самой последней (нижней) секции "Caused by" трассировки. В нашем случае, это:
Caused by: java.lang.NullPointerException <-- root cause at com.example.myproject.Book.getId(Book.java:22) <-- important line
Аналогично, при подобном исключении необходимо обратиться к строке 22 книги Book.java, чтобы узнать, что вызвало данное исключение – NullPointerException
Еще один пугающий пример с библиотечным кодом
Как правило, трассировка имеет гораздо более сложный вид, чем в рассмотренных выше случаях. Приведу пример (длинная трассировка, демонстрирующая несколько уровней цепочек исключений):
javax.servlet.ServletException: Произошло что–то ужасное at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388) at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418) at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) at org.mortbay.jetty.Server.handle(Server.java:326) at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943) at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756) at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218) at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228) at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582) Caused by: com.example.myproject.MyProjectServletException at com.example.myproject.MyServlet.doPost(MyServlet.java:169) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166) at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30) ... 27 more Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity] at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822) at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71) at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268) at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321) at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204) at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210) at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195) at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50) at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93) at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693) at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689) at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344) at $Proxy19.save(Unknown Source) at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below) at com.example.myproject.MyServlet.doPost(MyServlet.java:164) ... 32 more Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...] at org.hsqldb.jdbc.Util.throwError(Unknown Source) at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source) at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105) at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57) ... 54 more
В этом примере приведен далеко не полный стек вызовов. Что вызывает здесь наибольший интерес, так это поиск функций из нашего кода – из пакета com.example.myproject. В предыдущем примере мы сначала хотели отыскать «первопричину», а именно:
Caused by: java.sql.SQLException
Однако все вызовы методов в данном случае относятся к библиотечному коду. Поэтому мы перейдем к предыдущей секции «Caused by» и найдем первый вызов метода из нашего кода, а именно:
at com.example.myproject.MyEntityService.save(MyEntityService.java:59)
Аналогично предыдущим примерам, необходимо обратить внимание на MyEntityService.java, строка 59: именно здесь появилась ошибка (в данном случае ситуация довольно очевидная, так как об ошибке сообщает SQLException, но в этом вопросе мы рассматриваем именно процедуру отладки с помощью трассировки).
Перевод ответа: «What is a stack trace, and how can I use it to debug my application errors?» @Rob Hruska

Как и чем парсить Json на Java?

Часто возникает потребность работы с Json, в частности его чтения и парсинга. В Java обычно ты знаешь с каким типом переменных работаешь, а при парсинге Json смущает то, что тип полей может быть любой.
Какие есть способы разбора Json? Как это делать?
Вот, допустим, как достать данные из Json, представленного ниже?
{ "firstName": "Json", "lastName": "Smith", "age": 30, "address": { "streetAddress": "666 1nd Street", "city": "New York", "state": "NY", "postalCode": 10021 }, "phoneNumbers": [ { "type": "home", "number": "542 666-1234" }, { "type": "fax", "number": "653 666-4567" } ], "friends": [ { "firstName": "Test", "lastName": "Snow", "age": 20, "phoneNumbers": [ { "type": "home", "number": "141 111-1234" } ], "friends": [ { "firstName": "UnknownFirstName", "lastName": "UnknownLastName", "age": 999, "phoneNumbers": [ { "type": "home", "number": "000 000-0000" } ] } ] }, { "firstName": "Flash", "lastName": "Tompson", "age": 23, "phoneNumbers": [ { "type": "home", "number": "999 111-1234" } ] } ] }


Ответ

Достать данные можно разными способами и, конечно, зависит от задач. Попробую рассмотреть некоторые варианты разбора Json.
Заметка: для каждого из примеров для парсинга будет взят Json из вопроса, чтобы зря не копировать в ответ.

Simple Json
Где взять: здесь / репозиторий на github / или через Maven и пр.
Это самый примитивный способ. По сути, всё, что тут есть - это JSONObject и JSONArray.
JSONArray может включать в себя несколько объектов JSONObject, его можно обходить циклом на каждой итерации получая объект JSONObject JSONObject - объект, из которого можно доставать его отдельные свойства.
Я бы использовал его для небольших Json строк, где не надо сильно заморачиваться или если не лень писать свой класс-обработчик на основе кода, который продемонстрирован ниже:
// Считываем json Object obj = new JSONParser().parse(jsonString); // Object obj = new JSONParser().parse(new FileReader("JSONExample.json")); // Кастим obj в JSONObject JSONObject jo = (JSONObject) obj; // Достаём firstName and lastName String firstName = (String) jo.get("firstName"); String lastName = (String) jo.get("lastName"); System.out.println("fio: " + firstName + " " + lastName); // Достаем массив номеров JSONArray phoneNumbersArr = (JSONArray) jo.get("phoneNumbers"); Iterator phonesItr = phoneNumbersArr.iterator(); System.out.println("phoneNumbers:"); // Выводим в цикле данные массива while (phonesItr.hasNext()) { JSONObject test = (JSONObject) phonesItr.next(); System.out.println("- type: " + test.get("type") + ", phone: " + test.get("number")); }
Остальная работа с вложенными массивами аналогична. Можно складывать в List, Map и пр.

GSON
Где взять: здесь / репозиторий на github / или через Maven и пр.
Документация: http://www.studytrails.com/java/json/java-google-json-introduction/
Позволяет парсить Json также, как и Json-simple, т.е. используя JSONObject и JSONArray (см. документацию), но имеет более мощный инструмент парсинга. Достаточно создать классы, которые повторяют структуру Json'а. Для парсинга Json из вопроса создадим классы:
class Person { public String firstName; public String lastName; public int age; public Address address; public List phoneNumbers; public List friends; }
class Address { public String streetAddress; public String city; public String state; public int postalCode; }
class Phones { public String type; public String number; }
Теперь достаточно написать:
Gson g = new Gson(); Person person = g.fromJson(jsonString, Person.class);
Всё! Магия! Чудо! Теперь в person лежит объект с типом Person, в котором находятся данные именно с теми типами, которые были указаны в созданных классах! Теперь можно работать с любым типом, как это привыкли всегда делать: String, Integer, List, Map и всё остальное.
// Выведет фамилии всех друзей с их телефонами for (Person friend : person.friends) { System.out.print(friend.lastName); for (Phones phone : friend.phoneNumbers) { System.out.println(" - phone type: " + phone.type + ", phone number : " + phone.number); } }
// output: // Snow - phone type: home, phone number : 141 111-1234 // Tompson - phone type: home, phone number : 999 111-1234

Пример парсинга в Map
...... JSON для разбора:
{ "2":{ "sessions":[ { "time":"13:00", "price":"410" }, { "time":"06:40", "price":"340" }, { "time":"16:50", "price":"370" } ], "name":"Кинокис-L", "locate":"Москва, Садовая-Спасская ул., 21, 56", "metro":"Красные ворота" }, "7":{ "sessions":[ { "time":"06:35", "price":"190" }, { "time":"00:05", "price":"410" } ], "name":"Кинокис-V", "locate":"Павелецкая пл., 2, строение 1", "metro":"Павелецкая" }, "8":{ "sessions":[ { "time":"15:10", "price":"330" } ], "name":"Кинокис-J", "locate":"ул. Пречистенка, 40/2", "metro":"Кропоткинская" }, "9":{ "sessions":[ { "time":"13:00", "price":"600" }, { "time":"08:30", "price":"300" }, { "time":"04:00", "price":"510" }, { "time":"13:15", "price":"340" } ], "name":"Кинокис-U", "locate":"Шарикоподшипниковская ул., 24", "metro":"Дубровка" } }
...... Классы (POJO):
class Seanse { public String name; public String locate public String metro; public List sessions; }
class Sessions { public String time; public double price; }
...... Сам разбор выглядит так:
Gson g = new Gson(); Type type = new TypeToken>(){}.getType(); Map myMap = g.fromJson(json, type);
Всё.
Дополнительно в GSON можно использовать аннотации, например: исключить указанные поля при парсинге, поменять имя переменной (например не personFirstName, а fName) и многое другое. Подробнее см. в документации

Jackson
Где взять: здесь / репозиторий на github / или через Maven и пр.
Документация и примеры: https://github.com/FasterXML/jackson-docs
Как и GSON он также позволяет работать используя JSONObject и JSONArray если это требуется, и тоже умеет парсить на основе предоставленных классов (см. пример ниже).
Аналогично в нем можно указывать дополнительные требования за счет аннотаций, например: не парсить указанные поля, использовать кастомный конструктор класса, поменять имя переменной (например не firstName, а fName) и многое другое. Подробнее см. в документации
ObjectMapper mapper = new ObjectMapper(); Person person = mapper.readValue(jsonString, Person.class);
System.out.println("My fio: " + person.firstName + " " + person.lastName + " and my friends are: "); for (Person friend : person.friends) { System.out.print(friend.lastName); for (Phones phone : friend.phoneNumbers) { System.out.println(" - phone type: " + phone.type + ", phone number : " + phone.number); } }
// output: // My fio: Json Smith and my friends are: // Snow - phone type: home, phone number : 141 111-1234 // Tompson - phone type: home, phone number : 999 111-1234

JsonPath
Где взять: через Maven и другие сборщики / репозиторий на github
Относится к так называемым XPath библиотекам. Её суть аналогична xpath в xml, то есть легко получать часть информации из json'а, по указанному пути. А также позволяет фильтровать по условию.
// Выведет все фамилии друзей List friendsLastnames = JsonPath.read(jsonString, "$.friends[*].lastName"); for (String lastname : friendsLastnames) { System.out.println(lastname); }
// output: // Snow // Tompson
Пример с выборкой по условию:
// Поиск друга, которому больше 22 лет List friendsWithAges = JsonPath .using(Configuration.defaultConfiguration()) .parse(jsonString) .read("$.friends[?(@.age > 22)].lastName", List.class);
for (String lastname : friendsWithAges) { System.out.println(lastname); }
// output: // Tompson