This article will probably get updates

Сразу оговорюсь(Disclaimer, if you wish): эта заметка не является инструкцией к действию. Я не утверждаю, что надо делать так или иначе. Сдесь всего лишь собраны конструкции, которые произвели на меня впечатление любого рода, будь то понимание, что конструкция невероятно полезна или являет собой совершеннейший бред. Не важно. Просто имейте в виду, что так сделать можно, и не приписывайте мне выводов, вроде того стоит ли делать так или нет. Спасибо за понимание!

Local return

Почернутый из опыта одного бывшего C-программиста, который в какой-то момент стал моим коллегой. В его коде это выглядело как бесполезный цикл, на который я и обратил внимание. Примерно так вот:

do{
	//lots of if checks
}while(false);

Расспросы прояснили, что эту конструкцию коллега перенес из своего опыта программирования на C. Суть конечно же не в самом цикле, выполняющемся лишь единожды, но в том, что из него можно в любой момент выйти с помощью ключевого слова break. Коллега описал эту конструкцию как “goto without being blamed for bad code”. Я почувствовал некоторую необязательность цикла и решил её проверить. Как программист-практик я не читал спецификацию языка Java полностью. Лишь иногда заглядываю в неё при нужде или, как в этом случае, лёгком интересе. И в данном случае интерес был удовлетворен с лихвой. JLS7 (какая была под рукой) гласит:

14.7 Labeled Statements
Statements may have label prefixes.

Statements! Не Cycles/Loops, а Statements! Раньше я полагал что это механизм для управлением потоком исполнения со многими вложенными циклами, но оказалось, что это механизм более общий. Тут же я набросал простой пример, который лишь продемонстрировал то, что я теперь знал.

public static void main(String[] args)
{
	System.out.println("1");
	test :
	{
		System.out.println("2");
		if (true)	// эта проверка мешает компилятору 
				// понять что строка 3 недостежима
		{
			break test;
		}
		System.out.println("3");// 3
	}
	System.out.println("4");
}

Вывод программы:

1
2
4

Как видете, мы просто вышли из блока кода, не выполняя его до конца. В оригинальном коде было много проверок. Это был какой-то кусок валидатора. Логично было игнорировать остаток кода, если одна проверка провалилась. Тут конечно можно рассказывать, что надо было этот код сделать методом с логическим возвратным типом и в основном коде просто делать вызов в условии if. Мне лишь остаётся процитировать не помню кого именно: Важен не инструмент, а то, как ты его используешь. В конце концов цитата тоже инструмент и не важно кто сказал эти слова, важно … ну вы поняли :-).

Enum strategy

В Java enum - не просто набор констант. В какой-то момент было решено, что обычные константы в силе C небезопасны. Если у вас есть два статически импортированных класса с константами, имеющими одинаковое имя, никогда не знаешь какой из них ты используешь по имени константы. Это может привести к неприятным последствиям. Среда импортировала не то, а потом у тебя в базе данных в нужном поле не то значение. Если же от него зависит важная бизнесс-логика, то это вообще катастрофа. Посему было решено сделать перечислимые константы типо-безопасными. Сегодня каждый enum в Java это по сути абстрактный класс. Каждая “константа” внутри него - экземпляр наследника этого класса. Теперь невозможно присвоить “константу” полю не того типа, не сделав при этом явных преобразований. Замечательно! Кроме того в Java инамы получили синтаксическую поддержку в самом языке, что сделало работу с ними ещё удобнее. Однако и на этом не всё. Поскольку enum это класс, появляется возможность наделить его некоторым поведением. Согласно заветам Линуса Торвальдса, сразу покажу код.

enum Operation{
    ADD,
    MULTIPLY;

    abstract double apply(double a,double b);
}

Тут ваша среда разработки услужливо подсветит ADD и MULTIPLY. Ведь они по сути - подклассы, а значит должны дать реализацию абстрактному методу apply. Поддадимся зову подсказки.

enum Operation{
    ADD{
    	@Override
    	double apply(double a,double b){
    		return a + b;
    	}
    },
    MULTIPLY{
    	@Override
    	double apply(double a,double b){
    		return a * b;
    	}
    };

    abstract double apply(double a,double b);
}

Для сурового джависта с 25 годами опыта коммерческой разработки это всё покажется ерундой. В принципе ничего нового в показанном нет. Это обычная объектно-ориентированная техника. Полиморфизм, все дела. Но насколько этот подход более удобен по сравнению даже с полиморфной иерархией классов! Приведу пример. У вас есть три поля на красивом web-UI: два для значений численных и одно - выпадающий список операций над значениями этих полей. На значение последнего бэкенду надо реагировать по разному. У вас там AJAX, все дела, и ваш REST-endpoint получает некий объект, например, десериализованный из JSON. Каким может быть наш код? Например таким:

public Double react(double a, double b, String operation){
	if("ADD".equals(operation)){
		return a + b;
	} else if("MULTIPLY".equals(operation)){
		return a * b;
	} else {
		return null;
	}
}

Не очень красиво. При увеличении количества операций даже switch не поможет выполнить задачу красиво и кратко. Теперь посмотрим что можно написать используя enum.

public Double react(double a, double b, String operation){
	return Operation.valueOf(operation).apply(a,b);
}

Всё! По-моему это миленько :-). А наполнять список полей, к слову, можно из Operation.values() при не обходимости преобразовывая текстовое представление имён или же просто определить в enum финальное поле с именем и получать его значение.

На этом дайджест любопытных паттернов завершается. Однако, эта заметка не каменная. Я обязательно её пополню новыми приёмами в написании кода если мне на таковые укажут ;-).