Комментарии 43
Ну вот, вы сломали автора, подав на вход незнакомое слово.
Тоже разочарован, увидев многабукфф вместо чего-нибудь полезного (ожидал рассказа об устройстве Optional, но не увидел даже сравнения эффективности Optional и Nullable).
Я планировал в последней статье серии порекомендовать читателям посмотреть исходый код класса Optional. Это того стоит. Кстати, он поразительно компактен. Однако, ни изучение его внутреннего строения, ни сравнение эффективности не входит в задачи этого Tutorial. В моём понимании Tutorial, как жанр технических публикаций, нацелен на обучение использовать тот или иной инструмент.
Да, на мой взгляд проще понять ー Optional без всяких аналогий, чем вникнуть в эту уйму объектов и взаимодействий между ними…
Цель, которую я преследую в этой серии — показать использование Optional при работе с объектами, которые могут менять свою структуру. Для этого и были привлечены простые с точки зрения понимания физические модели.
понравилась логика статьи, но показалось, что декорации (вода, кофе и тд) подобраны не, как бы так сказать, удобно. Легче воспринимать что-то, с чем приходится работать. Хотя посмотрев это сквозь такую призму, имеешь в кармане еще один пример, как объяснить джуну пользу сие чуда.
Зачем там этот result в виде поля?
Зачем вообще метод mix? Чем MixedWater::new и Optional.map не устраивает?
А чтобы продемонстрировать ifPresent?
Так это плохой пример. Так делать не надо.
ifPresent/isPresent нужны в момент, когда вы хотите перейти от упакованного значения к самому значению. Т.е. когда вы хотите его куда то передать, где не принимают Optional.
А так вышло, что плохому учите.
Понятно, что это отнюдь не вся область применения Optional.
Засучите рукава и как Moriline приведите свои примеры. Или по совету Danik-ik приведите ссылку. Это поможет коллегам по сайту.
Дорогие недовольные! Большая просьба написать лучше или дать ссылку. При этом непременно именно "на то, с чем я работаю каждый день", ибо программисты наверняка все настолько одинаковые, что имеют рост 191 и размер обуви 46.
Всё, перестал ёрничать.
Может быть, примеры и в вакууме, но лично мне они показали удобство использования Optional вместо null, стоило только представить себе обратный случай. А обратный случай у меня в практике есть, пришлось даже писать собственный optional класс. А язык-то у меня без женериков, да…
P.S. даже если Вы дадите ссылку на идеальную статью по теме, я её увижу в комментариях именно к ЭТОЙ статье. Как-то так...
Она раскрывает в простейших примерах прикладные аспекты использования Optional в Java в формате "прочитай, пока в маршрутке"?
Нет, я не умаляю достоинств упомянутого материала, мне просто претит хайп о ненужности на Хабре "неидеальных" статей. В Интернете кто-то неправ, да.
Я польщён, что Вы прочитали эту статью, не зная Java. Но всё же — целевая группа этой серии — практикующие Java — программисты.
Эта стья не последняя из серии. О некоторых более общих аспектах, выступающих за рамки Tutorial, я планирую поговорить в последней статье этой серии. Но и там я не планирую писать о более общих концепциях. Это другая тема.
1. Введены лишние абстракции(ИМХО — класс CupOfBoiledWater). Как вариант, можно использовать этот код в примере для бойлера:
final class CupOfWater {
private final boolean powerAvailable;
public CupOfWater(boolean powerAvailable) {
this.powerAvailable = powerAvailable;
}
/** Return cups of water.
* @return Iterator<Water>
*/
public Iterator<Water> get(Integer numberOfCups) {
return (this.powerAvailable)? fill(numberOfCups, 90).iterator(): fill(numberOfCups, 10).iterator();
}
private List<Water> fill(Integer number, Integer temperature) {
List<Water>list = new ArrayList<Water>();
for(int i=0;i<number;i++) {
list.add(new Water(10L, temperature));
}
return list;
}
}
final class Water{
private final Long volume;
private final Integer temperature;
public Water(Long volume, Integer temperature) {
this.volume = volume;
this.temperature = temperature;
}
/** Return volume in millilitres of water.
* @return Long
*/
public Long volume() {
return this.volume;
}
/** Return temperature of water in Celsius scale.
* @return Integer
*/
public Integer temperature() {
return this.temperature;
}
@Override
public String toString() {
return "Water [volume=" + volume + ", temperature=" + temperature + "]";
}
}
final class Boiler {
private final CupOfWater water;
public Boiler(CupOfWater water) {
this.water = water;
}
public Iterator<Water> getCupOfWater() {
return water.get(2);
}
}
public class Main {
public static void main(String[] args) {
boilerTest();
}
public static void boilerTest() {
Iterator<Water>iterator = new Boiler(new CupOfWater(true)).getCupOfWater();
if(iterator.hasNext()) {
while (iterator.hasNext()) {
Water water = (Water) iterator.next();
System.out.println(water.toString());
if(water.temperature() > 10) {
// water is hot!
}else {
//water is cold!
}
}
}else {
System.out.println("water is not exists.");
}
}
}
2.
Но в большинстве практически интересных задач на вход подаются не простые переменные, а объекты. В том числе такие, которые могут принимать значение null.Автор предполагает существование null в качестве параметра при вызове его методов. Я предлагаю его избегать/отказаться всеми способами и на уровне кода и на уровне архитектуры. Как это делать — другая тема.
3.
Если дождевая вода не собрана, то на входе мы имеем нулевой объект, иначе – нормальный объект.И вот тут абстракции начинают течь. Бак имеет ёмкость с какой-то шкалой или объемом. Объем не может отсутствовать вообще у данного объекта так как это один из главных его параметров! Он может быть равным 0 и уже тем более не отрицательным. Он также может быть 1,2,3,4 и так далее. Если автор имел ввиду не бак, а подачу воды в водопроводе — там та же картина — вода хоть там, хоть там имеет свой объем в каких-то единицах. И он может быть только от 0 и выше. Но трактовку понятия «отсутствия воды» каждый видит по своему и в этом кроется ошибка. Я предлагаю вариант как «объект с параметром 0».
4.
Если запрашиваемого ресурса на момент запроса нет, и мы не хотим возвращать null, нам остается одно средство – выбросить Exception.
На этот счёт я говорил в прошлых комментариях — надо возвращать коллекцию, список, массив или итератор элементов. И тогда все будет хорошо.
Про лишние абстракции. Я заметил, что совсем абстрактные примеры со списками из строк или чисел часто «не зацепляют» и быстро забываются. Поэтому я предпочитаю использовать «материальные» примеры. Но они опасны тем, что моделируемые обьекты реального мира имеют важные с физической точки зрения, но несущественные с дидактической точки зрения свойства. Например — количество воды в ёмкости. В примерах я пытался от этих второстепенных аспектов по возможности абстрагироваться.
Мы часто не можем избежать возможный null в качестве параметра, если вынуждены использовать чужие API или работаем в многоязыковых средах.
Может Вы сами или кто-то из читателей попробует?
Аналогичная проблема в оригинальном решении. Чашка не кипятит воду которая внутри чашки, потому иметь функцию boil в CupOfWater классе довольно не логично.
В (3) Вы сами растворили абстракцию. Обьём бака здесь совсем ни при чём. Может, там не бак вообще, а скважина. Мы либо получили порцию воды из приоритетного источника, либо нет. Вы, кажется, преждевременно оптимизируете модель, назначение которой не создать максимально близкий к реальности переключатель воды, а продемонстрировать простейшее употребление Optional в максимальном количестве поз.
Мы либо получили порцию воды из приоритетного источника, либо нет.А в чём КОНКРЕТНО Вы эту воду получили? В каких единицах?
Просто неправильно использовать аргументы из анекдота про блондинку, динозавров и теорию вероятностей. И не зря же есть возраст у каждого человека в каких-то единицах, а не просто — или человек есть или его нет? И температура на Земле тоже в каких-то единицах, а не просто — или есть или нет! А теперь главное. Если стоять на позиции что тут мы играем, тут не играем, а тут мы рыбу заворачиваем — то так мы из первобытно-общинного строя с применением принципа «лично мое мнение» в ИТ не выйдем очень долго, не говоря уже про науку и научный метод.
1. Примеры странные и неубедительные. Складывается ощущение, что от Optional всё стало громоздко.
2. И всё-таки это since java 8
Некоторые вещи надо начать пробовать применять и тогда становится понятной их прелесть. В этом Вам могут помочь примеры из других параграфов статьи.
public class WaterDispenser implements IWaterDispenser{
private final List<Water> water = new ArrayList<>();
@Override
public void setAvailability(Iterator<Water> input) {
water.clear();
while (input.hasNext()) {
water.add(input.next());
}
}
@Override
public Iterator<Water> getCupOfWater() {
return !this.water.isEmpty()?this.water.iterator():new CupOfWater(false).get(5);
}
public static void main(String[] args) {
IWaterDispenser waterDispenser = new WaterDispenser();
waterDispenser.setAvailability(Collections.EMPTY_LIST.iterator());
Iterator<Water>one = waterDispenser.getCupOfWater();
//expected 5 items of water
while (one.hasNext()) {
System.out.println(one.next());
}
waterDispenser.setAvailability(Arrays.asList(new Water(20L, 10)).iterator());
Iterator<Water>two = waterDispenser.getCupOfWater();
//expected 1 item of water
while (two.hasNext()) {
System.out.println(two.next());
}
}
}
interface IWaterDispenser{
void setAvailability(Iterator<Water> input);
Iterator<Water> getCupOfWater();
}
Объект в футляре или Optional в Java 8 и Java 9. Часть 2: «Как это делается в Java 8»