Telegram Web Link
🖥 8 лучших техник программирования в Kotlin

Данная статья предлагает обзор продвинутых техник программирования в Kotlin.

Читать дальше

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Kotlin Flow: лучшие практики

В этой статье вы познакомитесь с лучшими практиками использования Kotlin Flow, включая создание операторов и обработку ошибок.

Не упустите возможность узнать больше о преимуществах этого инструмента и улучшить свои навыки в разработке мобильных приложений:

https://florentblot.medium.com/kotlin-flow-best-practices-ab05e249ec1c

#kotlin
Параллелизм в Java и интерфейс Condition

Благодаря этой статье вы узнаете, как заставить потоки ожидать определенных условий с помощью интерфейса Condition.

Используя Condition, мы можем создавать механизмы, которые позволяют потокам ожидать выполнения определенных условий, прежде чем приступить к их выполнению.

public interface Condition {

void await() throws InterruptedException;

void awaitUninterruptibly();

long awaitNanos(long nanosTimeout) throws InterruptedException;

boolean await(long time, TimeUnit unit) throws InterruptedException;

boolean awaitUntil(Date deadline) throws InterruptedException;

void signal();

void signalAll();
}


Интерфейс Condition связан с интерфейсом Lock. Поток не может взаимодействовать с Condition и его методами, если они не удерживаются с помощью Lock.

Condition использует базовые механизмы Lock. Например, signal и signalAll будет использовать базовую очередь потоков, которые поддерживаются Lock, и уведомит их о пробуждении.

Отличие между этими двумя интерфейсами состоит в том, что реализации Lock представляют собой высокоуровневую альтернативу блока synchronized, а реализации интерфейса Condition – это альтернатива методам notify/wait. Оба этих интерфейса входят в пакет java.util.concurrent.locks.

Одной из очевидных вещей, которые реализуются с помощью Condition, является файл BlockingQueue. Рабочие потоки (worker threads) обрабатывают данные, а потоки-издатели (publisher threads) отправляют данные. Данные публикуются в очереди, рабочие потоки будут обрабатывать данные из очереди, а если данных нет в очереди, то они должны находиться в режиме ожидания.

Для рабочего потока, если условие выполняется, процесс работы выглядит следующим образом:

1. Получить lock.
2. Проверить состояние.
3. Обработать данные.
4. Освободить lock.

Если условие не выполняется, процесс изменится:

Читать дальше

@javatg
🔥 5 фишек Java разработчика

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

1. Гибкость интерфейсов

interface Vehicle {
void start();
void stop();

default void honk() {
System.out.println("Beep beep!");
}
}

class Car implements Vehicle {
@Override
public void start() {
System.out.println("Car started.");
}

@Override
public void stop() {
System.out.println("Car stopped.");
}
}

public class Main {
public static void main(String[] args) {
Car car = new Car();
car.start();
car.stop();
car.honk(); // Использование метода по умолчанию из интерфейса
}
}

2. Обработка исключений

class CustomException extends Exception {
public CustomException(String message) {
super(message);
}
}

public class Main {
public static void main(String[] args) {
try {
// Бросаем исключение CustomException
throw new CustomException("Something went wrong.");
} catch (CustomException e) {
System.out.println("Exception caught: " + e.getMessage());
}
}
}

3. Использование аннотаций

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
String value() default "";
}

public class Main {
@MyAnnotation(value = "Example")
public static void main(String[] args) {
// Получаем аннотацию и выводим значение
MyAnnotation annotation = Main.class.getAnnotation(MyAnnotation.class);
System.out.println("Annotation value: " + annotation.value());
}
}

4. Перечисляемые типы

enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}

public class Main {
public static void main(String[] args) {
Day today = Day.TUESDAY;
System.out.println("Today is " + today);
}
}


5. Лямбда-выражения

import java.util.ArrayList;
import java.util.List;

public class Main {
public static void main(String[] args) {
List<integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);

// Применение лямбда-выражения для удвоения значений списка
numbers.replaceAll(n -> n * 2);

System.out.println(numbers); // Выводит: [2, 4, 6]
}
}



Подробнее

@javatg
💡Задача: "Матрица спирали"

