Java. Приклади розв’язування задач на потоки даних




Stream API. Приклади розв’язування задач на потоки даних, якими є об’єкти розроблених класів


Зміст


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

1. Клас Car (Автомобіль). Приклад
1.1. Умова задачі

Створити клас “Автомобіль”. У класі повинна зберігатись наступна інформація:

  • назва автомобіля;
  • рік випуску;
  • вартість;
  • колір;
  • об’єм двигуна.

Потрібно створити набір автомобілів та виконати наступні задачі:

  • відобразити всі автомобілі;
  • відобразити автомобілі заданого кольору;
  • відобразити автомобілі дорожче за заданої ціни;
  • відобразити автомобілі, чий рік випуску знаходиться в заданому діапазоні;
  • посортувати автомобілі в порядку спадання вартості.

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

 

1.2. Розв’язок

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

import java.util.ArrayList;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;

class Car {
  private String name; // назва автомобіля
  private int year; // рік випуску
  private String color; // колір
  private double volume; // об'єм двигуна
  private double price; // вартість

  // Конструктор
  public Car(String _name, String _color, int _year,
  double _volume, double _price) {
    name = _name; year = _year; color = _color;
    volume = _volume; price = _price;
  }

  // Методи get()
  String getName() { return name; }
  int getYear() { return year; }
  String getColor() { return color; }
  double getVolume() { return volume; }
  double getPrice() { return price; }
}

public class StreamAPI {

  // 1. Показати всі автомобілі
  public static void PrintAllCars(ArrayList<Car> AL) {
    // 1. Отримати потік Stream<Car>
    Stream<Car> stream = AL.stream();

    // 2. Реалізувати стандартний функц. інтерфейс Consumer<T>
    Consumer<Car> action = (n) -> {
      System.out.println(n.getName() + ", " + n.getColor() +
                         ", " + n.getPrice() + ", " + n.getYear() +
                         ", " + n.getVolume());
    };

    // 3. Вивести всі автомобілі
    stream.forEach(action);

    // 4. Те саме
    /*
      AL.stream().forEach((n) -> System.out.println(n.getName() + ", " +
        n.getColor() + ", " +
        n.getPrice() + ", " +
        n.getYear() + ", " +
        n.getVolume())); 
    */
  }

  // 2. Показати всі автомобілі заданого кольору
  public static void PrintAllCarsColor(ArrayList<Car> AL, String color) {
    // 1. Отримати потік
    Stream<Car> stream = AL.stream();

    // 2. Посилання на Predicate<T>
    Predicate<Car> predicate = (car) -> {
      if (car.getColor()==color)
        return true;
      return false;
    };

    // 3. Отримати новий потік згідно з предикатом
    Stream<Car> filterStream = stream.filter(predicate);

    // 4. Вивести новий відфільтрований потік
    // 4.1. Посилання на станд. інтерфейс Consumer<T>
    Consumer<Car> action = (n) -> {
      System.out.println(n.getName() + ", " + n.getColor() +
                         ", " + n.getPrice() + ", " + n.getYear() +
                         ", " + n.getVolume());
    };

      // 4.2. Вивід кожного елементу методом forEach()
      filterStream.forEach(action);
  }

  // 3. Показати всі автомобілі дорожче заданої ціни
  public static void PrintAllCarsPrice(ArrayList<Car> AL, double price) {
    // 1. Отримати потік
    Stream<Car> stream = AL.stream();

    // 2. Посилання на Predicate<T>
    Predicate<Car> predicate = (car) -> {
      if (car.getPrice()>price)
        return true;
      return false;
    };

    // 3. Отримати новий потік згідно з предикатом
    Stream<Car> filterStream = stream.filter(predicate);

    // 4. Вивести новий відфільтрований потік
    // 4.1. Посилання на станд. інтерфейс Consumer<T>
    Consumer<Car> action = (n) -> {
      System.out.println(n.getName() + 
                         ", " + n.getColor() +
                         ", " + n.getPrice() + 
                         ", " + n.getYear() +
                         ", " + n.getVolume());
    };

    // 4.2. Вивід кожного елементу методом forEach()
    filterStream.forEach(action);
  }

