Java. Генерування виключень в лямбда-виразах. Приклади

Генерування виключень в лямбда-виразах. Приклади


Зміст


Пошук на інших ресурсах:




1. Особливості генерування виключень в лямбда-виразах

Бувають випадки, коли у лямбда-виразах може виникнути виключна ситуація. У цьому випадку лямбда-вираз повинен згенерувати виключення. Генерування виключення лямбда-виразом реалізується стандартним способом з допомогою оператора throw. Фрагмент, що перевіряється у лямбда-виразі береться у блок try-catch.

Як і в методі, у лямбда-виразі можна генерувати виключення двох видів:

  • наперед визначених типів Java (ArithmeticException, ArrayIndexOutOfBoundsException і т.д.);
  • власноруч розроблених класів виключень.

 

2. Приклади генерування стандартного виключення в лямбда-виразі
2.1. Ділення двох чисел. Генерування виключення ділення на нуль

У прикладі наводиться лямбда-вираз, який повертає результат ділення двох чисел. У коді лямбда-виразу перевіряється значення дільника. Якщо це значення рівне 0, то генерується стандартне виключення ArithmeticException з відповідним повідомленням.

// Генерування виключень у лямбда-виразах
// Оголосити функціональний інтерфейс
interface IDivNumbers {
  // Оголосити метод, який ділить два числа
  double Division(double a, double b);
}

// Клас, що містить методи, які реалізують лямбда-вираз та
// тестують роботу програми.
public class Lambda {

  public static void main(String[] args) {

    // 1. Оголосити посилання на IDivNumbers
    IDivNumbers ref;

    // 2. Реалізувати лямбда-вираз, який ділить два числа і
    //     при необхідності генерує виключення
    ref = (a, b) -> {             
      try {
        // Обробити перевірку ділення на 0
        if (b==0)
          throw new ArithmeticException("Exception: divide by zero.");
          return a/b; // якщо b!=0, то повернути результат ділення
      }
      catch (ArithmeticException e) {
        System.out.println(e.getMessage()); // Вивести повідомлення
        return 0.0;
      }                  
    };

    // 3. Протестувати лямбда-вираз на виключну ситуацію
    double res = ref.Division(5, 0); // Exception: divide by zero.

    // 4. Вивести результат
    System.out.println("res = " + res); // res = 0.0
  }
}

Результат виконання програми

Exception: divide by zero.
res = 0.0

 

2.2. Поелементне сумування масивів. Шаблонний функціональний інтерфейс. Генерування виключення в лямбда-виразі. Передача лямбда-виразу в метод

Умова задачі. Використовуючи механізм лямбда-виразів реалізувати поелементне додавання масивів узагальненого типу T. Лямбда-вираз повинен обробляти нижчевказані виключення, які генеруються у випадку, якщо масиви не відповідають заданим вимогам.

Основні вимоги до масивів:

  • масиви повинні підтримувати роботу з числовими типами.
  • масиви повинні мати ненульову довжину. Якщо один з масивів має нульову довжину, то згенерувати виключення EmptyArrayException. Для реалізації виключення EmptyArrayException розробити однойменний клас;
  • масиви повинні мати однакову довжину. Якщо масиви мають різну довжину, то згенерувати стандартне виключення ArrayIndexOutOfBoundsException.

Лямбда-вираз повинен передаватись в метод як параметр. Для виконання цього потрібно оголосити додатковий клас з методом, який отримує лямбда-вираз в якості параметру.

У функції main() продемонструвати використання лямбда-виразів для обробки виключень.

Розв’язок. Згідно з умовою задачі у програмі потрібно ввести наступні класи та інтерфейс:

  • узагальнений (шаблонний) функціональний інтерфейс ISumArrays<T>, який оперує числовим типом T. Тип інтерфейсу обмежується типом Number (усі числові типи). В інтерфейсі потрібно визначити метод SumArrays(), який отримує параметром два масиви та повертає результуючий масив;
  • клас EmptyArrayException, який визначає виключення, що виникає у випадку, коли один з масивів має нульову довжину;
  • клас ArrayMethod, який містить єдиний метод AddMethod(). Цей метод отримує три параметри: два масиви-доданки та лямбда-вираз у вигляді посилання на ISumArrays<T>;
  • клас Lambda, в якому оголошується функція main(). У функції main() створюються тестувальні масиви для різних типів та лямбда-вираз. Ці всі дані передаються в метод AddMethod() екземпляру класу ArrayMethod.

Текст розв’язку задачі наведено нижче

// Генерування виключень у лямбда-виразах
// Оголосити узагальнений функціональний інтерфейс,
// який оперує типом T. Тип T обмежується числовими типами (Number).
interface ISumArrays<T extends Number> {
  // Метод, що отримує два масиви та повертає масив
  T[] SumArrays(T[] array1, T[] array2);
}

// Клас, що визначає виключення, яке виникає коли один з масивів
// має нульову довжину. Клас повинен бути успадкований з класу Exception
class EmptyArrayException extends Exception {
  // Конструктор класу
  EmptyArrayException(String message) {
    super(message); // викликати конструктор суперкласу
  }
}