Условие задачи: дан двумерный массив, надо вернуть все его элементы в "спиральном" порядке по часовой стрелке.

Пример:
Ввод:
matrix = [[1,2,3],[4,5,6],[7,8,9]]
Вывод: [1,2,3,6,9,8,7,4,5]

Ввод: matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
Вывод: [1,2,3,4,8,12,11,10,9,5,6,7]

Решение:

class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> answ = new ArrayList<>();
int move[][] = {{0,1},{1,0},{0,-1},{-1,0}};
int x = 0;
int y = -1;
int i = 0;
boolean finish = false;
while (!finish) {
finish = true;
while (true) {
int tmpX = x;
int tmpY = y;
if (x + move[i % 4][0] < matrix.length && x + move[i % 4][0] > -1) x += move[i % 4][0];
if (y + move[i % 4][1] < matrix[0].length && y + move[i % 4][1] > -1) y += move[i % 4][1];
if (x < matrix.length && y < matrix[0].length && matrix[x][y] != -200) {
answ.add(matrix[x][y]);
matrix[x][y] = -200;
finish = false;
}
else {
x = tmpX;
y = tmpY;
break;
}
}
i++;
}
return answ;
}
}


Пишите свое решение в комментариях👇

@javatg
10 полезнейших GitHub-репозиториев для Java-разработчиков

1. Java Design Patterns

2. Interviews

3. Algorithms

4. Realworld

5. Awesome Java

6. Baeldung Tutorials

7. JHipster

8. RxJava Android Samples

9. Java8 Tutorial

10. Cracking the Coding Interview in Java

@javatg
🔥 Выполнение одновременных сетевых запросов в Java: быстро и эффективно

Виртуальные потоки, представленные в Java 19, предназначены для ускорения одновременных сетевых запросов. В данной статье мы сравним пропускную способность обычных и виртуальных потоков, выполняющих HTTP-запросы.

Для этой цели воспользуемся двумя виртуальными машинами в Google Cloud. У каждой из них 8-ядерный процессор и 16 ГБ памяти. Одна машина послужит сервером, а другая — клиентом.

Читать

@javatg
💡Задача: Игра в прыжки

Условие: Вам дан целочисленный массив nums. Изначально вы находитесь в первом индексе массива, и каждый элемент массива представляет максимальную длину прыжка в этой позиции.

Верните true, если вы можете добраться до последнего индекса, или false в противном случае.

Пример:
Ввод: nums = [1,3,1,1,4]
Вывод: true
Объяснение: Переходим на 1 шаг от индекса 0 к 1, затем на 3 шага к последнему индексу.

Ввод: nums = [3,2,1,0,4]
Вывод: false

Решение:

class Solution {
public boolean canJump(int[] nums) {
if(nums[0]==0 && nums.length!=1){
return false;
}
for(int i=1;i<nums.length;i++){
if(i==nums.length-1){
return true;
}
if(nums[i]==0){
int flag=1;
for(int j=i-1;j>=0;j--){
if(nums[j]>flag){
break;
}
if(j==0){
return false;
}
flag++;

}
}
}
return true;
}
}


Пишите свое решение в комментариях👇

@javatg
🖥 Реализации шаблона Singleton, которые вы должны знать

Singleton — это шаблон проектирования в языке Java, который гарантирует, что класс имеет только один экземпляр, и обеспечивает глобальный доступ к этому экземпляру. Синглтоны обычно используются в сценариях, где наличие нескольких экземпляров может привести к непоследовательному или нежелательному поведению.

Ленивая загрузка
Ленивая загрузка (lazy loading) означает, что вы загружаете синглтон только тогда, когда он вам нужен. Иными словами, вы инициируете экземпляр только при вызове getInstance(). То есть, даже если у вас есть другие статические методы в вашем классе Singleton, которые будут, например, загружать конфигурацию, и эти методы используются для запуска вашего приложения, то процесс инициализации все равно ограничен только методом getInstance(). Таким образом, время запуска вашего приложения не будет зависеть от времени загрузки экземпляра.

Ленивая загрузка в классическом синглтоне
Ленивая загрузка обычно используется в классическом синглтоне. Давайте сначала рассмотрим классический класс Singleton, который используется в однопоточном приложении.

Это простой класс, который можно реализовать там, где у нас есть приватный конструктор, и мы можем вызвать getInstance() для инициализации переменной, если она по-прежнему имеет значение null. Результат должен выглядеть так:

public class Singleton {

private static Singleton instance;

private Singleton() {
}

public static Singleton getInstance() {
if(instance == null){
instance = new Singleton();
}
return instance;
}
}


Синхронизированная отложенная загрузка
Синхронизация может быть немного сложной, поскольку здесь мы можем использовать два разных подхода:

1. Синхронизируем весь метод getInstance().
2. Синхронизируем часть метода.

Давайте реализуем код:

public class ThreadSafeSingleton {

private static ThreadSafeSingleton instance;

private ThreadSafeSingleton() {
}

public static synchronized ThreadSafeSingleton getInstance() {
if(instance == null){
Main.waitTime();
Main.waitTime();
instance = new ThreadSafeSingleton();
}
Main.waitTime();
return instance;
}

public static ThreadSafeSingleton getInstanceOptimized() {
if(instance == null){
synchronized (ThreadSafeSingleton.class){
if(instance == null){
Main.waitTime();
Main.waitTime();
instance = new ThreadSafeSingleton();
}
}
}
Main.waitTime();
return instance;
}
}


Читать дальше

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
От Java до Kotlin, или первое впечатление от циклов for

Хотя Kotlin основан на Java, но он имеет множество отличий. Например, стандартные циклы for в Java не будут работать так же эффективно в Kotlin.

Следовательно, было бы полезно разобраться в том, какие отличия между ними существуют и как циклы работают в Kotlin.

https://dev.to/bacongubbe/from-java-to-kotlin-first-impression-on-for-loops-42f8

@javatg
🖥 Понимание различий между методами List.of() и Arrays.asList

List.of() — это фабричный метод, впервые представленный в Java 9, который создает неизменяемый список, содержащий указанные элементы. Вот несколько ключевых моментов, на которые вам следует обратить внимание, изучая List.of():Неизменяемость: полученный список неизменен, то есть его размер и элементы не могут быть изменены после создания.

Фиксированный размер: список, созданный List.of(), имеет фиксированный размер и не поддерживает добавление или удаление элементов.

Нулевые значени: List.of() не допускает нулевых элементов. Если вы попытаетесь добавить null, появится исключение NullPointerException.
Пример использования:

List<String> immutable_list = List.of("apple", "banana", "orange");

Arrays.asList()
Arrays.asList() — это метод, доступный еще в ранних версиях Java, и он предоставляет удобный способ создания изменяемого списка, поддерживаемого массивом.

Рассмотрим его характеристики:

Модифицируемость: полученный из Arrays.asList() список можно модифицировать, что позволяет добавлять, удалять или изменять элементы.

Поддерживается массивом: список поддерживается исходным массивом, поэтому любые изменения в списке влияют на базовый массив и наоборот.

Ограничение фиксированного размера: несмотря на возможность изменения, размер списка, возвращаемого Arrays.asList(), является фиксированным, что предотвращает структурные модификации, такие как добавление или удаление элементов.

Нулевые значения: в отличие от List.of(), Arrays.asList() допускает нулевые элементы.

Пример использования:


List<String> mutable_list = Arrays.asList("red", "green", "blue");

📌 Читать дальше

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача о максимальной сумме подмассива (алгоритм Кадане) на Java
Дан целочисленный массив, найдите в нем непрерывный подмассив с наибольшей суммой.

Например:
Input: {-2, 1, -3, 4, -1, 2, 1, -5, 4}

Output: Subarray with the largest sum is {4, -1, 2, 1} with sum 6.


Мы можем легко решить эту задачу за линейное время, используя Алгоритм Кадане.
Идея состоит в том, чтобы поддерживать максимальный (с положительной суммой) подмассив, “заканчивающийся” на каждом индексе данного массива. Этот подмассив либо пуст (в этом случае его сумма равна нулю), либо состоит на один элемент больше, чем максимальный подмассив, оканчивающийся на предыдущем индексе.

