Как стать автором
Обновить

Комментарии 17

Для фана и тренировки мозга — ок, но вопрос в другом, а почему вообще ожидается, что это гарантировано будет работать? И почему неработающие кейсы должны удивлять? Это примерно как «меняем double на float: что может пойти не так».

Не то чтобы ожидается, что работать не будут. Однако большинство нормальных использований либо ничего не сломают, либо сломают компиляцию. А чтобы сохранить компиляцию, но сломать рантайм, надо подумать. Так что да, для фана и тренировки мозга.

Я думал, что речь пойдет про баг в самой Java, а вы тут какие-то сферические примеры придумываете...

Не скажите, пример с


Object x = 1000;
List<?> list = new ArrayList<>();
list.remove(x);

вполне себе жизненный, по меньшей мере один раз я столкнулся с плавающей ошибкой при наличии List<Integer> и вызова на нём метода remove().

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

Тут нужно помнить, что грабли кроются в автоматическом разворачивании/заворачивании Integer-a и int-а, но так было не всегда. До 5 явы int нужно было явно заворачивать в Integer и наоборот.


Опять же, сами по себе методы List.remove(Object) и List.remove(int), ИМХО, довольно логичны в контексте других методов интерфейса "список". Просто именно с int-ом / Integer-ом получилась бяка.

Да какая там логика, это просто злоупотребление перегрузкой. Нигде больше такой фигни нет, везде есть разница между семантикой remove и removeAt.

Да, сегодня с высоты 2 с хвостиком десятков лет мы это видим. На заре не разглядели, бывает :)

Статья огонь, читал не отрываясь!


Умеет ли "Идея" распознавать подобный код с плавающими ошибками?

Про метод-референс мы говорим, что а-та-та будет:



Ну сравнение c new Integer() понятно что подозрительное:



x = (Integer)null — дело святое (конечно, варнинг исчезает, если тип Object):



Кое-что из остального поддержать можно, но не факт, что нужно...

Проверил,


var x = 1.0;
System.out.println(String.valueOf(false ? x : 100000000000L).substring(12) + "Ok");

определяется на ура. А то я уж было собрался расчехлять задачесоздатель ;)

А, кстати да. Я и забыл, что я сам это сделал.


List.remove тоже поддержал (добавил требование, что индекс должен быть от 0 до длины списка), хотя здесь простой пример, всё известно заранее. Не факт, что в реальной жизни пригодится.

Неожиданно, кстати, обнаружилась польза от контракта для remove — подсветилось res.remove(res.size()). Видимо, никогда не выполнялась эта ветка.

Ну и славненько! Больше проверок, хороших и разных!

wouter.coekaerts.be/2018/java-type-system-broken

Тип T выводится как StringBuilder, но в данном коде компилятор не обязан вставлять в байткод проверку типа в точке вызова. Ему достаточно, что StringBuilder можно присвоить в Object, а значит, всё хорошо.


Все носятся с null'ом — типа ошибка на миллион долларов… Реальная ошибка на миллион это реализация дженериков в Java 5… Эх, Мартин Мартин…

Вот интересно, кто то смог бы реализовать дженерики в Java по другому? (не создавая другой язык для jvm)

Всё же по-моему, от нулла больше реальных ошибок, чем от дженериков со стиранием.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории