Java | Фишки и трюки
7.21K subscribers
182 photos
29 videos
6 files
40 links
Java: примеры кода, интересные фишки и полезные трюки

Купить рекламу: https://telega.in/c/java_tips_and_tricks

✍️По всем вопросам: @Pascal4eg
Download Telegram
☕️Checked vs Unchecked исключения

🔹Исключения делятся на проверяемые (checked) и непроверяемые (unchecked).

🔹Checked исключения требуют обязательной обработки или объявления через throws. Обычно связаны с внешними ресурсами: файлами, сетью.

🔎Пример:

public void readConfigFile() {
try (FileInputStream file = new FileInputStream("config.txt")) {
int data = file.read();
System.out.println("Данные: " + data);
} catch (FileNotFoundException e) {
System.err.println("Файл не найден!");
} catch (IOException e) {
System.err.println("Ошибка ввода-вывода: " + e.getMessage());
}
}


🔹Unchecked исключения — наследники RuntimeException. Не требуют обработки, сигнализируют о логических ошибках.

🔻 Пример:

public void printLength(String text) {
if (text == null) throw new IllegalArgumentException("Строка не может быть null!");
System.out.println("Длина: " + text.length());
}



public int divide(int a, int b) {
if (b == 0) throw new ArithmeticException("Деление на ноль!");
return a / b;
}


📈Советы:
1. Для checked используйте try или try-with-resources.
2. Для unchecked проверяйте входные данные.
3. Документируйте исключения через
@throws.

🔺Checked — для внешних ошибок, Unchecked — для внутренних багов.
Please open Telegram to view this post
VIEW IN TELEGRAM
13🤝3👍1
☕️GraphQL в Java позволяет клиентам запрашивать только нужные данные, избегая избыточности REST. Пример на Spring Boot:

🔹Схема (schema.graphqls):
type Vehicle {
id: ID!
type: String!
modelCode: String!
}

type Query {
vehicles: [Vehicle!]!
}


🔻Контроллер:
@Controller
public class VehicleController {
@QueryMapping
public List vehicles() {
return List.of(new Vehicle("1", "bus", "XYZ123"));
}
}


💠Пример запроса:
{
vehicles {
id
type
}
}


🔸Ответ:
{
"data": {
"vehicles": [{ "id": "1", "type": "bus" }]
}
}


🔺Для интеграции с БД используйте Spring Data JPA и Querydsl:
public interface VehicleRepo extends JpaRepository, QuerydslPredicateExecutor {}


🔹Maven зависимости:

org.springframework.boot
spring-boot-starter-graphql


com.querydsl
querydsl-jpa


📈Советы:
1. Включите GraphiQL для интерактивных запросов.
2. Используйте
@MutationMapping для мутаций.
3. Настройте кеширование через CacheControl.

🔺GraphQL позволяет запрашивать только нужные поля, снижая нагрузку на сеть.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍141
☕️Spring Data Envers помогает автоматически отслеживать изменения сущностей в базе данных с помощью Hibernate Envers.

🔺Пример сущности с аудитом:
@Entity  
@Audited
public class Post {
@Id @GeneratedValue
private Long id;
private String title;
private String slug;
}


🔺Репозиторий с поддержкой ревизий:
public interface PostRepository extends JpaRepository, RevisionRepository { }  


💠Доступны методы findRevisions() и findLastChangeRevision() для получения истории изменений.
🔻Envers создает таблицы _AUD и REVINFO для хранения версий и метаданных. При изменениях данные копируются в _AUD с типом операции (INSERT, UPDATE, DELETE).


Пример использования:
for (Revision rev : postRepository.findRevisions(postId)) {  
System.out.println("Версия " + rev.getRevisionNumber() + ": " + rev.getEntity());
}


📈Советы:
1. Добавьте зависимости hibernate-envers и spring-data-envers.
2. Включите
@EnableJpaAuditing в конфигурации.
3. Для расширенного аудита используйте
@CreatedBy и @LastModifiedBy.

