JavaRush /Java блог /Random /Кофе-брейк #255. Создание глубокой и поверхностной копии ...

Кофе-брейк #255. Создание глубокой и поверхностной копии объекта. Java Stream API: когда использовать map() и FlatMap()

Статья из группы Random

Создание глубокой и поверхностной копии объекта в Java

Источник: DZone В этом руководстве рассмотрены две концепции копирования объектов в Java: глубокое копирование и поверхностное копирование. Вы узнаете, как они работают на нескольких простых примерах. Кофе-брейк #255. Создание глубокой и поверхностной копии объекта. Java Stream API: когда использовать map() и FlatMap() - 1При работе с объектами в Java бывают случаи, когда вам необходимо создать копию объекта. Однако не все копии одинаковы. Существует два основных способа копирования объектов: глубокое копирование (Deep Copy) и поверхностное копирование (Shallow Copy).

Глубокое копирование: что это такое?

Представьте, что у вас есть коллекция фигур, каждая из которых имеет свой перечень свойств. Глубокая копия объекта означает создание совершенно новой копии исходного объекта вместе со всеми вложенными объектами, которые он содержит. Иными словами, это похоже на точную копию каждой формы, включая все детали.

Поверхностное копирование: в чем разница?

С другой стороны, поверхностное копирование создает копию объекта, не зная о структуре класса, который он копирует. То есть, объект копируется без содержащихся в нем вложенных объектов. По умолчанию в Java применяется поверхностное копирование. Для этого используется метод clone().

Давайте применим копирование на практике: пример фигур

Представьте, что у вас есть класс с именем Circle, в котором есть вложенный объект класса Point, представляющий его центр. Сейчас мы увидим, как глубокое и поверхностное копирование работают с этими объектами.

public class Circle {
   public Point center;
    public int radius;

    public Circle(Point center, int radius) {
        this.center = center;
        this.radius = radius;
    }
}

public class Point {
        public int x, y;

        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

Создание поверхностной копии

Для поверхностного копирования мы просто копируем ссылки на вложенные объекты:

public Circle shallowCopyCircle(Circle original) {
        return new Circle(original.center, original.radius);
 }

Создание глубокой копии

Для глубокой копии Circle нам нужно создать новые экземпляры объектов Point и Circle.

 public Circle deepCopyCircle(Circle original) {
        Point copiedPoint = new Point(original.center.x, original.center.y);
        return new Circle(copiedPoint, original.radius);
  }

Создание простого класса CopyUtil

Вот класс утилиты с кодом копирования объектов:

public class CopyUtil {
    public Circle deepCopyCircle(Circle original) {
        Point copiedPoint = new Point(original.center.x, original.center.y);
        return new Circle(copiedPoint, original.radius);
    }
    public Circle shallowCopyCircle(Circle original) {
        return new Circle(original.center, original.radius);
    }
}

Модульные тесты

Давайте напишем несколько простых тестов для проверки наших методов глубокого и поверхностного копирования.

public class ShallowAndDeepCopyUnitTest {

    @Test
    public void givenCircle_whenDeepCopy_thenDifferentObjects() {
        CopyUtil util=new CopyUtil();
        Point center = new Point(3, 5);
        Circle original;
        original = new Circle(center, 10);
        Circle copied = util.deepCopyCircle(original);
        assertNotSame(original, copied);
        Assert.assertNotSame(original.center, copied.center);
    }

    @Test
    public void givenCircle_whenShallowCopy_thenSameCenter() {
        CopyUtil util=new CopyUtil();
        Point center = new Point(7, 9);
        Circle original = new Circle(center, 15);
        Circle copied = util.shallowCopyCircle(original);
        assertNotSame(original, copied);
        assertSame(original.center, copied.center);
    }
}

Заключение

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

Java Stream API: когда использовать map() и FlatMap()

Источник: Medium Прочитав эту публикацию, вы сможете понять, когда и в каких сценариях стоит применять map, а когда flatMap. map и flatMap — это две операции в Java Stream API, которые используются для преобразования элементов в потоке. Однако они служат разным целям и используются в разных случаях.

map:

Операция map используется для применения преобразования к каждому элементу в потоке, что приводит к однозначному сопоставлению (one-to-one mapping). Она создает новый поток, в котором каждый входной элемент преобразуется в соответствующий выходной элемент.

flatMap:

Операция flatMap используется для преобразования каждого элемента потока в поток из нескольких элементов. Все полученные потоки затем объединяются в один поток. Вот аналогия из реальной жизни, которая поможет понять разницу между map и flatMap. Представьте, что у вас есть список людей, и у каждого человека есть список своих любимых цветов. Вы хотите извлечь из списка людей все их любимые цвета. Используя Stream API, вы с помощью map можете извлечь список любимых цветов каждого человека, а с помощью flatMap можете извлечь все цвета из всех списков без привязки к конкретному человеку. Давайте посмотрим на это с помощью фрагментов кода. Использование map:

import java.util.*;
import java.util.stream.Collectors;

class Person {
    private String name;
    private List<String> favoriteColors;

    public Person(String name, List<String> favoriteColors) {
        this.name = name;
        this.favoriteColors = favoriteColors;
    }

    public List<String> getFavoriteColors() {
        return favoriteColors;
    }
}

public class MapVsFlatMapExample {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("Alice", Arrays.asList("Red", "Blue")),
            new Person("Bob", Arrays.asList("Green", "Yellow")),
            new Person("Charlie", Arrays.asList("Purple"))
        );

        List<List<String>> allFavoriteColors = people.stream()
            .map(Person::getFavoriteColors)
            .collect(Collectors.toList());

        System.out.println(allFavoriteColors);
        //[[Red, Blue], [Green, Yellow], [Purple]]
    }
}
В этом примере операция map извлекает список любимых цветов так, что в результате получается перечень из списков любимых цветов каждого опрошенного человека. А теперь код с использованием flatMap:

import java.util.*;
import java.util.stream.Collectors;

class Person {
    private String name;
    private List<String> favoriteColors;

    public Person(String name, List<String> favoriteColors) {
        this.name = name;
        this.favoriteColors = favoriteColors;
    }

    public List<String> getFavoriteColors() {
        return favoriteColors;
    }
}

public class MapVsFlatMapExample {
    public static void main(String[] args) {
        List<Person> people = Arrays.asList(
            new Person("Alice", Arrays.asList("Red", "Blue")),
            new Person("Bob", Arrays.asList("Green", "Yellow")),
            new Person("Charlie", Arrays.asList("Purple"))
        );

        List<String> allFavoriteColors = people.stream()
            .flatMap(person -> person.getFavoriteColors().stream())
            .collect(Collectors.toList());

        System.out.println(allFavoriteColors);
        //[Red, Blue, Green, Yellow, Purple]
    }
}
В этом примере операция flatMap извлекает каждый цвет из списка любимых цветов каждого человека, в результате чего получается не перечень из нескольких списков, а один большой список всех любимых цветов без привязки к каждому человеку.

Когда нужно использовать map:

  1. Если вы хотите преобразовать каждый элемент потока в отдельный объект.
  2. Если между входными и выходными элементами существует однозначное сопоставление “один к одному”.

Когда нужно использовать flatMap:

  1. Если вы хотите преобразовать каждый элемент в несколько элементов или другой поток.
  2. Если вы хотите объединить вложенную структуру (например, списки внутри списков) в один поток.
  3. Если между входными и выходными элементами существует связь “один ко многим” или “многие ко многим”.
Таким образом, map и flatMap используются для различных сценариев трансформации. Операция map преобразует один элемент в другой, а flatMap преобразует один элемент в несколько элементов или другой поток, а затем выравнивает результат.
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