Совет по Spring Boot💡
Когда вам нужно настроить bean, предоставляемый Spring Boot, проверьте наличие интерфейсов *Customizer
- велика вероятность, что вы сможете настроить bean
, не отказываясь от автоконфигурации.
👉@BookJava
👨🎓 Java Developer Professional: Что говорят студенты о курсе?
Сегодня один из выпускников курса Java Developer Professional от Отус, Алексей Андреев, расскажет о своем опыте.
Смотреть видео отзыв: https://vk.cc/cxSnkL
Студенты Java Developer Professional выделяют следующие преимущества курса:
✔️ Обилие практических заданий.
✔️ Высокая экспертиза преподавателей.
✔️ Интересный контент, особенно для тех, кто уже знаком с языком Java.
После прохождения курса студенты чувствуют себя увереннее в профессиональной сфере и отмечают, что им легче развиваться в профессии.
Группа стартует уже 27 июня! Успейте присоединится.
Чтобы оценить свой уровень знаний для обучения на курсе, пройдите вступительный тест.
👉 ПРОЙТИ ТЕСТ: https://vk.cc/cxSni4
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Реализация авторизации на основе ролей в Spring Boot с помощью Keycloak
Контроль доступа на основе ролей является обязательным условием для любого приложения, имеющего дело с пользователями, которые могут получать доступ к определенным ресурсам в зависимости от своей роли в организации.
В предыдущей статье мы узнали, как защитить Spring Boot REST API с помощью Keycloak, используя протокол аутентификации OpenID Connect.
В этой статье мы добавим авторизацию на основе ролей.
Цель состоит в том, чтобы разрешить доступ к некоторым конечным точкам только пользователям с определенной ролью. Точнее, мы собираемся ограничить доступ к конечной точке DELETE и сделать его доступным только пользователям с ролью администратора.
https://gauthier-cassany.com/posts/spring-boot-keycloak-roles
👉@BookJava
Как Spring Framework реализует паттерн Dependency Injection?
Инверсия контроля (inversion of control, IoC) – принцип проектирования, по которому контроль над потоком управления передается фреймворку. Управляющий и прикладной код разделяются. При разработке модуля этот подход избавляет от необходимости знать о других модулях программы и деталях их взаимодействия. Такой код становится более переипользуемым и модульным, уменьшает связность.
Внедрение зависимостей (Dependency Injection, DI) – одна из реализаций IoC. При взаимодействии с другими модулями, программа оперирует высокоуровневыми абстракциями, тогда как конкретная её реализация поставляется фреймворком.
Стандартная реализация DI – фреймворк инстанциирует все сервисы, и складывает их в IoC-контейнер. При этом специальная сущность, Service Locator, занимается поиском соответствия реализаций абстракциям и их внедрением.
Spring – большой набор различных библиотек. DI реализуется одной из основных библиотек – Spring IoC.
Сущности бизнес-логики в Spring, как и в JavaEE называются beans. Бины объявляются различными способами, корни большинства из них лежат в понятии Configuration. В качестве контейнера бинов выступает ApplicationContext. Чтобы передать инициализацию зависимости контексту, она помечается аннотацией @Autowired
.
👉@BookJava
🧑💻 Виды тестов. Основные инструменты и их использование
Ждём вас на первом занятии серии открытых практических уроков по тестированию Spring-приложений от OTUS, где мы:
- сделаем фокус на теории и основных инструментах тестирования Java-приложений;
- обсудим, как сделать наше приложение тестируемым, какие тесты бывают и как для их написания использовать такие фреймворки и библиотеки как JUnit5, Mockito, AssertJ с учетом некоторых их особенностей и возможностей;
- ответим на все возникающие вопросы.
Спикер — Senior Software Engineer и опытный преподаватель.
Встречаемся 24 июня в 20:00 мск в преддверии старта курса «Разработчик на Spring Framework».
Все участники вебинара получат специальную цену на обучение!
8️⃣9️⃣🔟Регистрируйтесь прямо сейчас, чтобы не пропустить бесплатный урок: https://vk.cc/cxOdSX
🎁 Только до 23 июня скидка на курс 10%, подробности у наших менеджеров - просто оставь заявку.Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
Что делает семафор?
Семафор – один из старейших примитивов синхронизации. Он был изобретен Дейкстрой в 1968 году. По большому счету это счетчик, который можно увеличивать и уменьшать из разных потоков. Уменьшение до 0 блокирует уменьшающий поток. Состояние, когда счетчик больше нуля называют сигнальное состояние, операцию его увеличения – release (освобождение) или signal, уменьшения – acquire (захват) или wait.
На практике можно представить, что release – выделение квоты доступа к критической секции программы. acquire – использование необходимого объема доступной квоты, или ожидание, если её не хватает.
В Java семафор реализован классом Semaphore. Состоит этот класс в основном из разных форм методов acquire (с таймаутом, с игнорированием InterruptedException, неблокирующий) и release. Методы могут принимать параметр permits – тот самый объем квот, которые необходимо освободить/захватить.
Несколько вспомогательных методов позволяют узнать больше о количестве и составе очереди потоков, которые ждут освобождения пермитов. А методы availablePermits и drainPermits позволяют узнать количество оставшихся пермитов, и захватить их все соответственно. В конструкторе конфигурируются изначальное количество пермитов, и свойство fair (аналогичное свойству ReentrantLock).
👉@BookJava
Для чего нужны функциональные интерфейсы Function<T,R>, DoubleFunction<R>, IntFunction<R> и LongFunction<R>?
Function<T, R> - интерфейс, с помощью которого реализуется функция, получающая на вход экземпляр класса T
и возвращающая на выходе экземпляр класса R
.
Методы по умолчанию могут использоваться для построения цепочек вызовов (compose
, andThen
).Function<String, Integer> toInteger = Integer::valueOf;
Function<String, String> backToString = toInteger.andThen(String::valueOf);
backToString.apply("123"); // "123"
⚫️DoubleFunction<R> - функция получающая на вход Double и возвращающая на выходе экземпляр класса R;
⚫️IntFunction<R> - функция получающая на вход Integer и возвращающая на выходе экземпляр класса R;
⚫️LongFunction<R> - функция получающая на вход Long и возвращающая на выходе экземпляр класса R.
👉@BookJava
Как разобраться в вышмате за 1 вечер? 😨
Да никак. Но можно научиться понимать математику. И сберечь месяцы жизни, кучу нервов и сил.
В помощь вам - полезный канал о высшей математике. Его автор - выпускник СПБГУ, а ныне — преподаватель предмета.
На простом языке объясняет сложные вещи, даёт шпаргалки и проводит эфиры с решением задач 📈
Находка для всех, кому нужен вышмат по жизни. От полезных материалов и разборов до ответов на любые вопросы и живых дискуссий в комментариях.
Посмотрите сами 👉 @lav_math
Как применяют технологию SPI
Service Provider Interface – технология из стандартной поставки JavaSE. Этой технологией реализуется IoC, не являющаяся при этом DI. С помощью SPI можно легко и без дополнительных инструментов поставлять конкретные реализации сервисов отдельными jar-файлами. Применение обычно похоже на механизм плагинов.
Два основных понятия SPI – это service и service provider. Service – интерфейс или абстрактный класс, который объявляет API требуемого сервиса, и предоставляется основным приложением. Service provider – реализация этого API, наследник класса/интерфейса сервиса, который динамически поставляется в основное приложение библиотекой-плагином. Для одного сервиса может быть предоставлено несколько провайдеров из одной или нескольких библиотек.
На интерфейс сервиса не накладывается никаких ограничений. Провайдер же обязан реализовывать этот интерфейс, и иметь конструктор без параметров. Внутри jar-файла в директории META-INF/services лежат текстовые файлы, где имя файла – полное имя сервиса, а его строчки – полные имена провайдеров этого сервиса, которые поставляются этой библиотекой.
Для получения провайдеров всех библиотек приложения используется класс ServiceLoader. Это итератор по сервис-провайдерам, а создается он статическим методом load, в который параметром передается интерфейс/абстрактный класс интересующего сервиса.
Доступ к файлам-ресурсам из classpath обеспечивается загрузчиком классов, поэтому дополнительно при загрузке можно указать специфический загрузчик. С появлением модульности в Java 9 можно также указать модуль.
SPI повсеместно используется в стандартной библиотеке JDK. С его помощью подключаются JDBC-драйверы. Через ServiceLoader также загружаются таймзоны, системные настройки, кодировки, провайдеры файловой системы и многое другое.
👉@BookJava
Что такое «ссылка на метод»?
Если существующий в классе метод уже делает все, что необходимо, то можно воспользоваться механизмом method reference (ссылка на метод) для непосредственной передачи этого метода. Такая ссылка передается в виде:
⚫️имя_класса::имя_статического_метода для статического метода;
⚫️объект_класса::имя_метода для метода экземпляра;
⚫️название_класса::new для конструктора.
Результат будет в точности таким же, как в случае определения лямбда-выражения, которое вызывает этот метод.private interface Measurable {
public int length(String string);
}
public static void main(String[] args) {
Measurable a = String::length;
System.out.println(a.length("abc"));
}
Ссылки на методы потенциально более эффективны, чем использование лямбда-выражений. Кроме того, они предоставляют компилятору более качественную информацию о типе и при возможности выбора между использованием ссылки на существующий метод и использованием лямбда-выражения, следует всегда предпочитать использование ссылки на метод.
👉@BookJava
Что такое «лямбда»? Какова структура и особенности использования лямбда-выражения?
Лямбда представляет собой набор инструкций, которые можно выделить в отдельную переменную и затем многократно вызвать в различных местах программы.
Основу лямбда-выражения составляет лямбда-оператор, который представляет стрелку ->. Этот оператор разделяет лямбда-выражение на две части: левая часть содержит список параметров выражения, а правая собственно представляет тело лямбда-выражения, где выполняются все действия.
Лямбда-выражение не выполняется само по себе, а образует реализацию метода, определенного в функциональном интерфейсе. При этом важно, что функциональный интерфейс должен содержать только один единственный метод без реализации.interface Operationable {
int calculate(int x, int y);
}
public static void main(String[] args) {
Operationable operation = (x, y) -> x + y;
int result = operation.calculate(10, 20);
System.out.println(result); //30
}
По факту лямбда-выражения являются в некотором роде сокращенной формой внутренних анонимных классов, которые ранее применялись в Java.
Отложенное выполнение (deferred execution) лямбда-выражения- определяется один раз в одном месте программы, вызываются при необходимости, любое количество раз и в произвольном месте программы.
Параметры лямбда-выражения должны соответствовать по типу параметрам метода функционального интерфейса:operation = (int x, int y) -> x + y;
//При написании самого лямбда-выражения тип параметров разрешается не указывать:
(x, y) -> x + y;
//Если метод не принимает никаких параметров, то пишутся пустые скобки, например:
() -> 30 + 20;
//Если метод принимает только один параметр, то скобки можно опустить:
n -> n * n;
Конечные лямбда-выражения не обязаны возвращать какое-либо значение.interface Printable {
void print(String s);
}
public static void main(String[] args) {
Printable printer = s -> System.out.println(s);
printer.print("Hello, world");
}
Блочные лямбда-выражения обрамляются фигурными скобками. В блочных лямбда-выражениях можно использовать внутренние вложенные блоки, циклы, конструкции if, switch, создавать переменные и т.д. Если блочное лямбда-выражение должно возвращать значение, то явным образом применяется оператор return:Operationable operation = (int x, int y) -> {
if (y == 0) {
return 0;
}
else {
return x / y;
}
};
Передача лямбда-выражения в качестве параметра метода:interface Condition {
boolean isAppropriate(int n);
}
private static int sum(int[] numbers, Condition condition) {
int result = 0;
for (int i : numbers) {
if (condition.isAppropriate(i)) {
result += i;
}
}
return result;
}
public static void main(String[] args) {
System.out.println(sum(new int[] {0, 1, 0, 3, 0, 5, 0, 7, 0, 9}, (n) -> n != 0));
}
👉@BookJava
🚀 Простой сервис HTTP-запросов и ответов 🚀
Очень хорошо подходит для тестирования ваших http-запросов! 🔥
https://httpbin.org/#/Response_inspection
👉@BookJava
⌨️ Только начинаете свой путь в Java-разработке?
Ждём вас на открытом практическом уроке «Сборка приложения на Java» от OTUS, где мы:
- рассмотрим, как запустить и собрать исполняемый jar-файл;
- добавим в него ресурсы;
- запустим Java-приложение;
- научимся использовать утилиты javac и java, jvm, jre, jdk и classpath.
Спикер Андрей Поляков — старший разработчик в международной финтех-компании.
Встречаемся 18 июня в 20:00 мск в рамках курса «Специализация Java-разработчик».
Все участники вебинара получат специальную цену на обучение!
➡️ Регистрируйтесь прямо сейчас, чтобы не пропустить бесплатный урок: https://vk.cc/cxCQ9tРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🚀 Протестируйте приложение с помощью Taikai
Taikai - это мощное расширение популярной библиотеки ArchUnit
, предлагающее полный набор предопределенных правил, адаптированных для различных технологий. 🔥
https://github.com/enofex/taikai
👉@BookJava
В чем разница между JavaEE, JavaSE и JavaME?
Как язык программирования, в рамках одной версии Java везде приблизительно одинаковая. С точки зрения платформы, существуют разные вариации:
• Standard Edition (SE) – основной набор.
• Enterprise Edition (EE) – стандартная версия, с дополнительными интерфейсами корпоративных web-технологий.
• Micro Edition (ME) – для платформ, сильно ограниченных в ресурсах. Интернет вещей, Raspberry PI, умные телевизоры. Если помните, игры для старых телефонов имели расширение .jar.
• Java Card – джава для банковских и SIM-карт. Подмножество основного языка, с урезанной библиотекой, измененным байткодом, и упором на безопасность. Когда в окне инсталлятора баннер заявляет «3 Billion Devices Run Java», в счёт идут и карточки.
• JavaFX – платформа для десктопных приложений, замена Swing. Сейчас живет как отдельный opensource-проект.
👉@BookJava
Что такое StringJoiner?
⚫️ObjDoubleConsumer<T>
- операция, которая принимает два аргумента классов T
и Double
, производит с ними некоторое действие и ничего не возвращает;
⚫️ObjLongConsumer<T>
- операция, которая принимает два аргумента классов T
и Long
, производит с ними некоторое действие и ничего не возвращает;
⚫️ObjIntConsumer<T>
- операция, которая принимает два аргумента классов T
и Integer
, производит с ними некоторое действие и ничего не возвращает.
👉@BookJava
Spring Boot 3.2: замените свой RestTemplate на RestClient
В мире Spring Boot отправка HTTP запросов к внешним сервисам является весьма распространенной задачей. Традиционно при достижении этой цели разработчики полагались на RestTemplate. Однако, по мере развития Spring Framework, на свет появился новый и более мощный способ обработки HTTP запросов: так называемый WebClient. Spring Boot 3.2 представил нам новый API для REST запросов: RestClient, использующий те же принципы fluent api, что и WebClient.
RestClient предлагает нам более современные и интуитивно понятные способы взаимодействия с RESTful сервисами.
https://habr.com/ru/companies/spring_aio/articles/822529/
👉@BookJava
⁉ Готовы освоить любимый язык опытных разработчиков и сделать свой стек непобедимым?
Ждём вас на открытом практическом уроке «Знакомство с Clojure, идеология, синтаксис и основные особенности» от OTUS, где мы:
- поговорим о том, что из себя представляет язык Clojure;
- обсудим предысторию его появления и основную идеологию;
- продемонстрируем выполнение кода в REPL и взаимодействие с ним из IDE;
- ответим на все возникающие вопросы.
🔔Встречаемся 25 июня в 19:00 мск в рамках курса «Clojure Developer». Все участники вебинара получат специальную цену на обучение!
➡ Регистрируйтесь прямо сейчас, чтобы не пропустить бесплатный урок.
Для чего нужны функциональные интерфейсы UnaryOperator<T>, DoubleUnaryOperator, IntUnaryOperator и LongUnaryOperator?
UnaryOperator<T> (унарный оператор) принимает в качестве параметра объект типа T, выполняет над ними операции и возвращает результат операций в виде объекта типа T:UnaryOperator<Integer> operator = x -> x * x;
System.out.println(operator.apply(5)); // 25
⚫️DoubleUnaryOperator - унарный оператор получающий на вход Double;
⚫️IntUnaryOperator - унарный оператор получающий на вход Integer;
⚫️LongUnaryOperator - унарный оператор получающий на вход Long.
👉@BookJava
Обновление Java с 17 на 21: через тернии к звездам
Меня зовут Денис, я тимлид команды R&D в Naumen Service Management Platform.
Как большие почитатели языка Java, мы, Naumen Service Management Platform, стараемся мигрировать на свежие версии языка. Причин множество: это и улучшенная безопасность, и появление крутых языковых фич, и буст перформанса. Но путь не всегда оказывается простым.
В докладе я расскажу, с какими проблемами и препятствиями мы столкнулись при обновлении продукта Naumen SMP на новую LTS версию Java. Также поделюсь мыслями, а зачем вообще стоит обновляться.
Доклад будет полезен разработчикам и техлидам, которые задумываются или уже планируют миграцию их систем на Java 21.
https://habr.com/ru/companies/naumen/articles/822639/
👉@BookJava
🚀 От новичка до Middle+ в Java-разработке под руководством лучших экспертов ниши!
Актуальное обучение для всех, кто хочет стать Java-разработчиком с нуля и для тех, кто еще не определился с языком программирования.
📌После онлайн-курса «Специализация Java-разработчик» от OTUS вы сможете:
- создавать современные приложения на Java;
- работать с реляционными базами данных;
- разрабатывать серверные веб-приложения;
- претендовать на позиции Middle Java Developer.
Вы освоите самые востребованные инструменты и лучшие практики.
Забудьте о скучном обучении — здесь вас ждут настоящие челленджи и нестандартные практические решения. А еще сильные проекты для портфолио и карьерный сапорт!
🎁 Успей на курс! Только до 23 июня скидка 10%, подробности у наших менеджеров - просто оставь заявку.
Старт уже 28 июня.
👉 Изучите подробности и оставьте заявку, чтобы получить специальную цену на курс: https://vk.cc/cxMyWBРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Что такое «функциональные интерфейсы»?
Функциональный интерфейс - это интерфейс, который определяет только один абстрактный метод.
Чтобы точно определить интерфейс как функциональный, добавлена аннотация @FunctionalInterface
, работающая по принципу @Override
. Она обозначит замысел и не даст определить второй абстрактный метод в интерфейсе.
Интерфейс может включать сколько угодно default методов и при этом оставаться функциональным, потому что default методы - не абстрактные.
👉@BookJava
Какие виды ссылок на методы вы знаете?
⚫️на статический метод;
⚫️на метод экземпляра;
⚫️на конструктор.
👉@BookJava
👩💻 Зачем Java-разработчикам Redis?
Узнайте на открытом практическом уроке от OTUS, где мы:
- посмотрим, как в Java-приложениях можно использовать Redis в качестве in-memory кеша;
- увидим, для чего это может быть полезно и какие задачи можно решить;
- ответим на все возникающие вопросы.
Спикер Сергей Петрелевич — опытный Java/Kotlin-разработчик, Oracle Certified Professional, Java SE 8 Programmer.
Встречаемся 25 июня в 20:00 мск в рамках курса «Java Developer. Professional».
Все участники вебинара получат специальную цену на обучение!
➡️ Регистрируйтесь прямо сейчас, чтобы посетить бесплатный урок: https://vk.cc/cxJfdq
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
К каким переменным есть доступ у лямбда-выражений?
Доступ к переменным внешней области действия из лямбда-выражения очень схож к доступу из анонимных объектов. Можно ссылаться на:
⚫️неизменяемые (effectively final - не обязательно помеченные как final
) локальные переменные;
⚫️поля класса;
⚫️статические переменные.
К методам по умолчанию реализуемого функционального интерфейса обращаться внутри лямбда-выражения запрещено.
Как отсортировать список строк с помощью лямбда-выражения?public static List<String> sort(List<String> list){
Collections.sort(list, (a, b) -> a.compareTo(b));
return list;
}
👉@BookJava
🚀 Готовься к переменам в мире IT с нашим практическим курсом по Domain Driven Design!
😰 Устал от запутанной инфраструктуры, вперемешку с бизнес логикой? Мы знаем, как это тяжело. Писать тесты становится неприятно и больно, приходится много мокать, тесты получаются огромными, хрупкими.. Но есть решение! Присоединяйся к нашему курсу, где мы разложим все по полочкам за 10 вебинаров, начиная с 17 июня.
🔝 Прими вызов и стань частью передовой волны технологического прогресса. Успей зарегистрироваться сейчас https://microarch.ru/courses/hexagonal-architecture?utm_source=posev&utm_medium=erid:2VtzqwL1BZQ&utm_campaign=1
🎓 На нашем курсе ты изучишь:
✅ Основы Domain-Driven Design и его важность для разработчиков.
✅ Создание эффективных и масштабируемых сервисов с использованием DDD.
✅ Применение шаблонов проектирования и принципов DDD для оптимизации кода и повышения производительности.
💡 Зачем тебе этот курс?
🌟 Плюс, ты получишь:
— Новые подходы к разработке, в том числе и использование подходов ядра и слоев в онион-архитектуре.
— Шанс быть первым внедрившим новые методы в отделе.
— Стань Senior Developer или Team Lead.
— Пиши код как профессионал, а не как в учебниках.
— Получи признание в компании и увеличь свою заработную плату.
🌟 Присоединяйся к нам прямо сейчас и стань экспертом в разработке успешных проектов: https://microarch.ru/courses/hexagonal-architecture?utm_source=posev&utm_medium=erid:2VtzqwL1BZQ&utm_campaign=1
Реклама. ИП Ветчинкин К.Е. ИНН: 773376451099 Erid: 2VtzqwL1BZQ
Hibernate и спецификация JPA: приключение на 20 минут
На прошлой неделе в блоге сообщества Spring АйО вышла статья-перевод про интересный кейс падения производительности при переходе на Hibernate 6.5. Оказалось, что выражения вида publisherId in :ids при пустом ids приводит к серьезной деградации производительности. Баг вскоре был пофикшен, однако, не дает покоя вопрос, почему так произошло?
Ниже приводим историю появления и незамедлительного решения этой проблемы, от лица Гэвина Кинга, создателя Hibernate.
https://habr.com/ru/companies/spring_aio/articles/821307/
👉@BookJava
Где у Java приложения точка входа?
В обычном Java приложении всегда должен быть main class
, содержащий метод main
. С него начинается исполнение всей программы. Main class
-ом может быть не только класс, но и интерфейс или енам. Для JavaFX приложения главный класс должен реализовывать javafx.application.Application
.
main обязательно public static
. Дополнительно, методу разрешено иметь модификатор strictfp. На аннотации и список исключений ограничений не накладывается.
В главном методе должен быть объявлен единственный аргумент – массив строк. Обе конструкции String[]
и String
... компилируются в один и тот же байт-код, так что приемлемы оба варианта. Название массива может быть любым, а значение будет содержать аргументы командной строки.
Когда приложение запускается как classpath
, главный класс передается параметром командной строки. Если выполняется единственный исходник, он и описывает main class
.
Для исполняемого jar-файла (java -jar MyJar.jar), его главный класс должен быть указан в манифесте. Внутри архива, в файл META-INF/MANIFEST.MF
добавляется строчка вида Main-Class: ru.google.com.MyClass
. Иначе запуск завершается ошибкой «no main manifest attribute
».
В случае, когда в указанном главном классе не оказывается метода, который бы удовлетворял всем критериям главного метода, программа падает с ошибкой «Main method not found».
В апплетах вместо main входной точкой служат методы init
и start
. Начиная с версии Java 9 технология апплетов объявлена устаревшей, а с 11 – совсем удалена. Не будем останавливаться на них подробнее.
👉@BookJava
👩💻 Курс для Java-разработчиков, которые хотят профессионального роста.
Пройди тест по Java и проверь свои знания, готов ли ты к обучению на курсе.
Ответишь — пройдешь на продвинутый курс "Java Developer. Professional" от OTUS по специальной цене + получишь доступ к записям открытых уроков курса курса
👉 ПРОЙТИ ТЕСТ: https://vk.cc/cxzaTCРеклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
Collection.removeIf
Метод перебирает коллекцию, и удаляет те элементы, которые соответствуют filter
.
В нашем примере мы в одну строку удаляем из списка все числа больше 5.
👉@BookJava