🔸Метод findRevisions() возвращает все версии сущности — от создания до удаления.
Please open Telegram to view this post
VIEW IN TELEGRAM
3👌2
☕️Spring WebFlux — реактивный фреймворк для асинхронных веб-приложений в Spring 5. Он работает на серверах Netty, Undertow или Servlet 3.1+ и использует Project Reactor для обработки потоков данных без блокировок. Это позволяет обрабатывать тысячи соединений с минимальным числом потоков, что важно для высоконагруженных систем.

🎯Пример контроллера:
@RestController  
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public Mono getUser(@PathVariable Long id) {
return userRepository.findById(id);
}
@GetMapping("/{id}/orders")
public Flux getUserOrders(@PathVariable Long id) {
return userRepository.findById(id)
.flatMapMany(orderRepository::findByUser);
}
}


📇WebClient для неблокирующих HTTP-запросов:
WebClient.create("http://service.com")  
.get()
.uri("/data")
.retrieve()
.bodyToFlux(Data.class)
.subscribe(System.out::println);


📈Советы:
1. Используйте WebFlux для микросервисов с высокой нагрузкой.
2. Комбинируйте с R2DBC для реактивного доступа к БД.
3. Избегайте блокирующих вызовов (JDBC, JPA) в реактивных цепочках.


💠«WebFlux обрабатывает больше запросов с меньшим числом потоков за счет асинхронного планирования».
Please open Telegram to view this post
VIEW IN TELEGRAM
💯63👍3
💠Room — это библиотека для работы с локальными базами данных SQLite в Android, предоставляющая удобный интерфейс для взаимодействия с данными. Она является частью Android Jetpack и значительно упрощает управление базами данных, устраняя необходимость писать сложный SQL-код вручную. Room обеспечивает безопасность и упрощает поддержку приложения благодаря проверке запросов на этапе компиляции и автоматической сериализации объектов.

⁉️Почему стоит использовать Room?

1. Меньше шаблонного кода: Room автоматически обрабатывает многие задачи, такие как создание таблиц, выполнение запросов и преобразование данных.
2. Проверка запросов на этапе компиляции: Если запрос SQL содержит ошибку, она будет обнаружена до запуска приложения.
3. Интеграция с современными инструментами: Room поддерживает работу с LiveData, RxJava, Coroutines и Paging, что делает её идеальной для современных приложений.
4. Удобная миграция данных: Room предоставляет встроенные инструменты для обновления структуры базы данных.

Как подключить Room к проекту?

implementation 'androidx.room:room-runtime:2.6.1'
annotationProcessor 'androidx.room:room-compiler:2.6.1'

✔️Для использования Kotlin Coroutines добавьте:
implementation 'androidx.room:room-ktx:2.6.1'


➡️Пример 1: Создание сущности.

Сущность представляет таблицу в базе данных. Например:
@Entity(tableName = "users")
public class User {
    @PrimaryKey(autoGenerate = true)
    public int id;

    @ColumnInfo(name = "name")
    public String name;

    @ColumnInfo(name = "age")
    public int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

✔️Аннотация @Entity указывает, что класс является таблицей в базе данных.

➡️Пример 2: Создание DAO.

DAO (Data Access Object) определяет методы для взаимодействия с базой данных:
@Dao
public interface UserDao {
    @Insert
    void insert(User user);

    @Query("SELECT * FROM users")
    List getAllUsers();

    @Delete
    void delete(User user);
}

Методы DAO используют аннотации (@Insert, @Query, @Delete) для выполнения операций.

➡️Пример 3: Инициализация базы данных.

✔️Для доступа к базе данных создаётся класс, наследующий RoomDatabase:
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDao userDao();
}

✔️Инициализация базы данных:
AppDatabase db = Room.databaseBuilder(context, AppDatabase.class, "database-name").build();
UserDao userDao = db.userDao();


➡️Пример 4: Работа с LiveData.

✔️Room легко интегрируется с LiveData для наблюдения за изменениями данных:
// Получение LiveData-списка всех пользователей
@Query("SELECT * FROM users")
LiveData<List<User>> getAllUsers(); // LiveData<List<User>> - тип возвращаемого значения

✔️В UI можно наблюдать за изменениями данных:
userDao.getAllUsers().observe(this, users -> {
    // Обновление интерфейса при изменении данных
});


➡️Пример 5: Миграция базы данных.

✔️Если структура базы данных изменяется (например, добавляется новое поле), необходимо настроить миграцию:
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(@NonNull SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE users ADD COLUMN email TEXT");
    }
};
AppDatabase db = Room.databaseBuilder(context, AppDatabase.class, "database-name")
    .addMigrations(MIGRATION_1_2)
    .build();


⚡️Советы по использованию Room:

1. Используйте Flow или LiveData для реактивного обновления UI.
2.
Оптимизируйте запросы, выбирая только необходимые поля из таблицы.
3.
Настройте UPSERT операции, используя стратегию OnConflictStrategy.REPLACE:
  

   @Insert(onConflict = OnConflictStrategy.REPLACE)
   void insertOrUpdate(User user);
  


☄️Room — это мощный инструмент для работы с локальными данными в Android-приложениях. Она упрощает взаимодействие с SQLite, делает код более организованным и поддерживаемым, а также интегрируется с современными архитектурными компонентами Android.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍43
⌨️ Срезы в стримах. Метод takeWhile

В Java 9 появилось два новых метода, полезных для выбора элементов потока с хорошей производительностью: takeWhile и dropWhile.

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

List<Dish> specialMenu = Arrays.asList(
new Dish("seasonal fruit", 120),
new Dish("prawns", 300),
new Dish("rice", 350),
new Dish("chicken", 400),
new Dish("french fries", 530));


Для получения блюд с калорийностью меньше 320, можно воспользоваться операцией filter. Недостаток операции filter в том, что она требует прохода в цикле по всему потоку данных с применением предиката ко всем элементам.

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

Поможет нам в этом операция takeWhile! Она позволяет выполнить срез любого потока данных (даже бесконечного) с помощью предиката. И, к счастью, она прекращает работу сразу же по обнаружении неподходящего элемента. Вот как ее следует использовать:

List<Dish> sliceMenu1
= specialMenu.stream()
.takeWhile(dish -> dish.getCalories() < 320)
.collect(toList());


#java #stream #takeWhile
Please open Telegram to view this post
VIEW IN TELEGRAM
👍202
☕️GraalVM ускоряет Java с помощью JIT-компиляции и поддерживает мультиязычность и нативную компиляцию.

🔹Пример JIT-ускорения:

public class Demo {
public static void workload(int a) {
System.out.println(a + 1); // Простая операция
}
public static void main(String[] args) {
for (int i = 0; i < 100_000; i++) workload(i);
}
}

🔺Запуск:

java -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler Demo


🚀Вызов JavaScript из Java:

import org.graalvm.polyglot.*;
public class Polyglot {
public static void main(String[] args) {
try (Context context = Context.create()) {
int result = context.eval("js", "Math.pow(2, 10)").asInt();
System.out.println(result); // 1024
}
}
}


🔸Нативная компиляция:

native-image -jar app.jar
./app

🔭Работает без JVM!

📈Советы:
1. Для мультиязычности добавьте org.graalvm.sdk.
2. Используйте
@CEntryPoint для нативных методов.
3. Тестируйте производительность через jmh.


GraalVM позволяет запускать Python и Ruby внутри Java через Polyglot API.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
⌨️ Типы классов

В Java существует несколько «типов» (форм) классов, каждый из которых решает свои задачи и обладает своими особенностями. Рассмотрим основные из них:

1. Топ-level класс
Класс, объявленный в собственном файле .java (или несколько в одном файле, но только один может быть public).
Когда используется: для большинства объектов предметной области.

2. Статический вложенный класс (static nested class)
Объявляется внутри другого класса с модификатором static.
Когда используется: чтобы логически сгруппировать вспомогательный класс и избежать загрязнения пакета; не требует ссылки на экземпляр внешнего класса.

3. Нестатический внутренний класс (inner class)
Нестатический класс внутри другого класса. Имеет неявную ссылку на экземпляр внешнего.
Когда используется: когда класс не имеет смысла отдельно от конкретного экземпляра внешнего класса.

4. Локальный класс (local class)
Объявляется внутри метода. Видим только внутри этого метода.
Когда используется: для единичной вспомогательной логики, зависящей от локальных переменных.

5. Анонимный класс (anonymous class)
Определяется прямо при создании объекта, без имени. Часто для реализации интерфейсов/абстрактных классов «на месте».
Когда используется: когда нужна «быстрая» одноразовая реализация интерфейса или абстрактного класса.

6. Абстрактный класс (abstract class)
Может содержать как реализованные, так и абстрактные (без реализации) методы; сам не может быть инстанцирован.
Когда используется: когда есть общая часть реализации для набора подклассов, но нужна возможность «заставить» их реализовать конкретные методы.

7. Финальный класс (final class)
Нельзя унаследовать.
Когда используется: чтобы зафиксировать поведение и запретить расширение (например, для безопасности).

8. Перечисление (enum)
Специальный вид класса для фиксированного набора констант; может содержать поля и методы.
Когда используется: для ограничения значений до заранее известных.

9. Запись (record) [Java 16+]
Лаконичная форма класса-носителя данных: автоматом генерируются конструктор, equals(), hashCode(), toString().
Когда используется: для неизменяемых DTO/Value-объектов.

10. Запечатанный класс (sealed class) [Java 17+]
Позволяет закрыть иерархию наследования: указать, какие классы могут расширять/реализовывать.
Когда используется: когда важно контролировать все возможные подклассы (например, при реализации «альгебраического типа»).

11. Аннотации (annotation types)
Специальный «интерфейс» с префиксом @interface для метаданных.
Когда используется: для декларации информации, обрабатываемой компилятором или фреймворками (например, @Override, @Entity).

Каждый из этих типов классов/типов в Java помогает структурировать код, задавая чёткие контракты, ограничивая использование и сокращая «бесполезный» шаблонный код.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍107🔥2
⌨️ Игра "Камень, ножницы, бумага"


import java.util.Random;
import java.util.Scanner;