  // 4. Відобразити автомобілі, чий рік випуску знаходиться в заданому діапазоні
  public static void PrintAllCarsYear(ArrayList<Car> AL, int year1, int year2) {
    // 1. Оголосити посилання на Predicate<T> та присвоїти цьому посиланню лямбда-вираз
    Predicate<Car> predicate = (car) ->
      (car.getYear()>=year1)&&(car.getYear()<=year2);

    // 2. Отримати результуючий потік згідно з предикатом
    Stream<Car> stream = AL.stream().filter(predicate);

    // 3. Вивести результуючий потік
    // 3.1. Оголосити посилання на стандартний функціональний інтерфейс Consumer<T>
    Consumer<Car> action;

    // 3.2. Присвоїти посиланню action лямбда-вираз, що виводить інформацію про автомобіль
    action = (car) -> {
      System.out.println(car.getName() + ", " + car.getColor() +
                         ", " + car.getYear() + ", " + car.getPrice() + ", " + car.getVolume());
    };

    // 3.3. Відобразити потік stream
    stream.forEach(action);
  }

  // 5. Відобразити автомобілі відсортовані за ціною
  public static void PrintCarsSortedByPrice(ArrayList<Car> AL) {
    // 1. Оголосити посилання на функціональний інтерфейс Comparator<T>
    Comparator<Car> comparator;

    // 2. Присвоїти посиланню лямбда-вираз, що порівнює два значення
    comparator = (car1, car2) -> {
      // Лямбда-вираз повинен повернути результат типу int: <0, ==0, >0
      // Сортування за спаданням: car2 - car1.
      return (int)(car2.getPrice()-car1.getPrice()); // Порівнюємо вартості
    };

    // 4. Отримати відсортований потік. Для сортування використати метод sorted().
    Stream<Car> sortedStream = AL.stream().sorted(comparator);

    // 5. Вивести потік
    // 5.1. Оголосити посилання на інтерфейс Consumer<T> та присвоїти йому лямбда-вираз,
    // який виводить дані про автомобіль
    Consumer<Car> action = (car) -> {
      System.out.println(
                         car.getName() + ", " +
                         car.getColor() + ", " +
                         car.getYear() + ", " +
                         car.getPrice() + ", " +
                         car.getVolume()
                        );
    };

    // 5.2. Відобразити потік sortedStream
    sortedStream.forEach(action);
  }

  public static void main(String[] args) {
    // 1. Сформувати тестувальний масив
    ArrayList<Car> AL = new ArrayList<Car>();
    AL.add(new Car("BMW", "Black", 2018, 2.2, 18800.0));
    AL.add(new Car("Audi", "Silver", 2017, 2.3, 20500.0));
    AL.add(new Car("Renault", "Red", 2018, 1.5, 11800.0));
    AL.add(new Car("Audi", "Silver", 2016, 2.5, 22800.0));
    AL.add(new Car("Renault", "Silver", 2017, 1.3, 10250.0));
    AL.add(new Car("VW", "Red", 2017, 2.3, 15800.0));
    AL.add(new Car("Mercedes", "White", 2018, 2.5, 25800.0));

    // 2. Вивести всі автомобілі
    StreamAPI.PrintAllCars(AL);

    // 3. Вивести автомобілі заданого кольору
    System.out.println("---------------------------------");
    StreamAPI.PrintAllCarsColor(AL, "Silver");

    // 4. Відобразити автомобілі дорожче заданої ціни
    System.out.println("---------------------------------");
    StreamAPI.PrintAllCarsPrice(AL, 20000.0);

    // 5. Відобразити автомобілі, чий рік випуску знаходиться в заданому діапазоні
    System.out.println("---------------------------------");
    StreamAPI.PrintAllCarsYear(AL, 2018, 2018);

    // 6. Посортувати автомобілі в порядку спадання вартості
    System.out.println("---------------------------------");
    System.out.println("Sorting by descending sort");
    StreamAPI.PrintCarsSortedByPrice(AL);
  }
}

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

BMW, Black, 18800.0, 2018, 2.2
Audi, Silver, 20500.0, 2017, 2.3
Renault, Red, 11800.0, 2018, 1.5
Audi, Silver, 22800.0, 2016, 2.5
Renault, Silver, 10250.0, 2017, 1.3
VW, Red, 15800.0, 2017, 2.3
Mercedes, White, 25800.0, 2018, 2.5
---------------------------------
Audi, Silver, 20500.0, 2017, 2.3
Audi, Silver, 22800.0, 2016, 2.5
Renault, Silver, 10250.0, 2017, 1.3
---------------------------------
Audi, Silver, 20500.0, 2017, 2.3
Audi, Silver, 22800.0, 2016, 2.5
Mercedes, White, 25800.0, 2018, 2.5
---------------------------------
BMW, Black, 2018, 18800.0, 2.2
Renault, Red, 2018, 11800.0, 1.5
Mercedes, White, 2018, 25800.0, 2.5
---------------------------------
Sorting by descending sort
Mercedes, White, 2018, 25800.0, 2.5
Audi, Silver, 2016, 22800.0, 2.5
Audi, Silver, 2017, 20500.0, 2.3
BMW, Black, 2018, 18800.0, 2.2
VW, Red, 2017, 15800.0, 2.3
Renault, Red, 2018, 11800.0, 1.5
Renault, Silver, 2017, 10250.0, 1.3

 

