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

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

Это такое сложное объяснение монады Maybe?

Ну вот, вы сломали автора, подав на вход незнакомое слово.


Тоже разочарован, увидев многабукфф вместо чего-нибудь полезного (ожидал рассказа об устройстве Optional, но не увидел даже сравнения эффективности Optional и Nullable).

Да Вы задира, однако. Какое из 6 слов меня сломало, по Вашему мнению? (Шутка)
Я планировал в последней статье серии порекомендовать читателям посмотреть исходый код класса Optional. Это того стоит. Кстати, он поразительно компактен. Однако, ни изучение его внутреннего строения, ни сравнение эффективности не входит в задачи этого Tutorial. В моём понимании Tutorial, как жанр технических публикаций, нацелен на обучение использовать тот или иной инструмент.
Какая ужасная аналогия… Вроде и знаешь, а осознать в термина чистой/грязной воды, кранов и кружек невозможно абсолютно. Ибо, бессмысленно.

Да, на мой взгляд проще понять ー Optional без всяких аналогий, чем вникнуть в эту уйму объектов и взаимодействий между ними…

Допускаю, что для определённой (возможно, весьма большой) категории Java-разработчиков проще познакомиться с Optional на других примерах.
Цель, которую я преследую в этой серии — показать использование Optional при работе с объектами, которые могут менять свою структуру. Для этого и были привлечены простые с точки зрения понимания физические модели.
Мне очень понрав
понравилась логика статьи, но показалось, что декорации (вода, кофе и тд) подобраны не, как бы так сказать, удобно. Легче воспринимать что-то, с чем приходится работать. Хотя посмотрев это сквозь такую призму, имеешь в кармане еще один пример, как объяснить джуну пользу сие чуда.
Ох что то мне пованивает ваша реализация класса Mixer.
Зачем там этот result в виде поля?
Зачем вообще метод mix? Чем MixedWater::new и Optional.map не устраивает?
А чтобы продемонстрировать ifPresent?
Так это плохой пример. Так делать не надо.
ifPresent/isPresent нужны в момент, когда вы хотите перейти от упакованного значения к самому значению. Т.е. когда вы хотите его куда то передать, где не принимают Optional.
А так вышло, что плохому учите.
Разумеется, цель автора состояла не в доподлинном моделировании свойств и поведения реальных объектов, а в показе возможностей методов класса Optional с помощью сильно упрощённых физических моделей.
Причем тут физические модели? Я же не к физической модели претензии предъявляю. Можно было придумать уместный пример. Например, для вызова логгера ifPresent замечательно подходит.
Моя цель состояла не столько в том, чтобы рассказать о методах класса Optional. На эту тему есть другие статьи, в том числе упомянутые мной в начале статьи. Я хотел показать, как методы этого класса можно применять к объектам, чья структура в каком-то смысле меняется. Поэтому и «материальные» примеры.
Понятно, что это отнюдь не вся область применения Optional.
Засучите рукава и как Moriline приведите свои примеры. Или по совету Danik-ik приведите ссылку. Это поможет коллегам по сайту.
Да опять же претензия не к материальности. Туториал должен учить «хорошему». И прививать хороший стиль программирования. А по факту учит «плохому». Я вам привел правильный пример — вызов API, которое не знает об Optional. Аргументы из серии «сделай лучше» оставим за скобками.

Дорогие недовольные! Большая просьба написать лучше или дать ссылку. При этом непременно именно "на то, с чем я работаю каждый день", ибо программисты наверняка все настолько одинаковые, что имеют рост 191 и размер обуви 46.
Всё, перестал ёрничать.
Может быть, примеры и в вакууме, но лично мне они показали удобство использования Optional вместо null, стоило только представить себе обратный случай. А обратный случай у меня в практике есть, пришлось даже писать собственный optional класс. А язык-то у меня без женериков, да…
P.S. даже если Вы дадите ссылку на идеальную статью по теме, я её увижу в комментариях именно к ЭТОЙ статье. Как-то так...

Бартоз Малевски «Теория категорий для программистов».

Она раскрывает в простейших примерах прикладные аспекты использования Optional в Java в формате "прочитай, пока в маршрутке"?
Нет, я не умаляю достоинств упомянутого материала, мне просто претит хайп о ненужности на Хабре "неидеальных" статей. В Интернете кто-то неправ, да.

