Pull to refresh

Comments 43

Это такое сложное объяснение монады Maybe?
Нет. Это описание методов класса Optional из Java 8, что следует из названия статьи.

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


Тоже разочарован, увидев многабукфф вместо чего-нибудь полезного (ожидал рассказа об устройстве 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.
Sign up to leave a comment.

Articles