public class RockPaperScissors {
public static void main(String[] args) {
String[] options = { "Камень", "Ножницы", "Бумага" };
Random rnd = new Random();
Scanner sc = new Scanner(System.in);
int userScore = 0, compScore = 0;

System.out.println("Игра «Камень, ножницы, бумага». Введите 0-Камень, 1-Ножницы, 2-Бумага, q-выход.");

while (true) {
System.out.print("Ваш выбор: ");
String inp = sc.nextLine();
if (inp.equalsIgnoreCase("q")) break;

int user, comp = rnd.nextInt(3);
try {
user = Integer.parseInt(inp);
if (user < 0 || user > 2) throw new NumberFormatException();
} catch (NumberFormatException e) {
System.out.println("Некорректно, попробуйте снова.");
continue;
}

System.out.printf("Вы: %s, Компьютер: %s → ", options[user], options[comp]);
int outcome = (user - comp + 3) % 3;
// 0=ничья, 2=победа пользователя, 1=проигрыш
if (outcome == 0) {
System.out.println("Ничья");
} else if (outcome == 2) {
System.out.println("Вы выигрываете");
userScore++;
} else {
System.out.println("Проигрываете");
compScore++;
}

System.out.printf("Счёт %d:%d%n", userScore, compScore);
}

System.out.println("Игра окончена. Финальный счёт " + userScore + ":" + compScore);
sc.close();
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
😁14👍3😍3
⌨️ Stream.reduce() vs Collectors.joining()

Когда требуется конкатенировать строки с использованием Stream, можно выбрать один из двух методов: Stream.reduce() или Stream.collect(Collectors.joining()).

Пример с Stream.reduce():
List<String> list = List.of("Str1", "Str2", "Str3");
String result = list.stream().reduce("", (a, b) -> a + b);
System.out.println(result); // Str1Str2Str3


Пример с Collectors.joining():
List<String> list = List.of("Str1", "Str2", "Str3");
String result = list.stream().collect(Collectors.joining());
System.out.println(result); // Str1Str2Str3


Использование reduce() для конкатенации строк не является оптимальным с точки зрения производительности. При каждом вызове операции +, создается новая строка, так как строки в Java неизменяемы. Это приводит к увеличению нагрузки на память из-за создания множества промежуточных объектов.

В свою очередь, метод Collectors.joining() использует StringBuilder для сборки строк, что значительно эффективнее. Он избегает создания лишних объектов и снижает потребление памяти.

#java #Stream #reduce #joining
Please open Telegram to view this post
VIEW IN TELEGRAM
👍141
⌨️ В Java static import (статический импорт) позволяет импортировать статические члены (методы и поля) из класса, чтобы использовать их напрямую без указания имени класса. Это может сделать код более читабельным и компактным.


// Для импорта конкретного статического члена
import static package.Clazz.member;

// Для импорта всех статических членов класса
import static package.Clazz.*;


Пример:

public class MathUtils {
public static final double PI = 3.141592653589793;
public static int add(int a, int b) {
return a + b;
}
public static int subtract(int a, int b) {
return a - b;
}
}



import static MathUtils.PI;
import static MathUtils.add;

public class Main {
public static void main(String[] args) {
System.out.println("Value of PI: " + PI);
System.out.println("Addition result: " + add(5, 3));
}
}



import static MathUtils.*;

public class Main {
public static void main(String[] args) {
System.out.println("Value of PI: " + PI);
System.out.println("Addition result: " + add(5, 3));
System.out.println("Subtraction result: " + subtract(5, 3));
}
}


Плюсы: читаемость, компактность кода.

Минусы:
- не очевидно откуда берется поле или метод
- импорт всех статических членов может привести к конфликтам имен, если разные классы содержат статические члены с одинаковыми именами

#java #static #import
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥41
⌨️ В какой последовательности указывать блоки catch?

Предположим, есть метод, который может выбросить IOException и FileNotFoundException в какой последовательности должны идти блоки catch? Сколько блоков catch будет выполнено?

Общее правило: обрабатывать исключения нужно от «младшего» к старшему. То есть нельзя поставить в первый блок catch(Exception ex) {}, иначе все дальнейшие блоки catch() уже ничего не смогут обработать, так как любое исключение будет соответствовать обработчику catch(Exception ex).

Таким образом, исходя из факта, что FileNotFoundException extends IOException сначала нужно обработать FileNotFoundException, а затем уже IOException:

void method() {
try {
//...
} catch (FileNotFoundException ex) {
//...
} catch (IOException ex) {
//...
}
}


В Java 7 стала доступна новая языковая конструкция, с помощью которой можно перехватывать несколько исключений одним блоком catch:

try {
//...
} catch(IOException | SQLException ex) {
//...
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍143🔥1
⌨️ Иерархия исключений

Исключения делятся на несколько классов, но все они имеют общего предка — класс Throwable, потомками которого являются классы Exception и Error.

Ошибки (Errors) представляют собой более серьёзные проблемы, которые, согласно спецификации Java, не следует обрабатывать в собственной программе, поскольку они связаны с проблемами уровня JVM. Например, исключения такого рода возникают, если закончилась память доступная виртуальной машине.

Исключения (Exceptions) являются результатом проблем в программе, которые в принципе решаемы, предсказуемы и последствия которых возможно устранить внутри программы. Например, произошло деление целого числа на ноль.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81
⌨️ Что такое generics?

Generics - это технический термин, обозначающий набор свойств языка позволяющих определять и использовать обобщенные типы и методы. Обобщенные типы или методы отличаются от обычных тем, что имеют типизированные параметры.

Примером использования обобщенных типов может служить Java Collection Framework. Так, класс LinkedList<E> - типичный обобщенный тип. Он содержит параметр E, который представляет тип элементов, которые будут храниться в коллекции. Создание объектов обобщенных типов происходит посредством замены параметризированных типов реальными типами данных. Вместо того, чтобы просто использовать LinkedList, ничего не говоря о типе элемента в списке, предлагается использовать точное указание типа LinkedList<String>, LinkedList<Integer> и т.п.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍102
⌨️ try-catch-finally

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

catch — ключевое слово для отметки начала блока кода, предназначенного для перехвата и обработки исключений в случае их возникновения.

finally — ключевое слово для отметки начала блока кода, который является дополнительным. Этот блок помещается после последнего блока catch. Управление передаётся в блок finally в любом случае, было выброшено исключение или нет.

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

try {
//код, который потенциально может привести к исключительной ситуации
}
catch(SomeException e ) { //в скобках указывается класс конкретной ожидаемой ошибки
//код обработки исключительной ситуации
}
finally {
//необязательный блок, код которого выполняется в любом случае
}


Возможно ли использование блока try-finally (без catch)?
Такая запись допустима, но смысла в такой записи не так много, всё же лучше иметь блок catch, в котором будет обрабатываться необходимое исключение.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍86❤‍🔥1
⌨️ Есть класс Point{int x, y;}. Почему хэш код в виде 31 * x + y предпочтительнее чем x + y?

Множитель создает зависимость значения хэш кода от очередности обработки полей, что в итоге порождает лучшую хэш функцию.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥82👍1
⌨️ instanceof или getClass() == ...

Часто нам нужно проверить является ли объект экземпляром определенного класса, например в методе equals(). Существует несколько способов это сделать. Разберём два из них.

instanceof проверяет, является ли ссылка на объект в левой части экземпляром типа в правой части или каким-либо подтипом.

getClass() == ... проверяет, идентичны ли типы.

Выбирать способ проверки типа нужно исходя из решаемой задачи. В методе equals() можно использовать оба способа в зависимости от того собираетесь ли вы позволять сравнивать объект определенного класса и объект класса наследника.


class Parent { }
class Child extends Parent { }

public class Test {
public static void main(String[] args) {
Parent parent = new Parent();
Child child = new Child();
System.out.println(parent instanceof Parent); // true
System.out.println(child instanceof Parent); // true
System.out.println(parent.getClass() == Parent.class); // true
System.out.println(child.getClass() == Parent.class); // false
}
}


#java #instanceof #getClass
Please open Telegram to view this post
VIEW IN TELEGRAM
👍114
⌨️ Правила переопределения метода Object.hashCode()

Общий совет: выбирать поля, которые с большой долью вероятности будут различаться. Для этого необходимо использовать уникальные, лучше всего примитивные поля, например, такие как id, uuid. При этом нужно следовать правилу, если поля задействованы при вычислении hashCode(), то они должны быть задействованы и при выполнении equals().

➡️ Могут ли у разных объектов быть одинаковые hashCode()?
Да, могут. Метод hashCode() не гарантирует уникальность возвращаемого значения. Ситуация, когда у разных объектов одинаковые хэш коды называется коллизией. Вероятность возникновения коллизии зависит от используемого алгоритма генерации хэш кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84
⌨️ Полные и сокращённые версии AND и OR

&& и || называются сокращёнными логическими операторами AND и OR соответственно, или операторами короткой схемы вычислений. В спецификации Java их ещё зовут условными. Значения их операндов могут быть только булева типа.

В отличие от двойных, одиночные & и | называются операторами полной схемы вычислений. Значения их операндов могут быть как только булевыми, так и только целочисленными (вместе с оператором ^ они используются в побитовых операциях).

В чём разница?

В том, что для операторов & и | всегда вычисляются значения обоих операндов, а при работе операторов && и || второй операнд вычисляется только по необходимости.

То есть иногда результат выражения однозначно определён уже по первому операнду:

✔️ Если первый операнд && равен false, то второй не вычисляется, так как уже понятно, что результат всего выражения будет false.

✔️ Если первый операнд || равен true, то второй не вычисляется, так как уже понятно, что || вернёт true.

&& и || используют как операторы булевой логики. Они оперируют значениями только булева типа и применяются только в логических выражениях.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍102
Скачать файл используя Java NIO

Пакет Java NIO предлагает возможность передавать байты между двумя каналами без их буферизации в памяти приложения.

Чтобы прочитать файл по нашему URL-адресу, мы создадим новый ReadableByteChannel из потока URL-адреса.

Байты, прочитанные из ReadableByteChannel, будут переданы в FileChannel, соответствующий загружаемому файлу.

Используем метод transferFrom() из класса ReadableByteChannel для загрузки байтов с заданного URL-адреса в наш FileChannel.

Методы transferTo() и transferFrom() более эффективны, чем простое чтение из потока с использованием буфера. В зависимости от операционной системы данные могут быть перенесены непосредственно из кэша файловой системы в наш файл без копирования каких-либо байтов в память приложения.

В системах Linux и UNIX эти методы используют метод нулевого копирования, который уменьшает количество переключений контекста между режимом ядра и пользовательским режимом.
👍84🔥3
⌨️ Ссылки на методы — это способ упрощенного вызова методов или конструктора, который позволяет передавать их как аргументы в методы или сохранять в переменных. Ссылки на методы появились в Java 8 и являются частью улучшенной поддержки функционального программирования в языке.

Есть несколько видов ссылок на методы:

1️⃣ Ссылка на статический метод
Используется для вызова статических методов класса.
Синтаксис:

ContainingClass::staticMethodName

Пример:

import java.util.function.Function;

public class MethodReferenceExample {
public static void main(String[] args) {
Function<String, Integer> converter = Integer::parseInt;
Integer number = converter.apply("123");
System.out.println(number); // 123
}
}


2️⃣ Ссылка на метод экземпляра конкретного объекта
Используется для вызова методов экземпляра объекта.
Синтаксис:

containingObject::instanceMethodName

Пример:

import java.util.Arrays;
import java.util.List;

public class MethodReferenceExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(System.out::println);
}
}


3️⃣ Ссылка на метод экземпляра произвольного объекта определенного типа
Синтаксис:

ContainingType::methodName

Пример:

import java.util.function.Function;

public class FunctionExample {
public static void main(String[] args) {
Function<String, Integer> stringLength = String::length;
Integer length = stringLength.apply("Hello, World!");
System.out.println(length); // 13
}
}


Отличие от предыдущего вида в том, что в предыдущем ссылка на метод получается у конкретного объекта, стало быть вызовется метод этого объекта, а в нашем случае при получении ссылки на метод, мы знаем только метод, но объект у которого вызовется этот метод еще не известен, он будет предоставлен при вызове метода. Код выше будет означать "Hello, World!".length()

4️⃣ Ссылка на конструктор
Используется для вызова конструктора.
Синтаксис:

ClassName::new

Пример:

import java.util.function.Supplier;

public class MethodReferenceExample {
public static void main(String[] args) {
Supplier<MethodReferenceExample> exampleSupplier = MethodReferenceExample::new;
MethodReferenceExample example = exampleSupplier.get();
System.out.println(example); // MethodReferenceExample@<hashcode>
}
}


#java #MethodReference
Please open Telegram to view this post
VIEW IN TELEGRAM
👍94