🔍 Ответ на вопрос про пропавший эксепшен:
Привет, друзья! Сегодня обсудим скрытую проблему с логированием исключений, которая часто возникает в многопоточной среде.
На первый взгляд все кажется довольно обычным: мы отправляем задачу на выполнение, которая вызывает метод logString с null значением. Это должно вызвать NullPointerException.
❓ Где же исключение? Вы могли заметить, что исключение не будет напечатано в логи, даже если оно происходит. Почему?
🔎 Объяснение:
Исключения в Java, возникающие в потоке, обрабатываются контекстом этого потока.
В случае использования ExecutorService.submit(...), если задача выбрасывает исключение, оно остается незамеченным, потому что submit возвращает Future, который просто тихо удаляет это исключение.
Если вы не вызываете методы get() у Future и не обрабатываете возможное исключение, вы его просто не увидите.
💡 Как это исправить? Чтобы исключение стало видимым, можно сделать следующее:
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<?> future = executorService.submit(() -> logString(null));
try {
future.get(); // Обрабатываем возможное исключение
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace(); // Выводим исключение в логи
} finally {
executorService.shutdown();
}
}
📌 В этом изменении future.get() либо вернёт результат, либо выбросит ExecutionException, если что-то пошло не так, позволяя вам логировать и обрабатывать ситуацию корректно.
👨💻 Вывод: Будьте внимательны при работе с многопоточностью. Убедитесь, что вы корректно обрабатываете возможные исключения, особенно при использовании ExecutorService.
➖➖➖➖➖
🎓 Надеюсь, это было полезно! Оставьте свои вопросы и комментарии ниже. 👇
Подписывайтесь, чтобы не пропустить важные советы и приемы! 🔥
#java #многопоточность #исключения #программирование #лучшиепрактики
Привет, друзья! Сегодня обсудим скрытую проблему с логированием исключений, которая часто возникает в многопоточной среде.
На первый взгляд все кажется довольно обычным: мы отправляем задачу на выполнение, которая вызывает метод logString с null значением. Это должно вызвать NullPointerException.
❓ Где же исключение? Вы могли заметить, что исключение не будет напечатано в логи, даже если оно происходит. Почему?
🔎 Объяснение:
Исключения в Java, возникающие в потоке, обрабатываются контекстом этого потока.
В случае использования ExecutorService.submit(...), если задача выбрасывает исключение, оно остается незамеченным, потому что submit возвращает Future, который просто тихо удаляет это исключение.
Если вы не вызываете методы get() у Future и не обрабатываете возможное исключение, вы его просто не увидите.
💡 Как это исправить? Чтобы исключение стало видимым, можно сделать следующее:
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<?> future = executorService.submit(() -> logString(null));
try {
future.get(); // Обрабатываем возможное исключение
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace(); // Выводим исключение в логи
} finally {
executorService.shutdown();
}
}
📌 В этом изменении future.get() либо вернёт результат, либо выбросит ExecutionException, если что-то пошло не так, позволяя вам логировать и обрабатывать ситуацию корректно.
👨💻 Вывод: Будьте внимательны при работе с многопоточностью. Убедитесь, что вы корректно обрабатываете возможные исключения, особенно при использовании ExecutorService.
➖➖➖➖➖
🎓 Надеюсь, это было полезно! Оставьте свои вопросы и комментарии ниже. 👇
Подписывайтесь, чтобы не пропустить важные советы и приемы! 🔥
#java #многопоточность #исключения #программирование #лучшиепрактики
🔥15❤4👍4🙏1
🔍 Ответ на вопрос про volatile и массивы в Java:
📌 Многие разработчики могут ошибочно полагать, что при объявлении массива volatile все его элементы также будут обладать свойствами volatile. Однако это не так!
Пример выше как раз демонстрирует эту особенность.
🔎 Объяснение:
volatile int[] arr делает переменную arr ссылкой volatile. Это означает, что любые изменения ссылки на массив будут видны другим потокам.
Однако элементы массива не наследуют volatile-свойство. Таким образом, arr[0] и arr[1] не имеют гарантий видимости друг для друга.
➖➖➖➖➖
Ставьте лайк , если нашли это полезным и задавайте свои вопросы и комментарии ниже для получения дополнительных знаний! 🚀
#java #многопоточность #volatile #программирование
📌 Многие разработчики могут ошибочно полагать, что при объявлении массива volatile все его элементы также будут обладать свойствами volatile. Однако это не так!
Пример выше как раз демонстрирует эту особенность.
🔎 Объяснение:
volatile int[] arr делает переменную arr ссылкой volatile. Это означает, что любые изменения ссылки на массив будут видны другим потокам.
Однако элементы массива не наследуют volatile-свойство. Таким образом, arr[0] и arr[1] не имеют гарантий видимости друг для друга.
➖➖➖➖➖
Ставьте лайк , если нашли это полезным и задавайте свои вопросы и комментарии ниже для получения дополнительных знаний! 🚀
#java #многопоточность #volatile #программирование
Telegram
Java Interview Tasks
Какие значения могут напечататься? (thread1 и thread2 запускаются одновременно в разных потоках)
🔥10👍4❤3👎1👏1🙏1🐳1
🔍 Ответ на задачу про то, как Java выбирает перегрузку метода?
🚀🚀🚀Когда вы вызываете метод в Java, который имеет несколько перегруженных вариантов, компилятор должен решить, какой из них использовать. Давайте разберёмся, как он это делает на примере вызова метода printFor(42).
Вот правила, которыми руководствуется компилятор:
🚀 Точный тип: Ищет метод с точным совпадением типа аргумента. У нас его нет для int, так как метода printFor(int) нет.
🚀 Примитивное расширение (widening): Далее проверяется, можно ли расширить примитивный тип. 42 (int) может быть преобразован в long, и метод printFor(long) подходит.
🚀 Автоупаковка (boxing): Если расширение невозможно, оценивается автоупаковка. int может стать Integer, что делает метод printFor(Integer) возможным, но менее предпочтительным, чем printFor(long).
🚀 Varargs (массив произвольной длины): Как запасной вариант, компилятор рассматривает использование varargs. Метод printFor(int...) подходит, но также менее предпочтителен.
🚀 Автоупаковка в Object: Ещё менее специфичный вариант — преобразование в Integer и затем в Object для printFor(Object).
🔗🔗 🔗 В итоге, компилятор выбирает printFor(long), потому что расширение примитивного типа более предпочтительно, чем автоупаковка и varargs. Это позволяет Java эффективно и предсказуемо обрабатывать вызовы методов!
🎓 Надеюсь, это было полезно! Оставьте свои вопросы, лайки и комментарии ниже. 👇
#Java #Программирование #CodingTips #JavaTips #java_interview_tasks
🚀🚀🚀Когда вы вызываете метод в Java, который имеет несколько перегруженных вариантов, компилятор должен решить, какой из них использовать. Давайте разберёмся, как он это делает на примере вызова метода printFor(42).
Вот правила, которыми руководствуется компилятор:
🚀 Точный тип: Ищет метод с точным совпадением типа аргумента. У нас его нет для int, так как метода printFor(int) нет.
🚀 Примитивное расширение (widening): Далее проверяется, можно ли расширить примитивный тип. 42 (int) может быть преобразован в long, и метод printFor(long) подходит.
🚀 Автоупаковка (boxing): Если расширение невозможно, оценивается автоупаковка. int может стать Integer, что делает метод printFor(Integer) возможным, но менее предпочтительным, чем printFor(long).
🚀 Varargs (массив произвольной длины): Как запасной вариант, компилятор рассматривает использование varargs. Метод printFor(int...) подходит, но также менее предпочтителен.
🚀 Автоупаковка в Object: Ещё менее специфичный вариант — преобразование в Integer и затем в Object для printFor(Object).
🔗🔗 🔗 В итоге, компилятор выбирает printFor(long), потому что расширение примитивного типа более предпочтительно, чем автоупаковка и varargs. Это позволяет Java эффективно и предсказуемо обрабатывать вызовы методов!
🎓 Надеюсь, это было полезно! Оставьте свои вопросы, лайки и комментарии ниже. 👇
#Java #Программирование #CodingTips #JavaTips #java_interview_tasks
1👍23🔥5❤3
🔍 Ответ на задачу про распределение монет по кошелькам
⚠️Это задача на метод stars&bars. если в условии есть упоминание, что кошельки не должны быть пустыми, то нам нужно заранее положить по одной монетке в каждый кошелек (иначе в ответе будут случаи, где некоторые кошельки пустые): 12 - 5 = 7
⚠️Теперь мы имеем 7 монет которые нужно распределить в 5 кошельков. Для этого возьмем 4 перегордки, (они поделят наши монетки на 5 частей("кошельков")). Выглядит пример так: 💰|💰💰|💰 |💰💰|💰
⚠️В общей сумме имеем 7+4 = 11 позиций, в котором нужно рассчитать количество перестановок перегородок, а это C(4 ; 11) = (11×10×9×8)/4×3×2×1 = 330
Ответ: 330 способов
🚀Если вам понравилось это объяснение, ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях!
🚀🚀 Если хотите больше таких задач ставьте 🔥 к этому посту.
#Combinations #Combinatorics #MathChallenge #java_interview_tasks
⚠️Это задача на метод stars&bars. если в условии есть упоминание, что кошельки не должны быть пустыми, то нам нужно заранее положить по одной монетке в каждый кошелек (иначе в ответе будут случаи, где некоторые кошельки пустые): 12 - 5 = 7
⚠️Теперь мы имеем 7 монет которые нужно распределить в 5 кошельков. Для этого возьмем 4 перегордки, (они поделят наши монетки на 5 частей("кошельков")). Выглядит пример так: 💰|💰💰|💰 |💰💰|💰
⚠️В общей сумме имеем 7+4 = 11 позиций, в котором нужно рассчитать количество перестановок перегородок, а это C(4 ; 11) = (11×10×9×8)/4×3×2×1 = 330
Ответ: 330 способов
🚀Если вам понравилось это объяснение, ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях!
🚀🚀 Если хотите больше таких задач ставьте 🔥 к этому посту.
#Combinations #Combinatorics #MathChallenge #java_interview_tasks
👍12🔥3❤2👎1
🔍 Ответ на задачу про то, как Java выбирает перегрузку метода с null?
В Java, когда вы вызываете перегруженный метод с аргументом null, компилятор должен решить, какую версию метода использовать. Давайте разберём конкретный пример с вызовом printFor(null).
👉 Как компилятор принимает решение?
👉👉Когда мы передаём null как аргумент, Java ищет наиболее специфичный метод, который может быть вызван. В этом конкретном случае, null может быть преобразован как в String, так и в Object, поскольку String является подтипом (наследником) Object.
👉👉Специфичность типа: Согласно правилам Java, если возможны несколько перегруженных методов, компилятор выбирает тот, чьё требование более специфично. Поскольку String является более специфичной версией Object, метод printFor(String o) будет выбран.
🔗 В итоге, когда вызывается printFor(null), на консоль будет выведено "String".
Такие правила выбора метода помогают Java обрабатывать вызовы предсказуемо и логично, даже с неопределёнными значениями, как null!
🎓 Надеюсь, это было полезно! Оставьте свои вопросы, лайки и комментарии ниже. 👇
#Java #Программирование #CodingTips #JavaTips #java_interview_tasks
В Java, когда вы вызываете перегруженный метод с аргументом null, компилятор должен решить, какую версию метода использовать. Давайте разберём конкретный пример с вызовом printFor(null).
👉 Как компилятор принимает решение?
👉👉Когда мы передаём null как аргумент, Java ищет наиболее специфичный метод, который может быть вызван. В этом конкретном случае, null может быть преобразован как в String, так и в Object, поскольку String является подтипом (наследником) Object.
👉👉Специфичность типа: Согласно правилам Java, если возможны несколько перегруженных методов, компилятор выбирает тот, чьё требование более специфично. Поскольку String является более специфичной версией Object, метод printFor(String o) будет выбран.
🔗 В итоге, когда вызывается printFor(null), на консоль будет выведено "String".
Такие правила выбора метода помогают Java обрабатывать вызовы предсказуемо и логично, даже с неопределёнными значениями, как null!
🎓 Надеюсь, это было полезно! Оставьте свои вопросы, лайки и комментарии ниже. 👇
#Java #Программирование #CodingTips #JavaTips #java_interview_tasks
🔥18👍6⚡1❤1👏1🐳1
🔍 Ответ на задачу о ConcurrentHashMap и атомарности
Одно из часто обсуждаемых свойств ConcurrentHashMap — это ее потокобезопасность в отношении методов put и get. ConcurrentHashMap гарантирует атомарность операций put и get, что значит, что каждое из этих действий выполняется полностью или не выполняется вовсе, и они могут безопасно выполняться одновременно из разных потоков.
⚡️Однако важно помнить, что эта гарантия распространяется только на сами операции put и get, но не на атомарность действий по отношению к вложенным объектам. В нашем случае, если мы извлекаем список из мапы и затем изменяем его, эти изменения не защищены от состояния гонки. Как было показано в предыдущей задаче, два потока могут создать и модифицировать один и тот же список, приводя к непредсказуемым результатам.
⚡️⚡️Поэтому при работе с ConcurrentHashMap, когда объекты, хранящиеся в мапе, также должны быть потокобезопасными, следует дополнительно обеспечивать синхронизацию либо использовать другие потокобезопасные структуры данных.
👉 Чтобы решить проблему, можно воспользоваться несколькими подходами. Вот некоторые из них:
/*
Solves the race with putIfAbsent
*/
/*
Solves the race with computeIfAbsent.
*/
🎓 Понравилась тема про потокобезопасность в Java? Ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях!
#ConcurrentHashMap #Java #Concurrency #Atomicity #java_interview_tasks
Одно из часто обсуждаемых свойств ConcurrentHashMap — это ее потокобезопасность в отношении методов put и get. ConcurrentHashMap гарантирует атомарность операций put и get, что значит, что каждое из этих действий выполняется полностью или не выполняется вовсе, и они могут безопасно выполняться одновременно из разных потоков.
⚡️Однако важно помнить, что эта гарантия распространяется только на сами операции put и get, но не на атомарность действий по отношению к вложенным объектам. В нашем случае, если мы извлекаем список из мапы и затем изменяем его, эти изменения не защищены от состояния гонки. Как было показано в предыдущей задаче, два потока могут создать и модифицировать один и тот же список, приводя к непредсказуемым результатам.
⚡️⚡️Поэтому при работе с ConcurrentHashMap, когда объекты, хранящиеся в мапе, также должны быть потокобезопасными, следует дополнительно обеспечивать синхронизацию либо использовать другие потокобезопасные структуры данных.
👉 Чтобы решить проблему, можно воспользоваться несколькими подходами. Вот некоторые из них:
/*
Solves the race with putIfAbsent
*/
void addCorrect(String key, String val) {
List<String> list = map.get(key);
if (list == null) {
list = Collections.synchronizedList(new ArrayList<>());
List<String> exist = map.putIfAbsent(key, list);
if (exist != null) {
list = exist;
}
}
list.add(val);
}
/*
Solves the race with computeIfAbsent.
*/
void addCorrect8(String key, String val) {
List<String> list = map.computeIfAbsent(key,
k -> Collections.synchronizedList(new ArrayList<>()));
list.add(val);
}
🎓 Понравилась тема про потокобезопасность в Java? Ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях!
#ConcurrentHashMap #Java #Concurrency #Atomicity #java_interview_tasks
👍19🔥4❤2👏1
🔍 Ответ на задачу про checkThenReact и состояние гонки:
В этом примере метода checkThenReact() описывается ситуация типичной проблемы конкурентного программирования, известной как "состояние гонки". Суть проблемы заключается в том, что несколько потоков (в данном случае actor1() и actor2()) могут одновременно проверить и изменить общее состояние, здесь представляемое переменной flag.
Возможные решения для устранения состояния гонки:
Синхронизация:
Заключите операцию проверки и изменения flag в блок синхронизации:
Использование AtomicBoolean:
Замена boolean на AtomicBoolean и использование атомарных операций. Например:
Эти подходы помогут устранить логическую проблему и гарантировать, что только один поток сможет изменить состояние flag в одно и то же время.
🎓Если вам интересны темы конкурентности и потокобезопасности, ставьте лайк, подписывайтесь и оставляйте комментарии с вашими вопросами и переживаниями!
#Concurrency #RaceCondition #Synchronization #AtomicOperations #java_interview_tasks
В этом примере метода checkThenReact() описывается ситуация типичной проблемы конкурентного программирования, известной как "состояние гонки". Суть проблемы заключается в том, что несколько потоков (в данном случае actor1() и actor2()) могут одновременно проверить и изменить общее состояние, здесь представляемое переменной flag.
Возможные решения для устранения состояния гонки:
Синхронизация:
Заключите операцию проверки и изменения flag в блок синхронизации:
private synchronized boolean checkThenReact() {
if (flag) {
flag = false;
return true;
} else {
return false;
}
}
Использование AtomicBoolean:
Замена boolean на AtomicBoolean и использование атомарных операций. Например:
private final AtomicBoolean flag = new AtomicBoolean(true);
private boolean checkThenReact() {
return flag.compareAndSet(true, false);
}
Эти подходы помогут устранить логическую проблему и гарантировать, что только один поток сможет изменить состояние flag в одно и то же время.
🎓Если вам интересны темы конкурентности и потокобезопасности, ставьте лайк, подписывайтесь и оставляйте комментарии с вашими вопросами и переживаниями!
#Concurrency #RaceCondition #Synchronization #AtomicOperations #java_interview_tasks
Telegram
Java Interview Tasks
Что может напечатать код? (методы actor1 и actor2 запускаются параллельно в разных тредах)
👍16🔥3❤1👌1
🔍 Ответ на задачу про JMM и особенности volatile полей
Данная задача подчеркивает одно из потенциально неожиданных поведений модели памяти Java (Java Memory Model - JMM), связанное с volatile полями. Конкретно, она касается разницы между volatile и final в контексте гарантий видимости и порядка инициализации.
⚠️ Ключевые моменты volatilе и final:
⚡️⚡️volatile гарантирует видимость изменений в переменной между потоками. Однако оно не гарантирует, что инициализация объекта до первой публикации будет выполнена полностью.
⚡️⚡️final гарантирует, что значение поля после его инициализации не изменяется, и другие потоки, получившие ссылку на объект, увидят окончательное (полностью инициализированное) состояние этого поля.
Проблема рваной публикации:
⚠️ Когда объект создается и его ссылка передается (опубликована) другим потокам, инициализация объекта может еще быть не завершена. В этом случае другие потоки могут видеть содержимое объекта в промежуточном состоянии. Это и есть суть "рваной" (racy) публикации.
Поведение volatile поля:
Если volatile поле объекта не было полностью инициализировано на момент, когда ссылка на объект становится видимой другим потокам, то впоследствии эти потоки могут наблюдать значение по умолчанию (например, 0 для примитивных типов).
⚠️ В коде выше делается следующее:
Объект Holder создается, и volatile поле x инициализируется в конструкторе.
Ссылка на объект публикуется в переменной h, которая не является volatile.
Второй поток считывает h и проверяет значение x.
Из-за отсутствия синхронизации (например, volatile для h), есть возможность, что thread2 увидит переменную h как не-null, но значение x еще не инициализированное, в результате чего оно может быть равно 0.
⚠️⚠️ Чтобы избежать подобных проблем:
Используйте final для полей, которые должны быть инициализированы полностью до публикации объекта. Это гарантирует, что другие потоки увидят полностью инициализированный объект.
Синхронизируйте публикацию объектов, чтобы гарантировать видимость полной инициализации.
Рассмотрите использование volatile для ссылочных переменных, через которые публикуются объекты, чтобы гарантировать полноценную инициализацию до публикации.
🎓 Если вы нашли это обсуждение полезным, ставьте лайк, подписывайтесь и делитесь своими мыслями в комментариях!
#JavaMemoryModel #VolatileFields #FinalFields #Synchronization #java_interview_tasks
Данная задача подчеркивает одно из потенциально неожиданных поведений модели памяти Java (Java Memory Model - JMM), связанное с volatile полями. Конкретно, она касается разницы между volatile и final в контексте гарантий видимости и порядка инициализации.
⚠️ Ключевые моменты volatilе и final:
⚡️⚡️volatile гарантирует видимость изменений в переменной между потоками. Однако оно не гарантирует, что инициализация объекта до первой публикации будет выполнена полностью.
⚡️⚡️final гарантирует, что значение поля после его инициализации не изменяется, и другие потоки, получившие ссылку на объект, увидят окончательное (полностью инициализированное) состояние этого поля.
Проблема рваной публикации:
⚠️ Когда объект создается и его ссылка передается (опубликована) другим потокам, инициализация объекта может еще быть не завершена. В этом случае другие потоки могут видеть содержимое объекта в промежуточном состоянии. Это и есть суть "рваной" (racy) публикации.
Поведение volatile поля:
Если volatile поле объекта не было полностью инициализировано на момент, когда ссылка на объект становится видимой другим потокам, то впоследствии эти потоки могут наблюдать значение по умолчанию (например, 0 для примитивных типов).
⚠️ В коде выше делается следующее:
Объект Holder создается, и volatile поле x инициализируется в конструкторе.
Ссылка на объект публикуется в переменной h, которая не является volatile.
Второй поток считывает h и проверяет значение x.
Из-за отсутствия синхронизации (например, volatile для h), есть возможность, что thread2 увидит переменную h как не-null, но значение x еще не инициализированное, в результате чего оно может быть равно 0.
⚠️⚠️ Чтобы избежать подобных проблем:
Используйте final для полей, которые должны быть инициализированы полностью до публикации объекта. Это гарантирует, что другие потоки увидят полностью инициализированный объект.
Синхронизируйте публикацию объектов, чтобы гарантировать видимость полной инициализации.
Рассмотрите использование volatile для ссылочных переменных, через которые публикуются объекты, чтобы гарантировать полноценную инициализацию до публикации.
🎓 Если вы нашли это обсуждение полезным, ставьте лайк, подписывайтесь и делитесь своими мыслями в комментариях!
#JavaMemoryModel #VolatileFields #FinalFields #Synchronization #java_interview_tasks
🔥13👍4❤1🐳1
🔍 Ответ на задачу про использование BigInteger в Java:
❓Что напечатает данный код?
🤔 На первый взгляд, можно подумать, что он выведет сумму всех значений, но реальный результат будет 0;
Почему так? 🤔
Методы класса BigInteger, как например add(), не изменяют текущее значение объекта, а возвращают новый объект с результатом операции. Таким образом, запись total.add(BigInteger) не изменяет значение total. Поэтому для получения суммы необходимо сделать следующее:
total = total.add(oneThousand);
total = total.add(twoThousand);
total = total.add(threeThousand);
total = total.add(fourThousand);
Теперь всё должно работать как положено! 💡 Не забывайте про это, когда работаете с неизменяемыми объектами, такими как BigInteger.
Если вам понравился этот разбор, поставьте лайк, подпишитесь и оставьте комментарий! 🤗
#Java #BigInteger #иммутабельность #сумма #java_interview_tasks
❓Что напечатает данный код?
🤔 На первый взгляд, можно подумать, что он выведет сумму всех значений, но реальный результат будет 0;
Почему так? 🤔
Методы класса BigInteger, как например add(), не изменяют текущее значение объекта, а возвращают новый объект с результатом операции. Таким образом, запись total.add(BigInteger) не изменяет значение total. Поэтому для получения суммы необходимо сделать следующее:
total = total.add(oneThousand);
total = total.add(twoThousand);
total = total.add(threeThousand);
total = total.add(fourThousand);
Теперь всё должно работать как положено! 💡 Не забывайте про это, когда работаете с неизменяемыми объектами, такими как BigInteger.
Если вам понравился этот разбор, поставьте лайк, подпишитесь и оставьте комментарий! 🤗
#Java #BigInteger #иммутабельность #сумма #java_interview_tasks
👍17🔥3⚡2🤡2
🔍 Ответ на вопрос про использование var в Java:
Все больше и больше в коде начали использовать var .
🤔 Давайте разберем плюсы и минусы его использования.
📌 Плюсы var:
✔️ Меньше "визуального шума": избавляет от длинных и громоздких объявлений.
✔️ Удобно при работе с дженериками и вложенными типами: никакого лишнего написания.
✔️ Код читается проще, когда тип очевиден из правой части.
Примеры, когда var выглядит отлично:
var map = new HashMap<String, List<Long>>();
var name = "LinkedIn";
var count = 42;
⚠️ Минусы var:
❌ Иногда теряется читаемость: особенно, когда возвращаемый тип не очевиден.
❌ Может прятать неожиданные типы, что усложняет отладку.
❌ Не подходит для публичных API / сигнатур, где тип данных должен быть явно указан.
Когда var может стать врагом:
var data = process(); // Непонятно, что за тип возвращается.
var a = someObj.getValue().getAnother().resolve(); // Много уровней вложенности.
📌 Мой вывод: var — это отличный инструмент, но важно знать, когда и как его использовать. Лично я применяю var, когда тип очевиден без догадок. Если нужно вчитываться или полагаться на IDE, лучше указать тип явно. Помните, что читаемость важнее краткости! 💡
Согласны с таким подходом? Или у вас есть свои мысли? Делитесь в комментариях, подписывайтесь и ставьте лайк! 🤗
#Java #var #кодстайл #java10 #java_interview_tasks
Все больше и больше в коде начали использовать var .
🤔 Давайте разберем плюсы и минусы его использования.
📌 Плюсы var:
✔️ Меньше "визуального шума": избавляет от длинных и громоздких объявлений.
✔️ Удобно при работе с дженериками и вложенными типами: никакого лишнего написания.
✔️ Код читается проще, когда тип очевиден из правой части.
Примеры, когда var выглядит отлично:
var map = new HashMap<String, List<Long>>();
var name = "LinkedIn";
var count = 42;
⚠️ Минусы var:
❌ Иногда теряется читаемость: особенно, когда возвращаемый тип не очевиден.
❌ Может прятать неожиданные типы, что усложняет отладку.
❌ Не подходит для публичных API / сигнатур, где тип данных должен быть явно указан.
Когда var может стать врагом:
var data = process(); // Непонятно, что за тип возвращается.
var a = someObj.getValue().getAnother().resolve(); // Много уровней вложенности.
📌 Мой вывод: var — это отличный инструмент, но важно знать, когда и как его использовать. Лично я применяю var, когда тип очевиден без догадок. Если нужно вчитываться или полагаться на IDE, лучше указать тип явно. Помните, что читаемость важнее краткости! 💡
Согласны с таким подходом? Или у вас есть свои мысли? Делитесь в комментариях, подписывайтесь и ставьте лайк! 🤗
#Java #var #кодстайл #java10 #java_interview_tasks
👍14❤3❤🔥1👎1🔥1🙏1
🔍 Ответ на задачу про порядок выполнения операций в Java:
Давайте посмотрим, что напечатает следующий код:
❓Что произойдёт при выполнении этого кода?
🧐 Важный момент — это порядок выполнения операций и вычислений.
Вначале вызывается int1(), который печатает 1 и возвращает 1.
Затем в правой части выполняется int2() * int3().
int2() печатает 2 и возвращает 2.
int3() печатает 3 и возвращает 3.
Происходит умножение (2 * 3 = 6).
Наконец, результат сложения: 1 + 6 = 7.
Итак, итоговый вывод будет:
1237
Первые три цифры — это значения, возвращаемые методами, а 7 — результат вычисления выражения. 🔢
Если вам интересны подобные разборы, ставьте лайк, не забывайте подписаться и оставлять свои комментарии! 🤗
#Java #порядок_выполнения #вычисления #java_interview_tasks
Давайте посмотрим, что напечатает следующий код:
public static void main(String[] args) {
System.out.print(int1() + int2() * int3());
}
private static int int1() {
System.out.print(1);
return 1;
}
private static int int2() {
System.out.print(2);
return 2;
}
private static int int3() {
System.out.print(3);
return 3;
}
❓Что произойдёт при выполнении этого кода?
🧐 Важный момент — это порядок выполнения операций и вычислений.
Вначале вызывается int1(), который печатает 1 и возвращает 1.
Затем в правой части выполняется int2() * int3().
int2() печатает 2 и возвращает 2.
int3() печатает 3 и возвращает 3.
Происходит умножение (2 * 3 = 6).
Наконец, результат сложения: 1 + 6 = 7.
Итак, итоговый вывод будет:
1237
Первые три цифры — это значения, возвращаемые методами, а 7 — результат вычисления выражения. 🔢
Если вам интересны подобные разборы, ставьте лайк, не забывайте подписаться и оставлять свои комментарии! 🤗
#Java #порядок_выполнения #вычисления #java_interview_tasks
👍27🔥3❤2🙏2
🔍 Ответ на задачу про передачу примитивов в методы в Java
Давайте рассмотрим, что произойдёт при выполнении этого кода:
❓Чего ожидать от вывода?
🔎 В Java при передаче примитивных типов (таких как int) в методы используется передача по значению. Это означает, что в метод inc передаётся копия значения count, а не сама переменная. Таким образом, любые изменения над параметром count в методе inc не влияют на переменную count в методе main.
🌟 Вот шаги выполнения:
В main у нас переменная count равна 123.
Мы вызываем метод inc(count), передавая копию значения count.
В методе inc эта копия увеличивается на 1, но никак не затрагивает оригинальную переменную в main.
Поэтому System.out.println(count); выведет оригинальное значение: 123
🔗 Это пример важной концепции в Java — примитивы передаются по значению, и изменения не сохраняются вне метода. Помните об этом при проектировании ваших программ!
⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️
🔍 Ответ на задачу про неизменяемость объектов в Java
Здесь у нас код, который работает с неизменяемостью объектов в Java:
❓Что выведет этот код?
🤔 Давайте разберёмся. На первый взгляд могло бы показаться, что после вызова метода inc count увеличится. Но это не так.
🔸 Тип Integer — это неизменяемый объект в Java. Кроме того, при передаче в метод inc, создаётся копия ссылки, а не передача по ссылке, как в некоторых других языках.
🔸 Метод count++ использует count локально, создавая новый объект Integer, но не изменяет оригинальный объект count в main.
Таким образом, System.out.println(count); напечатает: 123
😯 Не забывайте об этих особенностях при работе с объектами! Если у вас есть мысли или вопросы, делитесь ими в комментариях! Подписывайтесь и ставьте лайк, чтобы не пропустить новые посты! 🤗
#Java #неизменяемость #Integer #java_interview_tasks
Давайте рассмотрим, что произойдёт при выполнении этого кода:
public static void main(String[] args) {
int count = 123;
inc(count);
System.out.println(count);
}
private static void inc(int count) {
count++;
}
❓Чего ожидать от вывода?
🔎 В Java при передаче примитивных типов (таких как int) в методы используется передача по значению. Это означает, что в метод inc передаётся копия значения count, а не сама переменная. Таким образом, любые изменения над параметром count в методе inc не влияют на переменную count в методе main.
🌟 Вот шаги выполнения:
В main у нас переменная count равна 123.
Мы вызываем метод inc(count), передавая копию значения count.
В методе inc эта копия увеличивается на 1, но никак не затрагивает оригинальную переменную в main.
Поэтому System.out.println(count); выведет оригинальное значение: 123
🔗 Это пример важной концепции в Java — примитивы передаются по значению, и изменения не сохраняются вне метода. Помните об этом при проектировании ваших программ!
⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️⚡️
🔍 Ответ на задачу про неизменяемость объектов в Java
Здесь у нас код, который работает с неизменяемостью объектов в Java:
public static void main(String[] args) {
Integer count = 123;
inc(count);
System.out.println(count);
}
private static void inc(Integer count) {
count++;
}
❓Что выведет этот код?
🤔 Давайте разберёмся. На первый взгляд могло бы показаться, что после вызова метода inc count увеличится. Но это не так.
🔸 Тип Integer — это неизменяемый объект в Java. Кроме того, при передаче в метод inc, создаётся копия ссылки, а не передача по ссылке, как в некоторых других языках.
🔸 Метод count++ использует count локально, создавая новый объект Integer, но не изменяет оригинальный объект count в main.
Таким образом, System.out.println(count); напечатает: 123
😯 Не забывайте об этих особенностях при работе с объектами! Если у вас есть мысли или вопросы, делитесь ими в комментариях! Подписывайтесь и ставьте лайк, чтобы не пропустить новые посты! 🤗
#Java #неизменяемость #Integer #java_interview_tasks
🔥11👍3😨2❤1🐳1
🔍 Ответ на задачу про 6-значные числа и четные цифры:
Вместо подсчёта количества шестизначных чисел, в записи которых есть хотя бы одна чётная цифра, можно посчитать количество шестизначных чисел не обладающих данным свойством, то есть тех, в записи которых встречаются только нечётные цифры. Таких чисел:
5⁶ = (5³)² = 125² =
12·13·100 + 25 =
15625.
Всего же шестизначных чисел:
999 999 - 99 999 =
900 000.
Значит количество шестизначных чисел, обладающих указанным свойством, ровно:
900 000 - 15 625 =
884 375.
🚀Если вам понравилось это объяснение, ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях!
🚀🚀 Если хотите больше таких задач ставьте 🔥 к этому посту.
#MathChallenge #Combinatorics #java_interview_tasks
Вместо подсчёта количества шестизначных чисел, в записи которых есть хотя бы одна чётная цифра, можно посчитать количество шестизначных чисел не обладающих данным свойством, то есть тех, в записи которых встречаются только нечётные цифры. Таких чисел:
5⁶ = (5³)² = 125² =
12·13·100 + 25 =
15625.
Всего же шестизначных чисел:
999 999 - 99 999 =
900 000.
Значит количество шестизначных чисел, обладающих указанным свойством, ровно:
900 000 - 15 625 =
884 375.
🚀Если вам понравилось это объяснение, ставьте лайк, подписывайтесь на канал и делитесь своими мыслями в комментариях!
🚀🚀 Если хотите больше таких задач ставьте 🔥 к этому посту.
#MathChallenge #Combinatorics #java_interview_tasks
🔥10👍4⚡2🤮2🐳1
🔍 Ответ на задачу про вывод элементов списка
Тут есть одна особенность: индекс увеличивается до получения элемента из списка благодаря ++index.
При таком подходе, цикл начинает с индексом 1, а значит будет выбирать имена начиная с "Боря", а "Аня" будет пропущена. Значение index будет увеличено на 1, после чего произойдет проверка условия index < names.size(), и условие будет истинным до тех пор, пока индекс не станет равен размеру списка.
Таким образом, в результате выполнение кода мы увидим такой вывод на консоли:
Боря
Вова
А дальше будет эксепшен, так как следующего индекса в массиве уже нет.
🥳 Надеюсь, этот разбор был полезен! Не забудьте лайкнуть пост, подписаться на канал и оставить комментарий, если у вас есть вопросы или дополнения!
#java #coding #++i #java_interview_tasks
Тут есть одна особенность: индекс увеличивается до получения элемента из списка благодаря ++index.
При таком подходе, цикл начинает с индексом 1, а значит будет выбирать имена начиная с "Боря", а "Аня" будет пропущена. Значение index будет увеличено на 1, после чего произойдет проверка условия index < names.size(), и условие будет истинным до тех пор, пока индекс не станет равен размеру списка.
Таким образом, в результате выполнение кода мы увидим такой вывод на консоли:
Боря
Вова
А дальше будет эксепшен, так как следующего индекса в массиве уже нет.
🥳 Надеюсь, этот разбор был полезен! Не забудьте лайкнуть пост, подписаться на канал и оставить комментарий, если у вас есть вопросы или дополнения!
#java #coding #++i #java_interview_tasks
👍15🔥2🐳2❤1
🔍 Ответ на задачу про логические операторы
Давайте разберем работу логических операторов в данном коде на Java. У нас есть три логические переменные: a, b, и c, со значениями true, false, и false соответственно. В условии if используется комбинация операторов (логическое "ИЛИ") и && (логическое "И").
Стоит помнить, что оператор && имеет более высокий приоритет, чем оператор . Поэтому выражение b && c будет вычислено первым. Но поскольку b равно false, а c также false, это выражение дает в результате false.
Далее, выражение a false будет всегда истинным, так как a равно true. Следовательно, полное условие в if равно true, и будет выполнена первая ветка блока:
1
Когда дело касается вложенных логических операторов в условных выражениях, расстановка скобок может значительно упростить понимание кода и избежать путаницы. В данном случае, добавим скобки для ясности:
Скобки вокруг выражения (b && c) четко определяют, что это будет вычислено в первую очередь. Это не только делает код более понятным, но и исключает возможность неправильной интерпретации, особенно если у вас большой и сложный условный оператор.
Используйте скобки в логических выражениях, чтобы код был читаемым как для вас, так и для вашей команды! Рекомендуется всегда группировать логические операции скобками, если существует вероятность появления неоднозначности.
✍️ Научитесь писать чистый и понятный код! Поддержите эту идею, поставив лайк, подписывайтесь на канал и оставляйте комментарии с вашими мыслями об использовании скобок в коде.
#java #logicaloperators #boolean #clean_code #java_interview_tasks
Давайте разберем работу логических операторов в данном коде на Java. У нас есть три логические переменные: a, b, и c, со значениями true, false, и false соответственно. В условии if используется комбинация операторов (логическое "ИЛИ") и && (логическое "И").
Стоит помнить, что оператор && имеет более высокий приоритет, чем оператор . Поэтому выражение b && c будет вычислено первым. Но поскольку b равно false, а c также false, это выражение дает в результате false.
Далее, выражение a false будет всегда истинным, так как a равно true. Следовательно, полное условие в if равно true, и будет выполнена первая ветка блока:
1
Когда дело касается вложенных логических операторов в условных выражениях, расстановка скобок может значительно упростить понимание кода и избежать путаницы. В данном случае, добавим скобки для ясности:
boolean a = true;
boolean b = false;
boolean c = false;
if (a || (b && c)) {
System.out.println("1");
} else {
System.out.println("2");
}
Скобки вокруг выражения (b && c) четко определяют, что это будет вычислено в первую очередь. Это не только делает код более понятным, но и исключает возможность неправильной интерпретации, особенно если у вас большой и сложный условный оператор.
Используйте скобки в логических выражениях, чтобы код был читаемым как для вас, так и для вашей команды! Рекомендуется всегда группировать логические операции скобками, если существует вероятность появления неоднозначности.
✍️ Научитесь писать чистый и понятный код! Поддержите эту идею, поставив лайк, подписывайтесь на канал и оставляйте комментарии с вашими мыслями об использовании скобок в коде.
#java #logicaloperators #boolean #clean_code #java_interview_tasks
🔥8👍5❤2
Forwarded from Верхняя полка📝
Наверняка эта задачка входит в число хрестоматийных и встречается на собеседованиях по #Java, но поскольку я по ним не хожу, пришлось убить часок на разбирательство с ней. Поделюсь с вами; вдруг кто-то тоже встретит.
🎓 Дано
Ванильный пул потоков на голом JDK (аналоги из класса
И некий метод, который сначала просто напихивает задачки в этот пул:
, потом идёт по своим делам, а когда заканчивает с ними, проверяет готовность задачек и, если надо, дожидается завершения каждой, чтобы продолжить работу дальше:
🔍 Найти
Какого _🙊_ в некоторых случаях метод намертво зависает на вызове
При этом в дампе потоков нет никаких следов задач, которые бы зависли/зациклились/заблокированы.
🔑 Решение
Вариант 1. Добавить таймаут в метод
Вариант 2. Извернуться как-нибудь так, чтобы прийти к вызову вида
Вариант 3. Обернуть вызов
Казалось бы, смысла в нём нет, ведь если задача не завершена (
, то есть "сделанной" считается любая не новая задача (в том числе когда она ещё в работе).
А метод
, то есть ожидание наступит для любого состояния, предшествующего завершению, в том числе для вышеупомянутого
Но если бы задача, на которой завис наш поток, была в состоянии
А как она могла оказаться
✅ Вся цепочка кратко:
— не влезающие в очередь задачи молча отбрасываются политикой пула, оставляя им статус
— видя этот статус, метод
— исключить ожидание можно добавлением проверки на
⚠️ Если очередь будет большой, а задачи — долгоиграющими, можно нарваться на случай, когда задача уже в очереди и имеет шанс быть выполненной, но цикл с вызовом
Мораль: пишите однопоточные приложения🤪
🎓 Дано
Ванильный пул потоков на голом JDK (аналоги из класса
Executors
не подходят):var threadPool = new ThreadPoolExecutor(
corePoolSize, // 3
maxPoolSize, // 30
keepAliveTime, // 60
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(maxQueueLength), // 100
Executors.defaultThreadFactory(),
new DiscardPolicy()); // could also be a logging implementation
И некий метод, который сначала просто напихивает задачки в этот пул:
List<Future> futures = new ArrayList<>();
futures.add(threadPool.submit(task));
, потом идёт по своим делам, а когда заканчивает с ними, проверяет готовность задачек и, если надо, дожидается завершения каждой, чтобы продолжить работу дальше:
for (Future future : futures) {
try {
future.get();
}
catch (Exception e) {
log.error("Failed to get task result from future", e);
}
}
🔍 Найти
Какого _🙊_ в некоторых случаях метод намертво зависает на вызове
future.get()
?При этом в дампе потоков нет никаких следов задач, которые бы зависли/зациклились/заблокированы.
🔑 Решение
Вариант 1. Добавить таймаут в метод
future.get()
. Да, это решит проблему, но не даст понять, почему она появилась.Вариант 2. Извернуться как-нибудь так, чтобы прийти к вызову вида
CompletableFuture.allOf(c1, c2, c3).join()
. Наверняка так можно (не проверял), но выглядит избыточно сложно, должно же работать и так.Вариант 3. Обернуть вызов
future.get()
вот в такое условие:if (future.isDone()) {
future.get();
}
Казалось бы, смысла в нём нет, ведь если задача не завершена (
isDone() == false
), то мы просто дождёмся её завершения при вызове get()
. Но нет. Когда мы имеем дело с ThreadPoolExecutor
, то при вызове submit()
он в качестве имплементации Future
возвращает экземпляр FutureTask
, у которого метод isDone()
выглядит так:public boolean isDone() {
return state != NEW;
}
, то есть "сделанной" считается любая не новая задача (в том числе когда она ещё в работе).
А метод
FutureTask.get()
устроен так:public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
, то есть ожидание наступит для любого состояния, предшествующего завершению, в том числе для вышеупомянутого
NEW
(на самом деле только для NEW
и COMPLETING
).Но если бы задача, на которой завис наш поток, была в состоянии
COMPLETING
, мы наверняка увидели бы соответствующий ей поток в дампе, а раз его нет, значит, она в NEW
.А как она могла оказаться
NEW
, если все задачи вроде как были переданы пулу на исполнение? Видимо, он её не взял. А почему не взял? Правильно — из-за переполнения очереди, ведь она ограничена (new LinkedBlockingQueue<>(maxQueueLength)
). А почему тогда это не привело к ошибкам и прерыванию всего процесса? Верно, из-за с виду безобидной new DiscardPolicy()
, которая просто дропает не влезшие задачки (и логирует их, как было в нашем случае).✅ Вся цепочка кратко:
— не влезающие в очередь задачи молча отбрасываются политикой пула, оставляя им статус
NEW
;— видя этот статус, метод
future.get()
впадает в бесконечное ожидание;— исключить ожидание можно добавлением проверки на
NEW
в виде вызова future.isDone()
.⚠️ Если очередь будет большой, а задачи — долгоиграющими, можно нарваться на случай, когда задача уже в очереди и имеет шанс быть выполненной, но цикл с вызовом
get()
её не подождёт. В этом случае решение должно быть другим.Мораль: пишите однопоточные приложения🤪
🔥13✍3👍3😁2
🔍 Ответ на задачу про сравнение строк в Java
Давайте разберемся, что напечатает приведённый код! 🚀
Этот код выводит на экран:
true — В первом сравнении (a == b), оба операнда являются строковыми литералами, и компилятор оптимизирует их, так что они указывают на один и тот же объект в строковом пуле.
false — Во втором сравнении (a == d), d создается путем конкатенации на этапе выполнения, из-за чего она не будет указывать на тот же объект в строковом пуле, что и a.
true — В третьем сравнении (a.equals(d)), метод equals сравнивает содержимое строк, а не их ссылки, потому этот результат будет true, так как содержимое одинаково.
Интересно, правда? 😄 Не забудьте, что использование оператора == для сравнения строк может привести к неожиданным результатам. Для проверки эквивалентности строк на уровне содержимого всегда используйте equals. ✅
Ставьте лайк, подписывайтесь на канал и оставляйте комментарии! 💬👉
#Java #StringComparison #ИзучаемJava #java_interview_tasks
Давайте разберемся, что напечатает приведённый код! 🚀
String a = "ab";
String b = "a" + "b";
String c = "a";
String d = c + "b";
System.out.println(a == b);
System.out.println(a == d);
System.out.println(a.equals(d));
Этот код выводит на экран:
true — В первом сравнении (a == b), оба операнда являются строковыми литералами, и компилятор оптимизирует их, так что они указывают на один и тот же объект в строковом пуле.
false — Во втором сравнении (a == d), d создается путем конкатенации на этапе выполнения, из-за чего она не будет указывать на тот же объект в строковом пуле, что и a.
true — В третьем сравнении (a.equals(d)), метод equals сравнивает содержимое строк, а не их ссылки, потому этот результат будет true, так как содержимое одинаково.
Интересно, правда? 😄 Не забудьте, что использование оператора == для сравнения строк может привести к неожиданным результатам. Для проверки эквивалентности строк на уровне содержимого всегда используйте equals. ✅
Ставьте лайк, подписывайтесь на канал и оставляйте комментарии! 💬👉
#Java #StringComparison #ИзучаемJava #java_interview_tasks
👍10❤2🔥2
🔍 Ответ на задачу про исключения в Java
Давайте разберемся, что произойдет при выполнении представленного кода! ⬇️
Рассмотрим выполнение программы по шагам:
"A" будет напечатано, так как это первое действие в блоке try.
Далее происходит деление на ноль (10 / 0), что вызывает ArithmeticException.
Блок catch перехватывает исключение, и "C" выводится на экран.
Блок finally выполняется всегда, независимо от того, поймано ли исключение, таким образом, "D" будет напечатано.
После выполнения всех блоков try-catch-finally программа продолжает выполнение, поэтому "E" также будет напечатано.
Итак, правильная последовательность вывода: A, C, D, E. 🎉
Не забудьте поставить лайк, подписаться на наш канал и оставляйте комментарии! 💬👉
#Java #Исключения #ОбработкаИсключений #java_interview_tasks
Давайте разберемся, что произойдет при выполнении представленного кода! ⬇️
public class ExceptionTest {
public static void main(String[] args) {
try {
System.out.println("A");
int result = 10 / 0; // Здесь возникнет ArithmeticException
System.out.println("B"); // Эта строка не будет выполнена
} catch (ArithmeticException e) {
System.out.println("C");
} finally {
System.out.println("D");
}
System.out.println("E");
}
}
Рассмотрим выполнение программы по шагам:
"A" будет напечатано, так как это первое действие в блоке try.
Далее происходит деление на ноль (10 / 0), что вызывает ArithmeticException.
Блок catch перехватывает исключение, и "C" выводится на экран.
Блок finally выполняется всегда, независимо от того, поймано ли исключение, таким образом, "D" будет напечатано.
После выполнения всех блоков try-catch-finally программа продолжает выполнение, поэтому "E" также будет напечатано.
Итак, правильная последовательность вывода: A, C, D, E. 🎉
Не забудьте поставить лайк, подписаться на наш канал и оставляйте комментарии! 💬👉
#Java #Исключения #ОбработкаИсключений #java_interview_tasks
👍10🔥2🙏1
🔍 Ответ на задачу про работу с многопоточностью в Java
Давайте разберёмся, что происходит при запуске данного кода! 🔍
Объяснение:
thread::start — запускает новый поток, который выполняет переданное лямбда-выражение. В отдельном потоке выводятся значения от 0 до 4. Поток выполняет метод run, и будет выполняться параллельно с основным потоком.
thread::run — здесь метод run вызывается в основном потоке так, как если это был обычный метод, а не в отдельном потоке. Это означает, что в основном потоке без создания нового потока пойдет выполнение того же самого кода ещё раз, так как метод run просто выполняется в потоке, из которого он был вызван.
Следовательно, программа завершится успешным выполнением, и будут выведены две последовательности от 0 до 4. Таким образом, правильный ответ — Код скомпилируется и выполнится, но "thread::run()" будет выполняться в основном потоке.
Эта ситуация — прекрасный пример, демонстрирующий разницу между методами start() и run() в многопоточности. 🌟
Не забудьте поставить лайк, подписаться на канал и оставлять комментарии с вашими идеями и вопросами! 💬👉
#Java #Многопоточность #Concurrency #java_interview_tasks
Давайте разберёмся, что происходит при запуске данного кода! 🔍
public class ThreadTest {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
}
});
thread.start();
thread.run();
}
}
Объяснение:
thread::start — запускает новый поток, который выполняет переданное лямбда-выражение. В отдельном потоке выводятся значения от 0 до 4. Поток выполняет метод run, и будет выполняться параллельно с основным потоком.
thread::run — здесь метод run вызывается в основном потоке так, как если это был обычный метод, а не в отдельном потоке. Это означает, что в основном потоке без создания нового потока пойдет выполнение того же самого кода ещё раз, так как метод run просто выполняется в потоке, из которого он был вызван.
Следовательно, программа завершится успешным выполнением, и будут выведены две последовательности от 0 до 4. Таким образом, правильный ответ — Код скомпилируется и выполнится, но "thread::run()" будет выполняться в основном потоке.
Эта ситуация — прекрасный пример, демонстрирующий разницу между методами start() и run() в многопоточности. 🌟
Не забудьте поставить лайк, подписаться на канал и оставлять комментарии с вашими идеями и вопросами! 💬👉
#Java #Многопоточность #Concurrency #java_interview_tasks
🔥8👍5❤3
🔍 Ответ на задачу про исключение в стримах Java! 🚨
При выполнении данного кода возникнет исключение NullPointerException.
Давайте разберём, почему это происходит. 🤔
Код:
Проблема возникает в строчке findFirst(). Метод .map(Fee::getDescription) создаёт стрим, где первый элемент имеет значение null из-за description равного null в объекте Fee.
Когда findFirst() пытается вернуть найденное значение — а это null — метод Optional.of() выбрасывает NullPointerException, поскольку Optional.of() не позволяет обёртывать null значениями. Для обработки null значений нужно использовать Optional.ofNullable().
Чтобы исправить это и избежать исключения, можно немного изменить этот код:
String s = fees.stream()
.map(Fee::getDescription)
.filter(Objects::nonNull) // добавляем этот фильтр
.findFirst()
.orElse("1");
Этот код сначала фильтрует все null значения из стрима и предотвращает NullPointerException.
Если вам понравился разбор, не забудьте поставить лайк, подписаться и оставить комментарий! 😊
#streamAPI #nullHandling #java_interview_tasks
При выполнении данного кода возникнет исключение NullPointerException.
Давайте разберём, почему это происходит. 🤔
Код:
public static class Fee {
private String description;
public Fee(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
public static void main(String[] args) {
List<Fee> fees = List.of(new Fee(null));
String s = fees.stream()
.map(Fee::getDescription)
.findFirst()
.orElse("1");
System.out.println(s);
}
Проблема возникает в строчке findFirst(). Метод .map(Fee::getDescription) создаёт стрим, где первый элемент имеет значение null из-за description равного null в объекте Fee.
Когда findFirst() пытается вернуть найденное значение — а это null — метод Optional.of() выбрасывает NullPointerException, поскольку Optional.of() не позволяет обёртывать null значениями. Для обработки null значений нужно использовать Optional.ofNullable().
Чтобы исправить это и избежать исключения, можно немного изменить этот код:
String s = fees.stream()
.map(Fee::getDescription)
.filter(Objects::nonNull) // добавляем этот фильтр
.findFirst()
.orElse("1");
Этот код сначала фильтрует все null значения из стрима и предотвращает NullPointerException.
Если вам понравился разбор, не забудьте поставить лайк, подписаться и оставить комментарий! 😊
#streamAPI #nullHandling #java_interview_tasks
🔥18👍8❤1🤝1