Сопоставление с образцом для instanceof [Java 17]

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

Сопоставление с образцом для оператора instanceof позволяет избежать шаблонного кода для проверки типа и приведения к переменной более лаконично. Давайте разберемся с сопоставлением с образцом более подробно на нескольких примерах.

1. Традиционный подход

Зачастую в приложении нам необходимо проверить, относится ли объект к типу A или B, поскольку мы обрабатываем каждый тип по-разному.

Например, Customer может быть типа BusinessCustomer или PersonalCustomer. В зависимости от типа клиента мы можем извлекать информацию на основе контекста. Здесь для каждого типа происходит три вещи:

  • тест(экземпляр клиента PersonalCustomer)
  • конверсия(преобразование клиента в PersonalCustomer или BusinessCustomer)
  • объявление новой локальной переменной(pc или bc)

Обратите внимание, что шаг приведения кажется ненужным, поскольку мы уже проверили экземпляр в операторе if. Улучшение сопоставления с образцом пытается избежать этого шаблонного кода, как показано в следующем разделе.

Customer customer = null;String customerName;if(customer instanceof PersonalCustomer){PersonalCustomer pc =(PersonalCustomer) customer; //Redundant castingcustomerName = String.join(" ", pc.getFirstName(), pc.getMiddleName(), pc.getLastName());}else if(customer instanceof BusinessCustomer){BusinessCustomer bc =(BusinessCustomer) customer; //Redundant castingcustomerName = bc.getLegalName();}

2. Сопоставление с образцом

Теперь, с сопоставлением с образцом для instanceof, мы можем написать аналогичный код следующим образом. Здесь мы можем сократить шаблонный код приведения типов(т.е. приведение customer к pc).

В следующем примере переменная customer тестируется с типом PersonalCustomer; если Predicate имеет значение true, он присваивается переменной pc. Аналогичная проверка шаблона выполняется для типа BusinessCustomer.

Customer customer = null;String customerName;if(customer instanceof PersonalCustomer pc){customerName = String.join(" ", pc.getFirstName(), pc.getMiddleName(), pc.getLastName());}else if(customer instanceof BusinessCustomer bc){customerName = bc.getLegalName();}

Таким образом, по сути, шаблон проверки типа(используемый в instanceof) состоит из предиката, определяющего тип, и одной переменной привязки. Из приведенного выше определения мы можем сделать вывод, что шаблон представляет собой комбинацию:

  • предикат, который может быть применен к цели, и
  • набор переменных привязки, которые извлекаются из цели только в том случае, если предикат успешно применяется к ней

В приведенном ниже коде фраза String s является шаблоном проверки типа:

if(obj instanceof String s) {// can use 's' here} 

Обратите внимание, что шаблон будет соответствовать, а s будет присвоен только в том случае, если obj не равен null.

3. Область действия переменных

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

В следующем примере оператор печати будет выполнен только в том случае, если предикат не сработает, поэтому этот оператор даже не компилируется.

if(!(obj instanceof String s)) {//System.out.println(s); //compiler error - cannot access 's' here}

Переменная доступна в окружающем ее блоке if, и мы не можем получить к ней доступ за его пределами.

Object obj = new Object();if(obj instanceof String s) {System.out.println(s); //can use 's' here} else if(obj instanceof Number n) {//System.out.println(s); //can not use 's' here}//System.out.println(s); //can not use 's' here

Если мы пишем сложные условные операторы в операторе if, то мы можем использовать переменную-образец только с оператором &&(AND), потому что доступ к переменной будет осуществляться только тогда, когда предикат будет проверен на истинность. Мы не можем использовать переменную с оператором ||(OR), потому что предикат может быть проверен на ложность в нескольких случаях, и тогда мы будем иметь исключения разного рода.

//Allowed to use s in complex conditionif(obj instanceof String s && s.startsWith("a")) {System.out.println(s);}//compiler errorif(obj instanceof String s || s.startsWith("a")) {System.out.println(s);}

4. Заключение

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

Исходный код на Github

Прокрутить вверх