Алгоритм может быть реализован следующим образом на Java:
class Main
{
// Функция для нахождения максимальной суммы непрерывного подмассива
// в заданном целочисленном массиве
public static int kadane(int[] arr)
{
// сохраняет максимальный суммарный подмассив, найденный на данный момент
int maxSoFar = 0;

// сохраняет максимальную сумму подмассива, заканчивающегося на текущей позиции
int maxEndingHere = 0;

// обход заданного массива
for (int i: arr)
{
// обновить максимальную сумму подмассива, "заканчивающегося" на индексе "i" (путем добавления
// текущий элемент до максимальной суммы, заканчивающейся на предыдущем индексе 'i-1')
maxEndingHere = maxEndingHere + i;

// если максимальная сумма отрицательна, устанавливаем ее в 0 (что представляет
// пустой подмассив)
maxEndingHere = Integer.max(maxEndingHere, 0);

// обновить результат, если текущая сумма подмассива окажется больше
maxSoFar = Integer.max(maxSoFar, maxEndingHere);
}

return maxSoFar;
}

public static void main(String[] args)
{
int[] arr = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };

System.out.println("The sum of contiguous subarray with the " +
"largest sum is " + kadane(arr));
}
}


результат:

The maximum sum of a contiguous subarray is 6

Временная сложность приведенного выше решения равна O(n) и не требует дополнительного места, где n это размер ввода.

Приведенный выше код не обрабатывает случай, когда все элементы массива отрицательные. Если массив содержит все отрицательные значения, ответом является максимальный элемент. Мы можем легко разместить эту проверку перед тем, как продолжить алгоритм. Реализацию можно увидеть ниже на Java:

Продолжение

@javatg
Wildcards в Java Generics
Продолжаем изучать тему дженериков.

Wildcards.
Это очень важная фишка дженериков.

Пример:
public class Main {

public static void main(String[] args) {

String str = new String("Test!");
// никаких проблем
Object obj = str;

List<String> strings = new ArrayList<String>();
// ошибка компиляции!
List<Object> objects = strings;
}
}


Что же тут происходит?
Мы видим две очень похожие ситуации. В первой из них мы пытаемся привести объект String к типу Object. Никаких проблем с этим не возникает, все работает как надо.

Но вот во второй ситуации компилятор выдает ошибку. Хотя, казалось бы, мы делаем то же самое. Просто теперь мы используем коллекцию из нескольких объектов.

Но почему возникает ошибка? Какая, по сути, разница — приводим мы один объект String к типу Object или 20 объектов?
Между объектом и коллекцией объектов есть важное различие.

Если класс B является наследником класса А, то Collection<B> при этом — не наследник Collection<A>.

Именно по этой причине мы не смогли привести наш List<String> к List<Object>. String является наследником Object, но List<String> не является наследником List<Object>.

Интуитивно это выглядит не очень логично. Почему именно таким принципом руководствовались создатели языка?

Давай представим, что здесь компилятор не выдавал бы нам ошибку:
List<String> strings = new ArrayList<String>();
List<Object> objects = strings;


В этом случае, мы бы могли, например, сделать следующее:
objects.add(new Object());
String s = strings.get(0);


Поскольку компилятор не выдал нам ошибок и позволил создать ссылку List<Object> object на коллекцию строк strings, можем добавить в strings не строку, а просто любой объект Object!

Продолжение

@javatg
Попасть в команду Дзена быстрее, чем кажется! Присоединяйтесь к Hiring Days 8 и 9 июля и получите оффер за выходные не выходя из дома.

💼 Дзен — это высоконагруженный сервис, в который приходит до 150 тысяч запросов в секунду и от 30 миллионов пользователей каждый день. В команде пишут на языках Java 17, C++, Python и Go, а релизятся несколько раз в день.

🧑‍💻 Что нужно от вас: опыт работы в backend-разработке от двух лет, регистрация на сайте проекта. Сейчас ищут коллег в команды инфраструктуры и продуктовой разработки.

Регистрация открыта до 5 июля. Что самое крутое — если случится мэтч, оффер выдадут прямо за выходные. И да, всё онлайн!

Подробнее.
🖥 Задача максимальная сумма замкнутого подмассива

Сложность: Средняя

