Handler в Java: что это и как его применять
Разбираемся в том, как работают обработчики событий на практике.
В программах часто нужно выполнить определённый код в ответ на событие: нажатие кнопки, получение данных, завершение операции или возникновение ошибки. Такой код называют обработчиком — handler.
Под handler в Java могут пониматься разные сущности. В зависимости от контекста задачи обработчик может быть методом, функцией обратного вызова или объектом, который реагирует на определённое событие.
В этой статье мы разберём, что называют handler в Java, где используются обработчики и как они работают.
Содержание
- Что такое handler и зачем он нужен
- Как работает handler в Java
- Какие методы обработки есть в Java
- Примеры использования обработчиков
- Преимущества и недостатки обработчиков
- Как устроен handler в разных языках
- Что такое Handler в Android
- Повторяем главное
Что такое handler и зачем он нужен
Handler — это обработчик, то есть код или объект, который выполняет определённое действие в ответ на событие. Упрощённо принцип его работы можно описать так: «произошло X — выполни Y». Например, обработчик может реагировать на действие пользователя, перехватывать исключение, обрабатывать HTTP-запрос или получать событие от другой части программы.
Преимущество обработчиков в том, что они позволяют отделить само событие от реакции на него. Один компонент программы сообщает, что что-то произошло, а другой выполняет связанный с этим код.
Благодаря этому ПО проще поддерживать и изменять. Например, можно поменять реакцию на событие, не переписывая код, который это событие создаёт.
В Java обработчики встречаются в разных сценариях:
- В пользовательском интерфейсе. Они реагируют на нажатия кнопок, ввод текста и другие действия пользователя.
- При асинхронных операциях. Обработчик может запускаться после завершения фоновой задачи, чтения файла или получения ответа от сервера.
- При работе с исключениями. Специальный код выполняется, когда в программе возникает определённая ошибка.
- В серверных приложениях. Обработчики принимают HTTP-запросы, сообщения из очередей и другие входящие события.
- При работе с событиями. Один компонент программы может сообщить о произошедшем событии, а другой — выполнить связанный с ним код.
Во всех этих случаях обработчик связывает событие с действием, которое программа должна выполнить в ответ.
Как работают обработчики в Java
Схема работы обработчиков зависит от задачи. В простых случаях программа напрямую вызывает нужный метод или функцию. В более сложных проектах между событием и обработчиком могут появляться дополнительные сущности — например, очередь или диспетчер.
Упрощённо схема работы обработчика выглядит так:
событие → механизм доставки → обработчик → выполнение кода
Например, пользователь нажимает кнопку. Интерфейсная библиотека фиксирует событие, находит связанный с ним listener и вызывает его код. В другой системе задача может сначала попасть в очередь к диспетчеру, а только потом — к обработчику.

Изображение: Mermaid AI / Skillbox Media
Обработка событий в Java в общем виде состоит из пяти частей: источника события, самого события или данных, механизма доставки, handler и потока, или executor. Разберём, за что отвечает каждый из них.
| Компонент | За что отвечает |
|---|---|
| Источник события | Создаёт событие. Например, пользователь нажимает кнопку или завершается операция |
| Событие или данные | Содержат информацию о том, что произошло |
| Механизм доставки | Передаёт событие нужному обработчику |
| Handler, или обработчик | Выполняет код в ответ на событие, сообщение или запрос |
| Поток, или executor | Определяет, где будет выполняться код, если это предусмотрено архитектурой системы |
На практике эти компоненты могут взаимодействовать по-разному. Иногда событие сразу передаётся обработчику, а иногда сначала проходит через промежуточный механизм — например, диспетчер или executor.
Какие методы обработки есть в Java
В Java события и результаты операций можно обрабатывать с помощью разных инструментов: handlers, listeners, callbacks и других. Разберём основные.
Handler — общее название для кода или объекта, который что-либо обрабатывает: событие, запрос, сообщение, ошибку или результат операции. Например, HttpHandler получает HTTP-запрос и выполняет связанный с ним код.
Listener — объект, который регистрируют для получения определённых событий. Когда событие возникает, система вызывает соответствующий метод listener. Например, ActionListener можно использовать, чтобы отреагировать на нажатие кнопки.
Callback — функция или другой объект с кодом, который передают другой части программы для последующего вызова.
Эти понятия могут пересекаться. Например, функция, переданная в CompletableFuture.thenAccept(), является callback по способу вызова и одновременно выполняет роль handler, потому что обрабатывает результат операции.
Executor и ExecutorService — это интерфейсы из пакета java.util.concurrent, которые отвечают за выполнение задач в потоках. С их помощью можно передать код в другой поток или пул потоков без ручного создания Thread.
CompletableFuture используют для асинхронных операций и последовательной обработки их результатов. К вычислению можно добавить действия, которые выполняются после его завершения, а также отдельно обработать ошибки.
Например, у CompletableFuture есть методы thenApply(), thenAccept() и exceptionally() позволяют задать код для разных этапов асинхронной цепочки. Переданные им функции фактически выступают обработчиками результата или ошибки.
Выбор конкретного варианта обработчика зависит от задачи.
| Задача | Что обычно используют | Зачем |
|---|---|---|
| Реагировать на событие | Listener | Подписаться на событие и выполнить код, когда оно произойдёт |
| Обработать результат асинхронной операции | CompletableFuture и callback | Запустить действие после завершения операции или получения результата |
| Передать код для последующего вызова | Callback | Позволить другому компоненту вызвать переданную функцию в нужный момент |
| Выполнить задачу в другом потоке или пуле потоков | Executor или ExecutorService | Передать задачу управляемому потоку без ручного создания Thread |
Примеры использования обработчиков в Java
Давайте разберём три частых сценария использования handler — обработку события интерфейса, результата асинхронной операции и HTTP-запроса.
Событие в интерфейсе
Один из классических примеров событийной модели в Java — Swing. Это библиотека для создания графических интерфейсов: окон, кнопок, меню и других элементов. Swing позволяет назначать обработчики на действия пользователя. Например, чтобы выполнить код после нажатия кнопки, к ней можно добавить ActionListener:
button.addActionListener(event -> {
System.out.println("Кнопка нажата");
});Метод addActionListener() регистрирует listener для кнопки. Когда пользователь нажимает кнопку, Swing вызывает переданный код, и программа выполняет заданное действие.
Большинство событий интерфейса Swing обрабатывается в Event Dispatch Thread, или EDT. Поэтому длительные операции лучше не выполнять прямо внутри обработчика: пока EDT занят, интерфейс может перестать реагировать на действия пользователя.
Результат асинхронной операции
При асинхронной работе программа может запустить длительную задачу, например загрузку данных, и продолжить выполнять другой код, не дожидаясь результата.
Если дальнейшие действия зависят от этих данных, нужно указать, что сделать после завершения задачи. Для этого можно заранее передать функцию, которая будет вызвана, когда результат станет доступен. Так программе не придётся останавливаться и ждать результат, блокируя текущий поток.
Например, в Java это можно реализовать с помощью CompletableFuture:
CompletableFuture
.supplyAsync(() -> loadData())
.thenAccept(data -> {
System.out.println(data);
});В примере выше метод supplyAsync() запускает загрузку данных асинхронно, а thenAccept() задаёт действие, которое выполнится после получения результата. Переданная в thenAccept() функция получает загруженные данные и выводит их в консоль.
Такую функцию называют callback, или функцией обратного вызова.
HTTP-запрос
HTTP-сервер принимает запросы от клиентов, например браузеров. Чтобы ответить на запрос, нужно выполнить код: получить данные, сформировать страницу или вернуть сообщение. Этот код и задают в обработчике.
Обработчик заранее связывают с определённым сценарием. Когда приходит подходящий запрос, сервер сам вызывает обработчик и передаёт ему данные запроса и средства для отправки ответа.
Во встроенном HTTP-сервере Java для этого используется интерфейс HttpHandler:
server.createContext("/hello", exchange -> {
String response = "Hello";
exchange.sendResponseHeaders(200, response.length());
exchange.getResponseBody().write(response.getBytes());
exchange.close();
});Метод createContext() связывает путь /hello с обработчиком. Когда сервер получает запрос по этому адресу, он вызывает переданный код. Обработчик формирует HTTP-ответ, записывает его в тело ответа и закрывает соединение.
Преимущества и недостатки использования обработчиков
Обработчики помогают разделить источник события и код, который на него реагирует. За счёт этого код проще расширять и менять. Но есть и обратная сторона: становится сложнее понять, когда и где именно выполняется обработчик.
Плюсы обработчиков
Handler используют благодаря нескольким преимуществам:
- Реакцию на событие можно менять отдельно от кода, который это событие создаёт.
- Проще разделять ответственность между компонентами: один создаёт событие, другой его обрабатывает.
- Обработчики хорошо подходят для асинхронных операций, момент завершения которых заранее неизвестен.
- Во многих библиотеках и фреймворках уже есть готовые механизмы регистрации и вызова обработчиков.
Поэтому обработчики остаются одним из базовых механизмов событийного программирования и встречаются во многих языках, библиотеках и фреймворках.
Минусы обработчиков
К основным ограничениям подхода относят следующее:
- Порядок выполнения кода становится менее очевидным: обработчик могут зарегистрировать в одном месте, а вызвать позже в другом.
- Важно учитывать поток выполнения. Например, длительная операция в UI-потоке может заблокировать интерфейс.
- В многопоточном коде несколько обработчиков могут одновременно обращаться к общим данным, поэтому приходится следить за синхронизацией.
- Подписки на события нужно вовремя удалять. Иначе источник события продолжит хранить ссылку на listener, даже когда он уже не используется. Если такие ссылки накапливаются, приложение начинает расходовать всё больше памяти.
Чтобы избежать сложностей при работе с обработчиками, полезно проверять три вещи: где они регистрируются, какое событие их запускает и в каком потоке выполняется код.
Как устроен handler в разных языках
В разных языках, библиотеках и фреймворках под этим термином понимают разные механизмы: от функции, которая реагирует на событие, до отдельного класса для работы с очередью сообщений.
Рассмотрим несколько распространённых вариантов.
Python
В Python handler встречается в системе логирования. Объекты Handler получают записи журнала и направляют их в конкретное место. Например, StreamHandler выводит сообщения в поток, FileHandler записывает их в файл, а RotatingFileHandler позволяет создавать новые лог-файлы при достижении заданного размера.
Ещё один пример в Python — обработка системных сигналов. С помощью signal.signal() можно указать функцию, которая должна сработать при получении определённого сигнала, например SIGINT или SIGTERM. Когда такой сигнал поступает программе, Python вызывает назначенный обработчик.
JavaScript
В браузерном JavaScript обработчики чаще всего связаны с событиями. Функция может запускаться в ответ на клик, ввод текста, нажатие клавиши или другое действие.
Один из основных способов назначить обработчик — метод addEventListener(). С его помощью на одно событие можно определить несколько функций. Другой вариант — свойства вроде onclick. В этом случае свойству назначают один обработчик, поэтому новое значение заменяет предыдущее.
Похожий подход используется в Node.js. Класс EventEmitter позволяет создавать именованные события и назначать функции, которые будут выполняться при их возникновении. Такой механизм используется, например, при работе с потоками данных и серверами.
Что такое Handler в Android
В Android Handler — это конкретный класс, который позволяет передавать задачи для выполнения в определённом потоке.
Например, фоновый поток загрузил данные, но обновить интерфейс напрямую из него нельзя. Тогда задачу можно передать в главный поток через Handler. Он добавит её в очередь, а когда подойдёт она подойдёт, главный поток выполнит её.
Для этого Android-разработчики обычно используют метод post():
handler.post(() -> {
// код выполнится в потоке, с которым связан Handler
});Внутри этот механизм работает с Looper и MessageQueue. Looper следит за очередью задач конкретного потока, а Handler позволяет добавлять в неё новые задачи и сообщения.
То есть Handler в Android можно представить как посредника: он принимает задачу, помещает её в очередь нужного потока, в котором она выполняется
Главное о handler в пяти пунктах
Подведём итоги и коротко повторим основные моменты:
- Handler — общее название для кода или объекта, который обрабатывает событие, запрос, сообщение, ошибку или результат операции.
- Listener и callback — не отдельные виды handler в строгом смысле, а способы организовать вызов кода. Listener обычно подписывается на событие, а callback передают другому коду для последующего вызова.
- Один и тот же код может одновременно быть callback и выполнять роль handler. Например, функция в CompletableFuture.thenAccept() вызывается как callback и обрабатывает результат операции.
- При работе с обработчиками нужно учитывать, где и когда выполняется код. Особенно это важно в многопоточных и UI‑приложениях.
- В Android Handler с прописной буквы — это отдельный класс. Его не стоит путать с общим понятием handler в Java.
Больше интересного про код — в нашем телеграм-канале. Подписывайтесь!
