Java. Передача лямбда-виразу в метод в якості параметру. Приклади

Передача лямбда-виразу в метод в якості параметру. Приклади


Зміст


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




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

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

Існує два способи передачі лямбда-виразу в метод:

  • безпосередня передача лямбда-виразу. Цей спосіб добре підходить для лямбда-виразів з малою кількістю операторів;
  • передача посилання на функціональний інтерфейс, який зв’язаний з лямбда-виразом. У цьому випадку попередньо оголошується посилання на інтерфейс. Потім цьому посиланню присвоюється код лямбда-виразу. Цей спосіб доречний, коли лямбда-вираз стає надто довгим для вбудовування у виклик методу.

 

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

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

Спосіб 1. Спочатку оголошується функціональний інтерфейс IAverage, що містить метод, який отримує три параметри та повертає результат типу double

// Інтерфейс, що оголошує метод обчислення середнього
// арифметичного з 3-х чисел.
interface IAverage {
  double Avg(double a, double b, double c);
}

Наступним кроком потрібно оголосити метод, що буде отримувати посилання на інтерфейс IAverage в якості параметру. Цей метод може бути розміщений в деякому класі як показано нижче

// Клас, що містить реалізацію методу, який отримує
// параметром посилання на інтерфейс IAverage
class SomeClass {

  // Метод, який виводить на екран середнє арифметичне трьох чисел.
  // Метод отримує посилання на функціональний інтерфейс IAverage.
  // Програмний код обчислення середнього арифметичного формується
  // у лямбда-виразі, який передається аргументом у цей метод.
  public void PrintAverage(IAverage ref) {
    System.out.println("ref = " + ref.Avg(3, 7, 8));
  }
}

Після цього, у деякому клієнтському методі (наприклад, методі main()) потрібно передати відповідний лямбда вираз у метод PrintAverage() приблизно так:

...

public static void main(String[] args) {
  // Клієнтський код - демонструє передачу в метод лямбда-виразу
  // 1. Створити екземпляр класу SomeClass
  SomeClass obj = new SomeClass();

  // 2. Викликати метод PrintAverage() і передати йому лямбда-вираз
  obj.PrintAverage((a,b,c) -> (a+b+c)/3.0);
}

...

 

Спосіб 2. При цьому способі попередньо формується посилання на інтерфейс. Потім цьому посиланню присвоюється лямбда-вираз. Після цього це посилання передається в метод PrintAverage(). Такий підхід корисний, коли код лямбда-виразу надто великий і що ускладнює сприйняття виклику методу. Нижче наведено змінений код попереднього прикладу.

...

public static void main(String[] args) {
  // Клієнтський код - демонструє передачу в метод лямбда-виразу
  // 1. Оголосити посилання на інтерфейс IAverage
  IAverage ref;

  // 2. Присвоїти посиланню на інтерфейс IAverage
  // лямбда-вираз, що обчислює середнє арифметичне 3-х величин
  ref = (a, b, c) -> (a+b+c)/3.0;

  // 3. Створити екземпляр класу SomeClass
  SomeClass obj = new SomeClass();

  // 4. Викликати метод PrintAverage() та передати йому
  obj.PrintAverage(ref);
}

 

3. Приклади розв’язування задач, в яких лямбда-вираз передається як аргумент методу
3.1. Максимальне значення в масиві чисел. Шаблонний функціональний інтерфейс. Передача лямбда-виразу в статичний метод

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

Розв’язок. У задачі оголошується узагальнений (шаблонний) функціональний інтерфейс IArray. В інтерфейсі визначено один метод, який отримує масив чисел типу T та повертає значення типу T.
Клас Lambda є основним класом в програмі, який містить функцію main(). У функції main() формуються:

  • лямбда-вираз, який обчислює максимальне значення в масиві A, що є вхідним параметром. Слід звернути увагу, що масив A вказується параметром лямбда-виразу без квадратних дужок [ ];
  • масив цілих чисел, який передається у статичний метод Solution().

З метою демонстрації, у класі Lambda реалізовано статичний шаблонний метод Solution(), який отримує два параметри:

  • масив узагальненого типу T, в якому потрібно знайти максимальний елемент;
  • лямбда-вираз, який передається в метод як посилання ref на функціональний інтерфейс IArray.

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