От уж мне эти «простейшие примеры». Первым комментарием я не в коей мере не хотел упрекнуть автора в ненужности статьи. Ч хотел обратить внимание на то, что описанная им концепция является частым случаем очень мощной и очень важной конструкции. И я не заметил в статье оператора join. Может плохо читал, джаву я почти не знаю.
Эта серия статей из категории Tutorial. Её цель — показать, как можно использовать класс Optional в тех или иных случаях. Возник замысел из попыток автора рассказать коллегам в разных углах нашей планеты об этом.
Я польщён, что Вы прочитали эту статью, не зная 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 или работаем в многоязыковых средах.
Очевидны естественные преобразования между Maybe a и List a. Если в списке не более одного элемента это преобразование будет ещё и изоморфизмом.
Эта серия статей из категории Tutorial. Её цель — показать, как можно использовать класс Optional в тех или иных случаях. Ваш пример любопытен и познавателен. Однако, в этой статье речь не о Maybe, а об Optional.
Вам предложили использовать списки, я написал, что в некотором смысле, это одно и тоже. И буду признателен, если вы мне объясните разницу между Optional<a*> и Maybe a. С категориальной точки зрения.
Увольте. Дайте мне сначала мою задумку с Optional в Java 8, Java 9 до конца довести. Я не считаю себя специалистом в области теории функционального программирования.
Может Вы сами или кто-то из читателей попробует?
Разница между ними в том, что Optional — это класс-контейнер в Java, а Maybe — функтор из теории категорий. Могли бы и сами догадаться...
Судя по тому что написано в статье Optional реализует Maybe в джаве. А если что-то крякает как утка, ходит как утка. плавает как утка, летает как утка, то я называю это уткой.
Вы не одиноки в таком мнении. Автор книги:
Functional Programming in Java
How functional techniques improve your Java programs
Pierre-Yves Saumont
Manning Pubn
ISBN 9781617292736
Говорит примерно тоже самое, правда не столь образно.(Шутка)
Я противник сравнения вещей из разных миров. Да, класс в языке программирования и абстрактное понятие некой теории по определению разные. Как слон и автомобиль. Но интересно сравнивать африкансого слона с индийским, а BMW с Toyota. Либо мы должны договориться, какие сравнительные характеристики вещей нам интересны. Например у слона и автомобиля это могут быть вес и скорость.
Вы сейчас вообще о чем?
О том, что я противник сравнивания объектов разной природы. Например классов языка программирования и теоретических концепций типа функтора. Поскольку они принадлежат разным мирам, они по определению разные.
Почему вы рассказываете это именно мне?
Мне казалось, мы дискутируем это начиная с вот этого Вашего комментария. Так или иначе, позиции ясны, тема исчерпана, имхо.
А мне казалось что я написал то же самое что пытаетесь сказать вы…
А может Вам и правда попробовать написать на тему соответствия реализации Optional положениям теории? Это было бы наверное многим интересно.
Почему чашка с водой вообще должна знать что-то про енергию? Чашка с водой может быть горячей или холодной, но вы ее не включаете в сеть.

Аналогичная проблема в оригинальном решении. Чашка не кипятит воду которая внутри чашки, потому иметь функцию boil в CupOfWater классе довольно не логично.
Почему чашка с водой вообще должнна знать что-то про енергию?

В модели чашки нет понятия энергии. Про энергию знает кипятильник.
А с функцией boil Вы правы. С реальной физикой процесса кипения это связано мало. Это допущение сделано, чтобы не отвлекаться на детали моделирования.

В (3) Вы сами растворили абстракцию. Обьём бака здесь совсем ни при чём. Может, там не бак вообще, а скважина. Мы либо получили порцию воды из приоритетного источника, либо нет. Вы, кажется, преждевременно оптимизируете модель, назначение которой не создать максимально близкий к реальности переключатель воды, а продемонстрировать простейшее употребление Optional в максимальном количестве поз.

Мы либо получили порцию воды из приоритетного источника, либо нет.
А в чём КОНКРЕТНО Вы эту воду получили? В каких единицах?
Просто неправильно использовать аргументы из анекдота про блондинку, динозавров и теорию вероятностей. И не зря же есть возраст у каждого человека в каких-то единицах, а не просто — или человек есть или его нет? И температура на Земле тоже в каких-то единицах, а не просто — или есть или нет! А теперь главное. Если стоять на позиции что тут мы играем, тут не играем, а тут мы рыбу заворачиваем — то так мы из первобытно-общинного строя с применением принципа «лично мое мнение» в ИТ не выйдем очень долго, не говоря уже про науку и научный метод.
Про соответствие предложенных моделей физической реальности я уже ответил здесь. Да, Вы правы. Разумеется воду кипятит прибор. Но для обьяснения действия Optional я решил сделать такое допущение.
Я конечно вижу профит от Optional и использую его. Но всё же и теперь вы не смогли убедить меня.
1. Примеры странные и неубедительные. Складывается ощущение, что от Optional всё стало громоздко.
2. И всё-таки это since java 8
Я специально выделил как отдельный параграф минимальное использование Optional. Это всего 5 методов. Остальные методы себя показывают, если Вы интенсивно будете использовать нововведения Java 8, в первую осередь streams.
Некоторые вещи надо начать пробовать применять и тогда становится понятной их прелесть. В этом Вам могут помочь примеры из других параграфов статьи.
5. Мой вариант для примера с заначкой может выглядеть так:
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 или Iterator.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории