#java
Разница между equals() и compareTo()
♨️ При реализации интерфейсного метода Comparable compareTo, мы решаем как именно наши объекты будут сравниваться с друг с другом.
♨️В свою очередь, equals просто говорит нам, равны ли 2 объекта.
Разница между equals() и compareTo()
⟡
Метод equals() проверяет объекты на равенство, то есть возвращает просто логическое значение - true/false.⟡
compareTo() сравнивает объекты, и возвращает 0 если объекты равны, 1(или другое положительное число) если объект больше другого объекта, -1(или другое отрицательное число) - объект меньше другого объекта.♨️ При реализации интерфейсного метода Comparable compareTo, мы решаем как именно наши объекты будут сравниваться с друг с другом.
♨️В свою очередь, equals просто говорит нам, равны ли 2 объекта.
#java
Что такое атомарность в Java?
Как можно определить атомарность?
Атомарность операции чаще всего принято обозначать через ее признак неделимости: операция может либо примениться полностью, либо не примениться вообще. Хорошим примером будет запись значений в массив:
При использовании метода nonAtomic существует вероятность того, что какой-то поток обратится к array[0] в тот момент, когда array[0] не проинициализирован, и получит неожиданное значение. При использовании probablyAtomic (при том условии, что массив сначала заполняется, а уже потом присваивается. Такого быть не должно: array всегда содержит либо null, либо проинициализированный массив, но в array[0] не может содержаться что-то, кроме 1. Эта операция неделима, и она не может примениться наполовину, как это было с nonAtomic - только либо полностью, либо никак, и весь остальной код может спокойно ожидать, что в array будет либо null, либо значения, не прибегая к дополнительным проверкам.
Кроме того, под атомарностью операции зачастую подразумевают видимость ее результата всем участникам системы, к которой это относится (в данном случае - потокам); это логично, но, на мой взгляд, не является обязательным признаком атомарности.
Почему это важно?
Атомарность зачастую проистекает из бизнес-требований приложений: банковские транзакции должны применяться целиком, билеты на концерты заказываться сразу в том количестве, в котором были указаны, и т.д.
Что такое атомарность в Java?
Как можно определить атомарность?
Атомарность операции чаще всего принято обозначать через ее признак неделимости: операция может либо примениться полностью, либо не примениться вообще. Хорошим примером будет запись значений в массив:
При использовании метода nonAtomic существует вероятность того, что какой-то поток обратится к array[0] в тот момент, когда array[0] не проинициализирован, и получит неожиданное значение. При использовании probablyAtomic (при том условии, что массив сначала заполняется, а уже потом присваивается. Такого быть не должно: array всегда содержит либо null, либо проинициализированный массив, но в array[0] не может содержаться что-то, кроме 1. Эта операция неделима, и она не может примениться наполовину, как это было с nonAtomic - только либо полностью, либо никак, и весь остальной код может спокойно ожидать, что в array будет либо null, либо значения, не прибегая к дополнительным проверкам.
Кроме того, под атомарностью операции зачастую подразумевают видимость ее результата всем участникам системы, к которой это относится (в данном случае - потокам); это логично, но, на мой взгляд, не является обязательным признаком атомарности.
Почему это важно?
Атомарность зачастую проистекает из бизнес-требований приложений: банковские транзакции должны применяться целиком, билеты на концерты заказываться сразу в том количестве, в котором были указаны, и т.д.
#Spring #backEnd #java
Spring: @Component против @Bean
@Component и @Bean делают две совершенно разные вещи, и их не следует путать.
@Component (а также @Service и @Repository ) используются для автоматического обнаружения и автоматической настройки бобов с помощью сканирования classpath. Существует неявное отображение one-to-one между аннотированным классом и Бобом (то есть один боб на класс). Управление проводкой при таком подходе довольно ограничено, поскольку оно носит чисто декларативный характер.
@Bean используется для явного объявления одного компонента, а не позволяет Spring делать это автоматически, как описано выше. Он отделяет объявление Боба от определения класса.
Spring: @Component против @Bean
@Component и @Bean делают две совершенно разные вещи, и их не следует путать.
@Component (а также @Service и @Repository ) используются для автоматического обнаружения и автоматической настройки бобов с помощью сканирования classpath. Существует неявное отображение one-to-one между аннотированным классом и Бобом (то есть один боб на класс). Управление проводкой при таком подходе довольно ограничено, поскольку оно носит чисто декларативный характер.
@Bean используется для явного объявления одного компонента, а не позволяет Spring делать это автоматически, как описано выше. Он отделяет объявление Боба от определения класса.
#java
Немного о наследовании и ООП
Какие методы можно переопределять?
- Все методы, которые не являются static, final или private.
this - ссылка на текущий объект
super - не то же что и this. Это ключевое слово всего лишь уведомляет компилятору, что нужно вызвать из суперкласса.
Невозможно использование super в static методах и переменных.
Для того чтобы обратиться к элементам родительского класса с помощью super, эти элементы должны быть видны в дочернем классе.
При обращении к методу родительского класса, выражение super не обязательно должно быть первой строкой тела метода.
Ключевое слово new - вызывается конструктор, который инициализирует поля.
Конструктор не является членом класса, то есть он не наследуется, по этой причине, мы и используем ключевое слово super для его вызова из суперкласса.
К любому члену класса мы можем обратиться через "точку", к полям, к методом. К конструктору мы обратиться не сможем.
Немного о наследовании и ООП
Какие методы можно переопределять?
- Все методы, которые не являются static, final или private.
this - ссылка на текущий объект
super - не то же что и this. Это ключевое слово всего лишь уведомляет компилятору, что нужно вызвать из суперкласса.
⟡
keyword super означает обращение к объекту родительского класса.
С помощью keyword super можно обращаться как к методам, так и к переменным родительского класса.Невозможно использование super в static методах и переменных.
Для того чтобы обратиться к элементам родительского класса с помощью super, эти элементы должны быть видны в дочернем классе.
При обращении к методу родительского класса, выражение super не обязательно должно быть первой строкой тела метода.
❗️⟡
Конструктор - инициализатор, некий набор инструкций, который для вновь созданного объекта задает некоторое начальное состояние. Ключевое слово new - вызывается конструктор, который инициализирует поля.
Конструктор не является членом класса, то есть он не наследуется, по этой причине, мы и используем ключевое слово super для его вызова из суперкласса.
К любому члену класса мы можем обратиться через "точку", к полям, к методом. К конструктору мы обратиться не сможем.
Возможно будет продолжение в сторону Reflection API. Кому интересно, накидайте лайков.
#java
Кастинг ссылочных типов данных
Кастинг - это процесс, когда вы заставляете переменную одного типа данных вести себя как переменная другого типа данных.
Кастинг возможен только тогда, когда между классами/интерфейсами существует IS-A взаимоотношение.
Делая кастинг, вы не меняете тип данных объекта, а заставляете его чувствовать себя как объект другого типа.
Кастинг из дочернего класса в супер класс происходит автоматически - Upcasting.
Кастинг из супер класса в дочерний класс НЕ происходит автоматически - Downcasting.
Если между классами/интерфейсами нет IS-A взаимоотношения, компилятор не допустит кастинг.
Даже если компилятор допустил кастинг, выскочит runtime exception, если объект, который мы делаем каст на самом деле не принадлежит классу, на который мы его делаем каст.
Кастинг ссылочных типов данных
Кастинг - это процесс, когда вы заставляете переменную одного типа данных вести себя как переменная другого типа данных.
Кастинг возможен только тогда, когда между классами/интерфейсами существует IS-A взаимоотношение.
Делая кастинг, вы не меняете тип данных объекта, а заставляете его чувствовать себя как объект другого типа.
Кастинг из дочернего класса в супер класс происходит автоматически - Upcasting.
Кастинг из супер класса в дочерний класс НЕ происходит автоматически - Downcasting.
Если между классами/интерфейсами нет IS-A взаимоотношения, компилятор не допустит кастинг.
Даже если компилятор допустил кастинг, выскочит runtime exception, если объект, который мы делаем каст на самом деле не принадлежит классу, на который мы его делаем каст.
#java
О методе equals()
Если вы перезаписываете метод equals, всегда используйте в его параметре тип данных Object.
Правильно перезаписанный метод equals должен обладать следующими свойствами:
О методе equals()
Если вы перезаписываете метод equals, всегда используйте в его параметре тип данных Object.
Правильно перезаписанный метод equals должен обладать следующими свойствами:
⟡
Симметричность - для non-null ссылочных переменных a и b, a.equals(b) возвращает true тогда и только тогда, когда b.equals(a) возвращает true.⟡
Рефлексивность - для non-null ссылочных типов переменной a, a.equals(a) всегда должно возвращать true.⟡
Транзитивность - для non-null ссылочных переменных a, b, c если a.equals(b) и b.equals(c) возвращает true, то a.equals(c) тоже должно возвращать true.⟡
Постоянство - для non-null ccылочных переменных переменных a и b, неоднократный вызов a.equals(b) должен возвращать или только true или только false.⟡
Для non-null ссылочной переменной a, a.equals(null) всегда должно возвращать false.#java
Non-access modifiers
Non-access modifiers
⟡
transient. Переменные класса с ключевым словом transient не сериализуются.⟡
native. Методы с ключевым словом native реализованы не на Java. В своем описании они не имеют тела и заканчиваются как абстрактные методы символом ";".⟡
synchronized. Методы с ключевым словом synchronized могут быть использованы в одно и тоже время только одним потоком.⟡
volatile. Переменные с ключевым словом volatile могут быть изменены разными потоками и данные изменения будут видны во всех потоках.⟡
strictfp. Ключевое слово strictfp в методах и классах ограничивает точность вычислений с float и double по стандарту IEEE.#java
Checked/Unchecked exceptions
Runtime исключения бывают в коде, в котором присутствуют ошибочные выражения. Т.е. в выбросе данных исключений виноват программист. Компилятор НЕ в состоянии проверить возможность выброса runtime исключений.
❗️Runtime исключения можно не объявлять и не обрабатывать, но при желании, можно сделать и то, и другое.
Checked исключения указывают на часть кода, которая находится за пределами непосредственного контроля программой и которая может являться причиной выброса исключений. Они, как правило, возникают при взаимодействии вашей программы с внешними источниками (работа с файлами, с БД, с сетью), из-за которых могут возникать проблемы. Компилятор всегда проверяет возможность выброса checked исключений.
❗️Checked исключения всегда должны быть или объявлены и/или обработаны.
Checked/Unchecked exceptions
Раньше уже был пост на эту тему, но в этом попытаюсь объяснить более простыми словами + дополнить + повторение материала не помешает)
⟡
Сабклассы RuntimeExceptions = unchecked exceptionsRuntime исключения бывают в коде, в котором присутствуют ошибочные выражения. Т.е. в выбросе данных исключений виноват программист. Компилятор НЕ в состоянии проверить возможность выброса runtime исключений.
❗️Runtime исключения можно не объявлять и не обрабатывать, но при желании, можно сделать и то, и другое.
⟡
Сабклассы Exceptions = checked exceptionsChecked исключения указывают на часть кода, которая находится за пределами непосредственного контроля программой и которая может являться причиной выброса исключений. Они, как правило, возникают при взаимодействии вашей программы с внешними источниками (работа с файлами, с БД, с сетью), из-за которых могут возникать проблемы. Компилятор всегда проверяет возможность выброса checked исключений.
❗️Checked исключения всегда должны быть или объявлены и/или обработаны.
#java
Важные моменты в исключениях
Важные моменты в исключениях
⟡
Очередность catch блоков очень важна. Компилятор не пропустит код, если исключение "супер класс" будет стоять перед исключением "дочерний класс".⟡
Если в части кода, которая не находится в блоке try или в блоке try выбрасывается исключение, то соответствующая оставшаяся часть кода уже не обрабатывается.⟡
После выброса исключения мы можем увидеть стэк трейс (1) для всех методов, задействованных в выбросе этого исключения.⟡
При создании объекта исключения вы можете воспользоваться его конструктором, который принимает String параметр и вписать в него необходимую информацию. Вы также можете воспользоваться конструктором, который не принимает параметры.⟡
finally блок выполняется в том случае, если в try блоке или в catch блоке имеется return statement.⟡
finally блок не выполнится только в том случае, если вы прекращаете работу программы с помощью System.exit в try или в catch блоке или же, если происходит "крушение" JVM или, например, операционной системы.⟡
Если return statement имеется и в catch блоке и в finally блоке, то аутпутом метода будет возвращаемое значение из finally блока.(1) Про это позже будет пост
#java
Лямбда выражения
( Поскольку пост вышел довольно объемным, сделал его в телеграфе. Удобная штука оказалась )
https://telegra.ph/Lyambda-vyrazheniya-06-06
Лямбда выражения
( Поскольку пост вышел довольно объемным, сделал его в телеграфе. Удобная штука оказалась )
https://telegra.ph/Lyambda-vyrazheniya-06-06
Telegraph
Лямбда выражения
Как всегда, начнем с неудобств, которые решают лямбды) Имеется обычный класс, Employee. Поля - имя, департамент, ЗП. Есть задача - отфильтровать сотрудников. Если бы фильтрация была одноразовой, за каким-то одним параметром, проблем бы не было. Но, фильтровать…
#java
Встроенные функциональные интерфейсы
Решил написать сначала о функциональных интерфейсах, все-таки, это база для StreamAPI. Кстати, следующий пост будет о именно о них.
https://telegra.ph/Vstroennye-funkcionalnye-interfejsy-06-11
Встроенные функциональные интерфейсы
Решил написать сначала о функциональных интерфейсах, все-таки, это база для StreamAPI. Кстати, следующий пост будет о именно о них.
https://telegra.ph/Vstroennye-funkcionalnye-interfejsy-06-11
Telegraph
Встроенные функциональные интерфейсы
Как и упоминалось в предыдущем посте, разработчики Java создали довольно много функциональных интерфейсов. Рассмотрим основные.
#java #design
Почему композиция лучше наследования?
GoF: «Предпочитайте композицию наследованию класса».
Гибкость – это конечно полезная черта дизайна. Однако при выборе архитектуры нас интересуют в первую очередь сопровождаемость, тестируемость, читабельность кода, повторное использование модулей. Так вот с этими критериями хорошего дизайна у наследования проблемы.
Проблема хрупкого базового класса
Одним из основных критериев хорошей архитектуры является слабое зацепление (loose coupling), которое характеризует степень взаимосвязи между программными модулями. Не зря слабое зацепление входит в перечень паттернов GRASP, описывающих базовые принципы для распределения ответственности между классами.
Слабое зацепление имеет массу преимуществ!
Ослабив зависимости между программными модулями, вы облегчаете сопровождение и поддержку системы за счет формирования более гибкой архитектуры.
Появляется возможность параллельной разработки слабозацепленных модулей без риска нарушить их функционирование.
Логика работы класса становится более очевидной, легче становится использовать класс правильно и по назначению, и сложно использовать – неправильно.
Почему композиция лучше наследования?
GoF: «Предпочитайте композицию наследованию класса».
Гибкость – это конечно полезная черта дизайна. Однако при выборе архитектуры нас интересуют в первую очередь сопровождаемость, тестируемость, читабельность кода, повторное использование модулей. Так вот с этими критериями хорошего дизайна у наследования проблемы.
Проблема хрупкого базового класса
Одним из основных критериев хорошей архитектуры является слабое зацепление (loose coupling), которое характеризует степень взаимосвязи между программными модулями. Не зря слабое зацепление входит в перечень паттернов GRASP, описывающих базовые принципы для распределения ответственности между классами.
Слабое зацепление имеет массу преимуществ!
Ослабив зависимости между программными модулями, вы облегчаете сопровождение и поддержку системы за счет формирования более гибкой архитектуры.
Появляется возможность параллельной разработки слабозацепленных модулей без риска нарушить их функционирование.
Логика работы класса становится более очевидной, легче становится использовать класс правильно и по назначению, и сложно использовать – неправильно.
#java #testing
Для чего вообще нужно тестирование?
Недавно узнал, что не все начинающие разработчики понимают, почему тестирование необходимо и почему на него так много тратят времени.
Написание тестов, это всегда минимум 40% от выполнения каждого моего таска. Юнит-тесты, интеграционные, и тесты на взаимодействие с другими сервисами. Чем больше возможных ситуаций можно предугадать, тем лучше.
Юнит-тесты конечно простейшие. Вы с ними точно встречались, если делали какие-то задачи на LeetCode, или Codewars. Вы просто выделяете маленький блок кода, класс и его методы, даете определенные данные на вход и проверяете, что получаете на выходе. Это самый быстрый и наименее эффективный способ проверить, все ли работает корректно, ведь, если метод работает корректно сам по себе, это не значит, что он будет работать корректно в самой системе. Вот здесь нам и нужны интеграционные тесты.
При имплементации сложных решений, например создание больших фич, как переписывание утилитарного класса на другую библиотеку, необходимо писать интеграционные тесты. Интеграционные тесты, это по сути много юнит-тестов. Вы берете класс и проверяете, как он будет взаимодействовать с другими классами в вашей системе. Хорошие интеграционные тесты требуют написания тысяч линий кода, поэтому иногда приходится писать собственные фреймворки для тестирования.
Ну вот я проверил, что все правильно работает, для чего мне оставлять тысячи линий кода в проекте, если все и так работает?
Тесты часто вам помогают убедиться, что новая фича ничего старого не поломала. При хорошем деплойе проходят все тесты и, если что-то пойдет не так, то поблагодарите тестам, что это не случилось на проде и к вам домой не едет CEO.
Пишите много тестов.
Для чего вообще нужно тестирование?
Недавно узнал, что не все начинающие разработчики понимают, почему тестирование необходимо и почему на него так много тратят времени.
Написание тестов, это всегда минимум 40% от выполнения каждого моего таска. Юнит-тесты, интеграционные, и тесты на взаимодействие с другими сервисами. Чем больше возможных ситуаций можно предугадать, тем лучше.
Юнит-тесты конечно простейшие. Вы с ними точно встречались, если делали какие-то задачи на LeetCode, или Codewars. Вы просто выделяете маленький блок кода, класс и его методы, даете определенные данные на вход и проверяете, что получаете на выходе. Это самый быстрый и наименее эффективный способ проверить, все ли работает корректно, ведь, если метод работает корректно сам по себе, это не значит, что он будет работать корректно в самой системе. Вот здесь нам и нужны интеграционные тесты.
При имплементации сложных решений, например создание больших фич, как переписывание утилитарного класса на другую библиотеку, необходимо писать интеграционные тесты. Интеграционные тесты, это по сути много юнит-тестов. Вы берете класс и проверяете, как он будет взаимодействовать с другими классами в вашей системе. Хорошие интеграционные тесты требуют написания тысяч линий кода, поэтому иногда приходится писать собственные фреймворки для тестирования.
Ну вот я проверил, что все правильно работает, для чего мне оставлять тысячи линий кода в проекте, если все и так работает?
Тесты часто вам помогают убедиться, что новая фича ничего старого не поломала. При хорошем деплойе проходят все тесты и, если что-то пойдет не так, то поблагодарите тестам, что это не случилось на проде и к вам домой не едет CEO.
Пишите много тестов.
#java
Сохранение данных в постоянной памяти, используя Preferences.
Если вам нужно сохранять конфигурацию, информацию о пользователе, о программе на всех платформах одинаково и вы не хотите беспокоиться о разных путях, или писать отдельные методы для работы с файлами и переживать об их безопасности, то самый лучший и самый простой вариант это Preferences.
Если очень просто то это обычное API, позволяющее записывать значения по принципу ключ/значения. И основная особенность того, что на всех платформах оно будет адаптироваться. Фактическое хранение данных зависит от платформы.
Вот пример кода (Читайте комментарии):
Useful link - https://spec-zone.ru/RU/Java/Docs/7/api/java/util/prefs/Preferences.html
Сохранение данных в постоянной памяти, используя Preferences.
Если вам нужно сохранять конфигурацию, информацию о пользователе, о программе на всех платформах одинаково и вы не хотите беспокоиться о разных путях, или писать отдельные методы для работы с файлами и переживать об их безопасности, то самый лучший и самый простой вариант это Preferences.
Если очень просто то это обычное API, позволяющее записывать значения по принципу ключ/значения. И основная особенность того, что на всех платформах оно будет адаптироваться. Фактическое хранение данных зависит от платформы.
Вот пример кода (Читайте комментарии):
import java.util.prefs.Preferences;Запустите программу дважды. Значение «key1» должно быть записано со значением по умолчанию (true) в командную строку, так как значение preference было удалено в конце метода. Значение «key2» и «key3» должно было измениться после первого вызова.
class PreferenceTest {
//Created node for storage
private final Preferences prefs = Preferences.userRoot().node(this.getClass().getName());
public void setPreference() {
//Keys
final String key1 = "key1";
final String key2 = "key2";
final String key3 = "key3";
//Here we define variables with default values
System.out.println(prefs.getBoolean(key1, true));
System.out.println(prefs.get(key2, "Hello World"));
System.out.println(prefs.getInt(key3, 50));
prefs.putBoolean(key1, false);
prefs.put(key2, "Bye bye");
prefs.putInt(key3, 0);
//You should write key and default value for getting present value
System.out.println(prefs.getInt(key3, 50));
prefs.remove(key1);
}
public static void main(String[] args) {
PreferenceTest test = new PreferenceTest();
test.setPreference();
}
}
Useful link - https://spec-zone.ru/RU/Java/Docs/7/api/java/util/prefs/Preferences.html
#java
Difference between Concurrency and Parallelism
Concurrency:
By Concurrency, we mean executing multiple tasks on the same core. In simpler terms, it relates to processing more than one task at the same time. It is a state in which multiple tasks start, run, and complete in overlapping time periods. An application capable of executing multiple tasks virtually at the same time is called a Concurrent application.
In case the computer only has one CPU or one Core the application may not make progress on more than one task at the exact same time. Instead, divide the time and the Core/CPU among various tasks. Concurrency is useful in decreasing the response time of the system.
Parallelism:
Parallelism is the ability of an application to split up its processes or tasks into smaller subtasks that are processed simultaneously or in parallel. It is the mechanism in which multiple processes execute independently of each other where each process acquires a separate core. This utilizes all the cores of the CPU or
Difference between Concurrency and Parallelism
Concurrency:
By Concurrency, we mean executing multiple tasks on the same core. In simpler terms, it relates to processing more than one task at the same time. It is a state in which multiple tasks start, run, and complete in overlapping time periods. An application capable of executing multiple tasks virtually at the same time is called a Concurrent application.
In case the computer only has one CPU or one Core the application may not make progress on more than one task at the exact same time. Instead, divide the time and the Core/CPU among various tasks. Concurrency is useful in decreasing the response time of the system.
Parallelism:
Parallelism is the ability of an application to split up its processes or tasks into smaller subtasks that are processed simultaneously or in parallel. It is the mechanism in which multiple processes execute independently of each other where each process acquires a separate core. This utilizes all the cores of the CPU or