// Функціональний інтерфейс IArray
interface IArray<T extends Number> {
  // Метод пошуку максимуму в масиві чисел
  T Max(T[] array);
}

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

  // Статичний шаблонний метод, який отримує параметром лямбда-вираз.
  // Метод оперує типом T.
  // Тип T обмежений типом Number - це означає, що тип T може
  // бути тільки числовим типом (double, float, int, ...).
  // Параметри методу:
  // - масив чисел типу T;
  // - посилання на інтерфейс IArray<T>, в якому реалізовано лямбда-вираз.

  public static <T extends Number> void Solution(T[] array, IArray<T> ref) {
    // Вивести максимальне значення в масиві
    T max = ref.Max(array);
    System.out.println("max = " + max);
  }

  public static void main(String[] args) {
    // Сформувати лямбда-вираз, який обчислює максимальне значення
    // в масиві цілих чисел
    IArray<Integer> refInt = (A) -> {
      Integer max = A[0];
      for (int i=0; i<A.length; i++)
        if (max<A[i]) max = A[i];
      return max;
    };

    // Створити масив цілих чисел
    Integer[] A = { 7, 3, 2, 8, 8, 4 };

    // Передати лямбда-вираз в метод Solution()
    Lambda.Solution(A, refInt); // max = 8
  }
}

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

max = 8

 

3.2. Сортування масиву рядків методом вставки. Алгоритм сортування передається лямбда-виразом

У прикладі демонструється використання лямбда-виразу для сортування масиву рядків методом вставки.

// Функціональний інтерфейс, призначений для сортування
// масиву рядків
interface ISortStrings {
  void Sort(String[] array);
}

// Клас, що містить метод, в який передається лямбда-вираз
class SortMethods {
  // Метод, що сортує та виводить посортовані рядки.
  // У метод передається лямбда-вираз у вигляді посилання ref.
  void SortStrings(String[] AS, ISortStrings ref) {
    // Посортувати масив AS
    ref.Sort(AS);

    // Вивести посортований масив
    for (String s : AS)
      System.out.println(s);
  }
}

public class Lambda2 {

  public static void main(String[] args) {

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

    // 2. Визначити лямбда-вираз для алгоритму сортування вставками.
    // Сортування відбувається за зростанням: A...Z
    ref = (s) -> {
      String tmp;
      for (int i=0; i<s.length-1; i++)
        for (int j=i; j>=0; j--)
          if (s[j].compareTo(s[j+1])>0) {
            tmp = s[j];
            s[j] = s[j+1];
            s[j+1] = tmp;
          }
    };

    // 3. Сформувати тестувальний масив рядків
    String[] AS = {
      "afd", "jkl", "jprst", "mno", "axf", "aaa", "bcd", "ghi"
    };

    // 4. Викликати метод сортування SortMethods() та передати йому лямбда-вираз
    SortMethods obj = new SortMethods(); // створити екземпляр класу
    obj.SortStrings(AS, ref);
  }
}

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

aaa
afd
axf
bcd
ghi
jkl
jprst
mno

 

3.3. Обчислення кількості входжень елементу в масиві. Узагальнений функціональний інтерфейс

Реалізувати лямбда-вираз, який визначає кількість входжень елементу в масиві. Лямбда-вираз реалізує узагальнений функціональний інтерфейс.
Реалізувати метод класу, який отримує лямбда-вираз в якості параметру та виводить кількість входжень елементу в масиві. Продемонструвати роботу методу у функції main().

// Узагальнений функціональний інтерфейс.
interface IFindItem<T> {
  // Метод для визначення кількості входжень елементу в масиві
  int NOccurences(T item, T[] array);
}

// Клас, що містить метод, в який передається лямбда-вираз
class FindItems<T> {
  // Метод, який отримує:
  // - item - шуканий елемент типу T;
  // - array - масив елементів типу T;
  // - ref - посилання на лямбда-вираз.
  int Find(T item, T[] array, IFindItem<T> ref) {
    // Визначити кількість входжень item в array
    int count = ref.NOccurences(item, array);
    return count;
  }
}

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

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

    // 2. Сформувати лямбда-вираз для типу String
    ref = (item, array) -> {
      int n = 0; // к-сть входжень
      for (int i=0; i<array.length; i++)
        if (item==array[i])
          n++;
      return n;
    };

    // 3. Оголосити тестувальний масив
    String[] AS = { "abc", "def", "abc", "ghi", "fjk", "def", "def" };

    // 4. Викликати метод Find() та вивести кількість входжень "def" в AS
    FindItems<String> obj = new FindItems<String>();
    int count = obj.Find("def", AS, ref); // count = 3
    System.out.println("count = " + count);
  }
}

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

count = 3

 


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