Условие задачи: дается круговой целочисленный массив nums длины n, верните максимально возможную сумму непустого подмассива nums.

Циклический массив означает, что конец массива соединяется с началом массива. Формально следующим элементом nums[i] является nums[(i + 1) % n], а предыдущим элементом nums[i] является nums[(i - 1 + n) % n].

Подмассив может включать в себя каждый элемент фиксированных чисел буфера не более одного раза. Формально, для подмассива nums[i], nums[i + 1], ..., nums[j] не существует i <= k1, k2 <= j с k1 % n == k2 % n.

Пример:

Ввод:
nums = [1,-2,3,-2]
Вывод: 3
Объяснение: [3]

Ввод: nums = [5,-3,5]
Вывод: 10

Решение

Пишите свое решение в комментариях👇

@javatg
Please open Telegram to view this post
VIEW IN TELEGRAM
10 распространенных утечек памяти в Java и способы их устранения

В этом руководстве изложены оптимальные решения по поиску и устранению утечек памяти в Java на этапе кодирования.

В перечень распространенных утечек памяти в Java входят:


Статические поля и коллекции.
Незакрытые ресурсы.
Переменные ThreadLocal.
Неограниченное кэширование.
Неправильное использование слушателей событий (Event Listeners).
Неубранные корни сборки мусора.
Неуправляемые пулы потоков.
Неправильное использование шаблона Singleton.
Глубокие и сложные графы объектов.
Сторонние библиотеки.
Поскольку с утечками памяти лучше (и проще всего) всего бороться на этапе кодирования, давайте рассмотрим оптимальные способы их устранения.

Читать статью

@javatg
Каким будет результат сравнения в следующем коде?

Ответ:
s1 == s2 ? true

s1 == s3 ? false

s1 equals s3 ? true

Вопрос на понимание работы пула строк в Java и на понимание сравнения строк. Разберем детально: Переменная s1 ссылается на строку в пуле уникальных строк в памяти, переменная s2 ссылается на ту же саму строку в пуле уникальных строк, что и переменная s1, первое сравнение будет true, так как s1 и s2 ссылаются на один и тот же объект. Переменная s3 ссылается на новый объект, который не находится в пуле уникальных строк, так как он создан через new, следовательно второе сравнение будет false, так как сравниваем переменные которые ссылаются на на два разных объекта. Третье сравнение будет true, так как мы сравниваем строки посимвольно на эквивалентность через equals, а содержимое данных строк одинаково.


#junior #собеседования

@javatg
Видеокурс Kotlin с нуля

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

Вас ждёт 24 урока средней продолжительностью 10 минут, так что вы не успеете устать и сможете дозированно получать новые знания:

https://www.youtube.com/playlist?list=PLgPRahgE-Gcu4s-I9mrHUrKUp9dY6QcJC

@javatg
💌Запечатанные классы (Sealed Classes)

В релизе Java 17 компания Oracle представила новую функцию под названием Sealed Classes (запечатанные классы). По идее, она предназначена для повышения безопасности и гибкости приложений Java.
Запечатанные классы позволяют разработчикам ограничивать иерархию наследования класса или интерфейса. Иными словами, они обеспечивают больший контроль над тем, как класс может быть расширен или реализован.

Пример класса Shape, который может быть расширен классами Circle, Square или Triangle.

Синтаксис для определения запечатанного класса:
public sealed class Shape permits Circle, Square, Triangle {
// Определение класса
}


🔍Что такое сопоставление с образцом и как оно улучшает читаемость кода Java

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

В функциональных языках сопоставление с образцом можно использовать в качестве альтернативы традиционным операторам потока управления, таким как if-else или switch-case.

Сопоставление с образцом на примере кода:
public interface Shape {
Double area();
}

public final static class Circle implements Shape {
public final double radius;

Circle(double radius) {
this.radius = radius;
}

@Override
public Double area() {
return Math.PI * radius * radius;
}
}

public final static class Square implements Shape {
public final double side;

Square(double side) {
this.side = side;
}

@Override
public Double area() {
return side * side;
}
}

📌 Подробнее

@javatg
2025/07/07 02:38:29
Back to Top
HTML Embed Code: