Java. Лямбда-вирази для узагальнених функціональних інтерфейсів. Приклади




Лямбда-вирази для узагальнених функціональних інтерфейсів. Приклади


Зміст


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

1. Особливості використання узагальнень (шаблонів) в функціональних інтерфейсах

Функціональний інтерфейс може бути узагальненим (шаблонним). У цьому випадку цільовий тип лямбда-вираз визначається на основі типу, вказаному у посиланні на цей функціональний інтерфейс.

Наприклад. Нехай задано узагальнений функціональний інтерфейс IValue

// Узагальнений (шаблонний) функціональний інтерфейс.
// Цей інтерфейс оперує узагальненим типом T.
interface IValue<T> {
  T GetValue();
}

Інтерфейс IValue<T> оперує узагальненим типом T. В інтерфейсі оголошується абстрактний метод GetValue(), який повертає значення типу T. Отже, цей функціональний інтерфейс є сумісний з будь-яким лямбда-виразом, що приймає один параметр і повертає значення цього ж типу.

При оголошенні посилання на функціональний інтерфейс IValue<T> в аргументі типу потрібно вказати цільовий тип лямбда-виразу:

// Оголосити посилання на функціональний інтерфейс IValue
// який буде оперувати типом Float
IValue<Float> refIValue;

Після цього можна сформувати лямбда-вираз та викликати метод GetValue()

// Встановити лямбда-вираз з прив'язкою до типу Float
refIValue = () -> 3.1415f; // повернути значення типу float

// Викликати метод GetValue(), який поверне 3.1415f
float v = refIValue.GetValue(); // v = 3.1415

Якщо при формуванні лямбда-виразу спробувати повернути значення іншого (несумісного) типу

refIValue = () -> "Hello world!"; // тут тип String а не Float

то компілятор видасть помилку на кшталт

Type mismatch: cannot convert from String to Float

Щоб лямбда-вираз повертав тип String, потрібно оголосити нове посилання на інтерфейс IValue з аргументом типу String (IValue<String>).

 

2. Розв’язки задач на побудову лямбда-виразів, що реалізують узагальнені функціональні інтерфейси. Приклади
2.1. Побудова лямбда-виразу, що повертає числове значення

У прикладі демонструється:

  • оголошення узагальненого (шаблонного) функціонального інтерфейсу IValue<T>, що оперує типом T;
  • побудова лямбда-виразу та його використання для числового типу Float. Лямбда-вираз реалізує узагальнений функціональний інтерфейс IValue<T>.

 

// Узагальнений (шаблонний) функціональний інтерфейс.
// Цей інтерфейс оперує узагальненим типом T.
interface IValue<T> {
  T GetValue();
}

public class TrainLambda02 {

  public static void main(String[] args) {
    // Оголосити посилання на функціональний інтерфейс IValue
    // який буде оперувати типом Float
    IValue<Float> refIValue;

    // Встановити лямбда-вираз з прив'язкою до типу Float
    refIValue = () -> 3.1415f; // повернути значення типу float

    // Викликати метод GetValue(), який поверне 3.1415f
    float v = refIValue.GetValue(); // v = 3.1415
    System.out.println("v = " + v);
  }
}

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

v = 3.1415

 

2.2. Лямбда-вираз, що реалізує поелементне додавання масивів чисел

Умова задачі. Розробити програму, в якій здійснюється поелементне додавання масивів з 10 чисел. Тип чисел може бути будь-яким числовим (int, double, float, …). Додавання масивів реалізувати з допомогою лямбда-виразу.

 

Розв’язок. Щоб додавати два масиви чисел, потрібно реалізувати функціональний інтерфейс ISumArrays, який містить один метод SumArrays(). Цей метод повинен отримувати два параметри – масиви чисел. Метод повинен повертати результат – масив чисел, що є сумою двох масивів-параметрів.

В умові задачі сказано, що тип чисел може бути будь-яким числовим (int, double, float, …). Це означає, що потрібно розробити узагальнений (шаблонний) інтерфейс ISumArrays для деякого типу T. Оскільки, тип T обмежується числовими типами, то його потрібно обмежити типом Number.

У функції main() потрібно протестувати роботу створеного функціонального інтерфейсу.

Нижче наведено текст програми, що розв’язує дану задачу.

// Шаблонний функціональний інтерфейс ISumArrays
interface ISumArrays<T extends Number> {
  T[] SumArrays(T[] A, T[] B);
}

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

  public static void main(String[] args) {
    // 1. Оголосити посилання на ISumArrays для типу Double
    ISumArrays<Double> ref;

    // 2. Створити два масиви типу double
    Double[] A1 = { 2.5, 1.4, 0.9, 1.1, 2.7, 2.9, 1.3, 2.0, 5.5, 1.2 };
    Double[] A2 = { 1.5, 1.0, 0.6, 1.7, 0.7, 0.2, 0.3, 0.2, 1.1, 3.3 };

    // 3. Сформувати лямбда-вираз для типу Double
    ref = (A, B) -> {
      Double[] C = new Double[A.length]; // числовий тип у масивах
      for (int i=0; i<A.length; i++)
      {
        // додати два числа як double
        C[i] = A[i].doubleValue() + B[i].doubleValue();
      }
      return C;
    };

    // 4. Викликати метод функціонального інтерфейсу
    Double[] A3 = (Double[])ref.SumArrays(A1, A2);

    // 5. Вивести результат
    System.out.print("A3: ");
    for (Double t : A3)
      System.out.print(" " + t);
    System.out.println();
  }
}

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

...

ref = (A, B) -> {
  Double[] C = new Double[A.length]; // числовий тип у масивах
  for (int i=0; i<A.length; i++)
  {
    // додати два числа як double
    C[i] = A[i].doubleValue() + B[i].doubleValue();
  }
  return C;
};

...

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

 

2.3. Обчислення кількості входжень заданого елементу в масиві

Умова задачі. Розробити програму, яка демонструє використання лямбда-виразу для пошуку елементу в масиві. Програма повинна містити узагальнений функціональний інтерфейс. Лямбда-вираз реалізувати для типу String.

Розв’язок. Текст програми, що розв’язує дану задачу наступний.

 

// Шаблонний функціональний інтерфейс IFindItem
interface IFindItem<T> {
  // метод, що обчислює кількість входжень
  // заданого елементу в масиві чисел
  int Search(T item, T[] items);
}

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

  public static void main(String[] args) {
    // 1. Оголосити посилання на функціональний інтерфейс
    //   для типу String
    IFindItem<String> ref;

    // 2. Визначити лямбда-вираз
    ref = (item, items) -> {
      int count=0;
      for (int i=0; i<items.length; i++)
        if (item==items[i])
          count++;
      return count;
    };

    // 3. Створити масив рядків
    String[] AS = { "abc", "abd", "def", "acf", "abc", "afx" };

    // 4. Протестувати лямбда-вираз
    int count = ref.Search("abc", AS);
    System.out.println("count = " + count); // count = 2
  }
}

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

count = 2

 


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