// Узагальнений клас, що містить метод, в який передається лямбда-вираз.
// Для просумовування елементів метод викликає інший метод SumArrays()
// інтерфейсу ISumArrays.
class ArrayMethod<T extends Number> {
  // Метод, що отримує лямбда-вираз в якості параметру
  public T[] AddMethod(T[] array1, T[] array2, ISumArrays<T> ref) {   
    T[] array3 = null;
    array3 = ref.SumArrays(array1, array2); // повернути суму масивів 
    return array3;
  }
}

// Клас, що містить методи, які реалізують лямбда-вираз та
// тестують роботу програми.
public class Lambda {

  public static void main(String[] args) {
    // 1. Реалізація для масивів типу Double
    // 1.1. Оголосити посилання на інтерфейс ISumArrays<T>
    ISumArrays<Double> ref;

    // 1.2. Сформувати лямбда-вираз з прив'язкою до типу Double
    ref = (array1, array2) -> {
      try {
        // Перевірка на нульову довжину масивів
        if (array1.length==0)
          throw new EmptyArrayException("array1 is empty."); 
        if (array2.length==0)
          throw new EmptyArrayException("array2 is empty.");

        // Перевірка на рівність елементів в масивах
        if (array1.length!=array2.length)
          throw new ArrayIndexOutOfBoundsException("Arrays are not equal");
      }
      catch (EmptyArrayException e) {
        System.out.println(e.getMessage());
        return null;
      }
      catch (ArrayIndexOutOfBoundsException e) {
        System.out.println(e.getMessage());
        return null;
      }

      // Код просумовування масивів
      Double[] array3 = new Double[array1.length];         
      for (int i=0; i<array1.length; i++)
        array3[i] = array1[i] + array2[i];            
      return array3;
    };

    // 1.3. Оголосити два масиви різної довжини
    Double[] AD1 = { 2.0, 1.5, 3.8 };
    Double[] AD2 = { 1.1, 4.0 };

    // 1.4. Викликати метод AddMethod() з класу ArrayMethod<T>
    Double[] AD3;
    ArrayMethod<Double> obj = new ArrayMethod<Double>();
    AD3 = obj.AddMethod(AD1, AD2, ref);

    // 1.5. Вивести масив AD3
    if (AD3 != null) {
      System.out.println("Array AD3:");
      for (int i=0; i<AD3.length; i++)
        System.out.print(" " + AD3[i]);
      System.out.println();
    }

    // 2. Реалізація масивів однакової довжини
    // 2.1. Оголосити масиви, що мають однаковий розмір
    Double[] AD4 = { 1.5, 2.5, 3.3 };
    Double[] AD5 = { 2.0, 1.8, 1.9 };

    // 2.2. Викликати метод просумовування масивів
    AD3 = obj.AddMethod(AD4, AD5, ref);

    // 2.3. Вивести масив AD3
    if (AD3 != null) {
      System.out.println("Array AD3:");
      for (int i=0; i<AD3.length; i++)
        System.out.print(" " + AD3[i]);
      System.out.println();
    }        
  }
}

Результат роботи програми

Arrays are not equal
Array AD3:
3.5 4.3 5.199999999999999

 

3. Приклад генерування виключення, яке обробляється спеціально розробленим класом

Умова задачі. Розробити клас NegativeRootException, який обробляє виключення що виникає при спробі взяття кореня квадратного з від’ємного числа. Реалізувати лямбда-вираз, який обчислює площу трикутника за довжинами його сторін. Розрахунок ведеться за формулою Герона. Якщо у формулі Герона виникає корінь з від’ємного числа (трикутник не існує), то згенерувати виключення NegativeRootException. Виключення повинно генеруватись в лямбда-виразі.

Розв’язок. Текст розв’язку задачі наступний.

// Генерування виключень у лямбда-виразах
// Оголосити функціональний інтерфейс
interface INegativeRoot {
  // Оголосити метод, визначає площу трикутника за його сторонами
  double AreaTriangle(double a, double b, double c);
}

// Створити клас виключення, який обробляє корінь квадратний з від'ємного числа
// Таке виключення є контрольоване (checked).
class NegativeRootException extends Exception {
  // Конструктор класу
  NegativeRootException(String message) {
    super(message); // викликати конструктор суперкласу Exception
  }
}

// Клас, що містить методи, які реалізують лямбда-вираз та
// тестують роботу програми.
public class Lambda {

  @SuppressWarnings("finally")
  public static void main(String[] args) {

    // 1. Оголосити посилання на INegativeRoot
    INegativeRoot ref = null;

    // 2. Реалізувати лямбда-вираз, який обчислює площу
    //    трикутника за формулою Герона
    ref = (a, b, c) -> {
      double p = (a+b+c)/2; // півпериметер
      double t = p*(p-a)*(p-b)*(p-c); // підкореневий вираз

      try {
        // перевірка на від'ємний корінь з генеруванням виключення
        if (t<0) {
          t=0;
          throw new NegativeRootException("Exception: negative root.");
        }
        return Math.sqrt(t);
      }
      catch (NegativeRootException e) {
        t = 0;
        System.out.println(e.getMessage());
      }
      finally {
        // Блок, який виконується завжди
        return t;
      }
    };

    // 3. Протестувати лямбда-вираз на виключну ситуацію
    double res = ref.AreaTriangle(1, 1, 5); // Exception: negative root.

    // 4. Вивести результат
    System.out.println("res = " + res); // res = 0.0
  }
}

Після виконання програма видасть наступний результат

Exception: negative root.
res = 0.0

 


Зв’язані теми