Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Wildcard для спецификации подтипов Java: Дженерики

Дженерики позволяют нам работать однообразно с любым типом данных, но иногда возникает задача создать дженерик для определенного набора типов. Возьмем для примера задачу поиска среднего значения для списка чисел. Для Integer реализация метода выглядит так:

public class Application {
    public static Double average(List<Integer> numbers) {
        // Double
        var sum = 0.0;
        for (var number : numbers) {
            sum += number;
        }

        return sum / numbers.size();
    }

    public static void main(String[] args) {
        var numbers = List.of(1, 2, 3, 4, 5);
        System.out.println(average(numbers)); // => 3.0
    }
}

Если сделать из метода average() дженерик, то он не сработает, так как тип T будет Object, для которого операция сложения не определена.

public static <T> Double average(List<T> numbers) {
    var sum = 0.0;
    for (var number : numbers) {
        // The operator += is undefined for the argument type(s) double, T
        sum += number;
    }

    return sum / numbers.size();
}

Для подобных задач в Java есть механизм Wildcard, с его помощью можно уточнить типы, с которыми работает дженерик. В нашем случае и Integer и Double являются подтипами Number, а значит мы можем написать так: List<? extends Number>. В таком случае в метод попадут только числа, какими бы они не были, а типом параметра numbers станет List<Number>.

public static <T> Double average(List<? extends Number> numbers) {
    var sum = 0.0;
    for (var number : numbers) {
        sum += number;
    }

    return sum / numbers.size();
}

Обновленный код почти работает. Он все еще выдает ошибку The operator += is undefined for the argument type(s) double, Number, так как во время сложения получается что тип переменной sum это Double, а тип переменной number - Number. Эта задача решается за счет метода doubleValue() определенного у Number, который любое число преобразует в Double. Рабочий код:

public static <T> Double average(List<? extends Number> numbers) {
    var sum = 0.0;
    for (var number : numbers) {
        sum += number.doubleValue();
    }

    return sum / numbers.size();
}

Wildcard не часто используется в прикладном коде, но часто используется в библиотеках. Поэтому его нужно знать на начальном этапе, хотя бы для того, чтобы читать документацию и понимать что там написано.

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


Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

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

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 6 300 ₽ в месяц
Разработка приложений на языке Java
10 месяцев
с нуля
Старт 9 мая

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»