2. Робота з потоками об’єктів узагальнених (шаблонних) класів. Клас Point<T>. Приклад
2.1. Умова задачі

Розробити узагальнений (шаблонний) клас Point, що реалізує точку на координатній площині (x; y).

На основі розробленого класу Point створити набір об’єктів. Для створеного набору об’єктів реалізувати наступні задачі:

  • отримати точку (об’єкт) з найбільшим значенням координати x;
  • створити новий потік чисел типу double. Кожне число є відстанню від точки до початку координат. Отриманий потік вивести на екран;
  • створити новий потік об’єктів. У потоці повинні бути точки (об’єкти), відстань від яких до початку координат більше 5;
  • посортувати об’єкти в спадному порядку за критерієм відстані від точки до початку координат.

Розв’язок задач помістити в клас Solution, який буде містити 4 узагальнені методи, які будуть розв’язувати задачі згідно з умовою.

При розв’язку задачі використовувати засоби Stream API.

 

2.2. Розв’язок

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

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

// Узагальнений шаблонний клас, який реалізує точку на координатній площині
class Point<T extends Number> {
  // Внутрішні поля класу
  private T x;
  private T y;

  // Конструктор
  public Point(T x, T y) {
    this.x = x; this.y = y;
  }

  // Методи доступу до полів класу
  public T getX() { return x; }
  public T getY() { return y; }
}

// Клас, що є рішенням
class Solution {

  // 1. Отримати точку (об'єкт) з найбільшим значенням координати x
  public <T extends Number> Point<T> getMaxCoordX(ArrayList<Point<T>> AL) {
    // 1. Отримати потік даних з масиву
    Stream<Point<T>> stream = AL.stream();

    // Реалізувати компаратор - метод порівняння, який повертає <0, ==0, >0
    // в залежності від того, чи координата x точки 2 більша за координату x точки 1
    Comparator<Point<T>> comparator;

    comparator = (point1, point2) -> {
      // отримати координати x точок point1, point2
      T x2 = point2.getX();
      T x1 = point1.getX();

      if (x2.doubleValue()>x1.doubleValue())
        return -1;
      if (x2.doubleValue()<x1.doubleValue())
        return 1;
      return 0;
    };

    // 3. Обчислити точку Point<T> з максимальним значенням X
    Optional<Point<T>> maxPt = stream.max(comparator);

    // 4. Повернути знайдену точку назовні
    return maxPt.get();
  }

  // Метод, який формує новий потік типу double. Елементи потоку є
  // відстанями від точки до початку координат.
  public <T extends Number> Stream<Double> getStreamLengthOrigin(ArrayList<Point<T>> AL) {

    // 1. Отримати потік точок з масиву AL
    Stream<Point<T>> stream = AL.stream();

    // 2. Сформувати функцію отримання значення типу double з типу Point<T>
    // 2.1. Оголосити посилання на стандартний функціональний інтерфейс Function<T, R>
    Function<Point<T>, Double> function;

    // 2.2. Сформувати лямбда-вираз, який повертає відстань від точки point до
    // початку координат
    function = (point) -> {
      double x = point.getX().doubleValue();
      double y = point.getY().doubleValue();
      return (double)(Math.sqrt(x*x+y*y));
    };

    // 3. Застосувати функцію function з допомогою методу map()
    Stream<Double> streamOrigin = stream.map(function);

    // 4. Повернути результат
    return streamOrigin;
  }

  // Створити новий потік об’єктів. У потоці повинні бути точки (об’єкти),
  // відстань від яких до початку координат більше 5.
  public <T extends Number> Stream<Point<T>> getPointsLength5(ArrayList<Point<T>> AL) {

    // 1. Отримати потік точок з масиву AL
    Stream<Point<T>> stream = AL.stream();

    // 2. Сформувати предикат (умову), який буде використовуватись при формуванні
    // нового потоку
    // 2.1. Оголосити посилання на стандартний функціональний інтерфейс Predicate<T>
    Predicate<Point<T>> predicate;

    // 2.2. Присвоїти посиланню лямбда-вираз
    predicate = (point) -> {
      // обчислити відстань length від точки до початку координат
      double x = point.getX().doubleValue();
      double y = point.getY().doubleValue();
      double length = Math.sqrt(x*x+y*y);

      // перевірити значення length
      if (length>5.0)
        return true;
      return false;
    };

    // 3. Сформувати новий потік з потоку stream
    Stream<Point<T>> streamLength5 = stream.filter(predicate);

    // 4. Повернути результат
    return streamLength5;
  };

