Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Лекция 11
Дженерики и коллекции
Программирование на языке Java
Роман Гуров
ВШЭ БИ 2021
Дженерики и наследование
Вспомним знакомое нам приведение к интерфейсу (или суперклассу):
Number number = 1;
// эквивалентно: = new Integer(1);
Number[] numberArray = new Integer[10];
Все ок, это отлично работает
Но, такое преобразование не сработает для типов дженерика:
Optional optionalInt = Optional.of(1);
Optional optionalNumber = optionalInt;
Дженерики и наследование
Optional optionalInt = Optional.of(1);
Optional optionalNumber = optionalInt;
Такое ограничение существует не случайно.
Допустим, что у Optional появился метод .set(), присваивающий ему некоторое значение:
public void set(T value) {
if (value == null) {
throw new NullPointerException();
}
this.value = value;
}
optionalInt.set(30);
Тогда, по логике вещей, после преобразования к Optional
станет законным вызов set от, например, BigDecimal
optionalNumber.set(new BigDecimal("3.14"));
Дженерики и наследование
Тот же самый пример, но с ArrayList:
ArrayList arr_int = new ArrayList<>();
arr_int.add(42);
ArrayList arr_number = arr_int;
arr_number.add(new BigDecimal("3.14"));
Изначальный объект – массив интов, преобразование ссылки на него не должно изменять его сущность
Но стоп! А что же тогда тут?
Number[] numberArray = new Integer[10];
Само преобразование работает, но нарушить закон нам не позволит виртуальная машина:
numberArray[0] = 42;
numberArray[1] = 1.3; // ArrayStoreException
Дженерики и наследование
А зачем тогда вообще кому-то нужны такие преобразования?
Number[] numberArray = new Integer[10];
ArrayList arr_number = new ArrayList();
Всё просто: как и раньше, мы хотим создавать универсальные функции
public static double doubleSum(Number[] values) {
double sum = 0;
for (int i = 1; i < values.length; ++i) {
sum += values[i].doubleValue();
}
return sum;
}
Consumer и Supplier
В языке существует понятие функциональных интерфейсов:
public interface Consumer {
void accept(T value);
}
public interface Supplier {
T get();
}
Аналог void функции,
принимающей один аргумент типа T
Аналог функции без аргументов,
возвращающей объект типа T
Но самый фокус в том, что функции умеют приводиться к таким интерфейсам
Number number = 42;
Supplier s = number::hashCode;
Consumer c = System.out::println;
c.accept(s.get());
Подробности – в другой лекции
ifPresent и orElseGet в Optional
Optional совместим с этими функциональными интерфейсами:
Optional optionalString = Math.random() > 0.5 ? Optional.of("test") : Optional.empty();
optionalString.ifPresent(System.out::println);
String result = optionalString.orElseGet(MyLocalizedMessages::GetEmptyStringMessageLocalized);
Попытаемся реализовать эти два метода:
class Optional {
private final T value;
public void ifPresent(Consumer consumer) {
if (value != null) {
consumer.accept(value);
}
}
public T orElseGet(Supplier supplier) {
return value != null ? value : supplier.get();
}
}
ifPresent и orElseGet в Optional
class Optional {
private final T value;
public void ifPresent(Consumer consumer) {
if (value != null) {
consumer.accept(value);
}
}
public T orElseGet(Supplier supplier) {
return value != null ? value : supplier.get();
}
}
Но в такой реализации всплывает проблема с первого слайда лекции:
Optional opt_seq = /* ... */;
Consumer
«Дженерики и коллекции. Программирование на языке Java» 👇
Оставляя свои контактные данные и нажимая «Попробовать в Telegram», я соглашаюсь пройти процедуру
регистрации на Платформе, принимаю условия
Пользовательского соглашения
и
Политики конфиденциальности
в целях заключения соглашения.
Пишешь реферат?
Попробуй нейросеть, напиши уникальный реферат с реальными источниками за 5 минут
Дженерики и коллекции. Программирование на языке Java