  // Посортувати об’єкти в спадному порядку за критерієм відстані від точки
  // до початку координат.
  public <T extends Number> Stream<Point<T>> getSortedPoints(ArrayList<Point<T>> AL) {

    // 1. Отримати потік точок з масиву AL
    Stream<Point<T>> stream = AL.stream();

    // 2. Сформувати компаратор - метод, який порівнює відстані від двох точок до початку координат.
    // Метод повертає значення типу int відповідно <0, ==0, >0.
    Comparator<Point<T>> comparator = (point1, point2) -> {
      // 2.1. Визначити відстані від точок point1, point2 до початку координат
      double x1 = point1.getX().doubleValue();
      double y1 = point1.getY().doubleValue();
      double x2 = point2.getX().doubleValue();
      double y2 = point2.getY().doubleValue();
      double length1 = Math.sqrt(x1*x1+y1*y1);
      double length2 = Math.sqrt(x2*x2+y2*y2);

      // 2.2. Повернути результат
      return (int)(length2-length1);
    };

    // 3. Викликати метод сортування
    Stream<Point<T>> sortedStream = stream.sorted(comparator);

    // 4. Повернути посортований потік stream
    return sortedStream;
  }
}

public class StreamAPI {

  public static void main(String[] args) {
    // Етапи розв'язку задачі
    // 1. Створити набір об'єктів типу Point(),
    // значення координат сформувати випадковим чином
    ArrayList<Point<Integer>> AL = new ArrayList<Point<Integer>>();
    Point<Integer> pt;
    int x, y;

    // створюється 10 точок
    for (int i=0; i<10; i++) {
      x = (int)(Math.random()*10);
      y = (int)(Math.random()*10);
      pt = new Point<Integer>(x, y);
      AL.add(pt);
    }

    // Вивести масив точок на екран для контролю
    System.out.print("AL = [");
    for (Point<Integer> t : AL) {
      System.out.print("(" + t.getX() + "," + t.getY() + ") ");
    }
    System.out.println("]");

    // 2. Реалізувати рішення. Для цього потрібно створити екземпляр класу
    // Solution і по черзі викликати методи цього екземпляру
    Solution solution = new Solution();

    // 2.1. Задача 1. Рішення
    Point<Integer> maxPt = solution.getMaxCoordX(AL);

    System.out.println("Solution 1. Max Point.");
    System.out.println("maxPt = (" + maxPt.getX().intValue() +
", " + maxPt.getY().intValue() + ")");

    // 2.2. Задача 2. Рішення
    Stream<Double> streamOrigin = solution.getStreamLengthOrigin(AL);

    // Вивести потік streamOrigin на екран
    System.out.println("Solution 2. Array of lengths.");

    Consumer<Double> action = (n) -> {
      System.out.println(n + " ");
    };
    streamOrigin.forEach(action);

    // 2.3. Задача 3. Рішення
    Stream<Point<Integer>> streamPoints = solution.getPointsLength5(AL);

    // Вивести результат задачі 3
    System.out.println("Solution 3. Points with length>5.0");
    Consumer<Point<Integer>> action2 = (point) -> {
      System.out.println("("+point.getX()+"; " + point.getY() + ")");
    };
    streamPoints.forEach(action2);

    // 2.4. Задача 4. Рішення
    Stream<Point<Integer>> streamSorted = solution.getSortedPoints(AL);

    System.out.println("Solution 4. Sorting points.");

    // Вивести результат задачі 4
    streamSorted.forEach(action2);
  }
}

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

AL = [(9,2) (7,4) (3,3) (8,2) (4,7) (8,6) (0,1) (0,2) (4,6) (4,6) ]
Solution 1. Max Point.
maxPt = (9, 2)
Solution 2. Array of lengths.
9.219544457292887
8.06225774829855
4.242640687119285
8.246211251235321
8.06225774829855
10.0
1.0
2.0
7.211102550927978
7.211102550927978
Solution 3. Points with length>5.0
(9; 2)
(7; 4)
(8; 2)
(4; 7)
(8; 6)
(4; 6)
(4; 6)
Solution 4. Sorting points.
(9; 2)
(8; 6)
(7; 4)
(8; 2)
(4; 7)
(4; 6)
(4; 6)
(3; 3)
(0; 2)
(0; 1)

 


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