Skip to content

Commit d841e03

Browse files
committed
Merge remote-tracking branch 'origin/NikitaUdinDev' into PavelLeonovTeamLead
2 parents afa1361 + 512dfa5 commit d841e03

10 files changed

Lines changed: 307 additions & 30 deletions

.idea/gradle.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

NikitaUdinReadMe

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
### Генерация и валидация данных (Никита Юдин)
2+
3+
Задачи:
4+
5+
- Создать классы и методы, которые заполняют коллекцию выбранного класса:
6+
- Генерация случайных объектов.
7+
- Чтение объектов из файла.
8+
- Ручной ввод объектов пользователем.
9+
- Сделать валидацию данных .
10+
- Работать с Builder, чтобы объекты создавались корректно.
11+
- Дополнительное задание 3: заполнение коллекций должно осуществляться посредством стримов. (Генерация данных тоже через стримы)
12+
- 3* Коллекции для заполнения должны быть кастомными.
13+
- (Использовать стрим для генерации данных, а результат перекладывать в кастомную коллекцию)

src/main/java/input/CollectionInterface.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package input;
22

3-
public interface CollectionInterface<T> {
3+
public interface CollectionInterface<T> extends Iterable<String>{
44
boolean add(T car); // important
55
boolean remove(T car); // important
66
boolean removeAt(int index);
Lines changed: 168 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,191 @@
11
package input;
22

3-
public class CustomCollection implements CollectionInterface{
3+
import java.util.*;
4+
import java.util.function.Consumer;
5+
import java.util.stream.Stream;
46

5-
@Override
6-
public boolean add(Object car) {
7-
return false;
7+
/**
8+
* CustomCollection - кастомная реализация динамического массива с автоматическим расширением.
9+
* Поддерживает хранение элементов любого типа, итерацию и базовые операции коллекции.
10+
*
11+
* <p>Коллекция использует внутренний массив для хранения элементов и автоматически
12+
* расширяется при заполнении. Коэффициент расширения: {@value #GROWTH_FACTOR}.
13+
*
14+
* <p>Реализует интерфейс {@link Iterable} для поддержки for-each циклов и стримов.
15+
*
16+
* @param <T> тип элементов, хранимых в коллекции
17+
*/
18+
public class CustomCollection<T> implements Iterable<T> {
19+
private static final float GROWTH_FACTOR = 1.5f;
20+
private static final int DEFAULT_CAPACITY = 10;
21+
22+
private Object[] elements;
23+
private int size;
24+
25+
public CustomCollection() {
26+
this.elements = new Object[DEFAULT_CAPACITY];
827
}
928

10-
@Override
11-
public boolean remove(Object car) {
12-
return false;
29+
public CustomCollection(int initialCapacity) {
30+
if (initialCapacity <= 0) {
31+
throw new IllegalArgumentException("Capacity cannot be less then 0");
32+
}
33+
this.elements = new Object[initialCapacity];
1334
}
1435

15-
@Override
16-
public boolean removeAt(int index) {
17-
return false;
36+
// TODO Конструктор из существующей коллекции, копирует все элементы с ёмкостью равной ёмкости коллекции
37+
38+
public boolean add(T element) {
39+
// Проверяем достаточно ли места для добавления
40+
if (size == elements.length) {
41+
// Если недостаточно, то увеличиваем размер списка
42+
increaseCapacity(size + 1);
43+
}
44+
// Добавляем новый элемент на последнюю позицию
45+
elements[size] = element;
46+
// Увеличиваем число элементов в массиве
47+
size++;
48+
return true;
49+
}
50+
51+
public void removeByIndex(int index) {
52+
if (index < 0 || index >= size) {
53+
throw new IndexOutOfBoundsException("Index cannot be less then 0 or more then " + size);
54+
}
55+
// Вычисляем количество элементов, которые нужно сместить влево после удаления
56+
int numToMove = size - index - 1;
57+
58+
if (numToMove > 0) {
59+
// Используем System.arraycopy для эффективного копирования части массива:
60+
// 1. elements - исходный массив
61+
// 2. index+1 - начальная позиция в исходном массиве (элемент после удаляемого)
62+
// 3. elements - целевой массив (тот же массив, копируем в себя)
63+
// 4. index - начальная позиция в целевом массиве (на место удаляемого элемента)
64+
// 5. numToMove - количество элементов для копирования
65+
System.arraycopy(elements, index + 1, elements, index, numToMove);
66+
}
67+
// Уменьшаем size на 1 после копирования в конце массива остался "лишний" элемент и удаляем его
68+
elements[--size] = null;
1869
}
1970

20-
@Override
2171
public void clear() {
72+
for (int i = 0; i < size; i++) {
73+
elements[i] = null;
74+
}
75+
size = 0;
76+
}
2277

78+
public T get(int index) {
79+
if (index < 0 || index >= size) {
80+
throw new IndexOutOfBoundsException("Index cannot be less then 0 or more then " + size);
81+
}
82+
return (T) elements[index];
2383
}
2484

25-
@Override
26-
public Object get(int index) {
27-
return null;
85+
public T set(int index, T element) {
86+
if (index < 0 || index >= size) {
87+
throw new IndexOutOfBoundsException("Index cannot be less then 0 or more then " + size);
88+
}
89+
90+
T old = (T) elements[index];
91+
elements[index] = element;
92+
return old;
2893
}
2994

30-
@Override
31-
public boolean add(Object car, int index) {
32-
return false;
95+
/**
96+
* Возвращает последовательный {@code Stream} с элементами этой коллекции в качестве источника.
97+
*
98+
* <p>Этот метод позволяет использовать функциональные операции над элементами коллекции.
99+
*
100+
* @return последовательный {@code Stream} элементов этой коллекции
101+
*/
102+
public Stream<T> stream() {
103+
return (Stream<T>) Arrays.stream(elements, 0, size);
104+
}
105+
106+
/**
107+
* Добавляет все элементы из указанной коллекции в конец этой коллекции.
108+
*
109+
* <p>Порядок элементов в целевой коллекции соответствует порядку,
110+
* в котором они возвращаются итератором указанной коллекции.
111+
*
112+
* @param collection коллекция, содержащая элементы для добавления
113+
* @return {@code true} если эта коллекция изменилась в результате вызова
114+
*/
115+
public boolean addAll(Collection<? extends T> collection) {
116+
// Проверяем, что переданная коллекция не null и не пустая
117+
if (collection == null || collection.isEmpty()) {
118+
// Возвращаем false, так как нечего добавлять
119+
return false;
120+
}
121+
122+
int requiredCapacity = size + collection.size();
123+
if (requiredCapacity > elements.length) {
124+
increaseCapacity(requiredCapacity);
125+
}
126+
for (T element : collection) {
127+
// Добавляем элемент в конец массива
128+
// elements[size] = element - добавляет элемент на текущую позицию
129+
// size++ - увеличивает счетчик элементов
130+
elements[size++] = element;
131+
}
132+
return true;
33133
}
34134

35-
@Override
36135
public int size() {
37-
return 0;
136+
return size;
137+
}
138+
139+
public boolean isEmpty() {
140+
return size == 0;
38141
}
39142

40143
@Override
41-
public boolean contains(Object car) {
42-
return false;
144+
public Iterator iterator() {
145+
return new CustomArrayIterator();
146+
}
147+
148+
// Внутренний клас для итератора
149+
class CustomArrayIterator implements Iterator<T> {
150+
private int cursor = 0; // текущая позиция
151+
private int lastRet = -1; // индекс последнего возвращенного элемента
152+
153+
public CustomArrayIterator() {
154+
}
155+
156+
public boolean hasNext() {
157+
return cursor < size;
158+
}
159+
160+
public T next() {
161+
if (!hasNext()) {
162+
throw new NoSuchElementException("Элемент отсутствует");
163+
}
164+
lastRet = cursor;
165+
T element = (T) elements[cursor];
166+
cursor++;
167+
168+
return element;
169+
}
170+
171+
public void remove() {
172+
if (lastRet == -1) {
173+
throw new IllegalStateException();
174+
}
175+
removeByIndex(lastRet);
176+
cursor = lastRet;
177+
lastRet = -1;
178+
}
179+
}
180+
181+
/**
182+
* Увеличивает емкость внутреннего массива, чтобы обеспечить минимальную указанную емкость.
183+
* @param minCapacity минимальная требуемая емкость
184+
*/
185+
private void increaseCapacity(int minCapacity) {
186+
int newCapacity = (int) Math.max(elements.length * GROWTH_FACTOR + 1, minCapacity);
187+
Object[] newElements = new Object[newCapacity];
188+
System.arraycopy(elements, 0, newElements, 0, size);
189+
elements = newElements;
43190
}
44191
}

src/main/java/input/FileReader.java

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package input.Strategy;
2+
3+
import dto.Client;
4+
import input.CustomCollection;
5+
6+
import java.io.IOException;
7+
8+
/**
9+
* Интерфейс стратегии для ввода данных клиентов.
10+
* Реализует паттерн Стратегия для различных способов получения объектов {@link Client}.
11+
* Каждая реализация представляет конкретный способ получения данных
12+
* Реализации должны гарантировать, что возвращаемые объекты {@link Client}
13+
* являются валидными
14+
*/
15+
public interface ClientInputStrategy {
16+
CustomCollection<Client> getData() throws IOException;
17+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package input.Strategy;
2+
3+
import dto.Client;
4+
import input.CustomCollection;
5+
6+
import java.io.File;
7+
import java.io.IOException;
8+
import java.nio.charset.StandardCharsets;
9+
import java.nio.file.Files;
10+
import java.nio.file.Path;
11+
import java.nio.file.Paths;
12+
import java.util.Optional;
13+
import java.util.stream.Stream;
14+
15+
/**
16+
* Стратегия для чтения данных о клиентах из файла.
17+
* Реализует интерфейс ClientInputStrategy для получения коллекции клиентов.
18+
*/
19+
public class FileReader implements ClientInputStrategy {
20+
private final String filePath;
21+
22+
public FileReader(String filePath) {
23+
this.filePath = filePath;
24+
}
25+
26+
/**
27+
* Читает данные о клиентах из файла и возвращает их в виде коллекции.
28+
* Файл должен содержать строки в формате: Имя|Телефон|ID
29+
* Телефон должен соответствовать формату: +7XXXXXXXXXX (11 цифр после +7)
30+
*
31+
* @return коллекция клиентов, прочитанных из файла
32+
* @throws RuntimeException если файл не найден или произошла ошибка ввода-вывода
33+
*/
34+
@Override
35+
public CustomCollection<Client> getData() {
36+
CustomCollection<Client> clients = new CustomCollection<>();
37+
Path path = Paths.get(filePath);
38+
39+
if (!Files.exists(path)) {
40+
throw new RuntimeException("File not found: " + filePath);
41+
}
42+
43+
try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) {
44+
lines
45+
.filter(line -> !line.trim().isEmpty())
46+
.map(this::parseToClient)
47+
.filter(Optional::isPresent)
48+
.map(Optional::get)
49+
.map(Client.ClientBuilder::build)
50+
.forEach(clients::add);
51+
52+
} catch (IOException e) {
53+
throw new RuntimeException(e);
54+
}
55+
return clients;
56+
}
57+
58+
/**
59+
* Парсит строку из файла в объект ClientBuilder.
60+
* Строка должна быть в формате: Имя|Телефон|ID
61+
*
62+
* @param line строка из файла для парсинга
63+
* @return Optional содержащий ClientBuilder если строка валидна,
64+
* или пустой Optional если строка содержит ошибки формата
65+
*/
66+
public Optional<Client.ClientBuilder> parseToClient(String line) {
67+
try {
68+
String[] parts = line.split("\\|");
69+
if (parts.length != 3) {
70+
throw new IllegalArgumentException("Invalid data format");
71+
}
72+
String name = parts[0].trim();
73+
String phoneNumber = parts[1].trim();
74+
int idNumber;
75+
76+
try {
77+
idNumber = Integer.parseInt(parts[2].trim());
78+
} catch (NumberFormatException e) {
79+
System.out.println("[WARN] Missing line (ID is not a number): " + line);
80+
return Optional.empty();
81+
}
82+
83+
if (name.isEmpty()) {
84+
System.out.println("[WARN] Missing line (name is empty): " + line);
85+
return Optional.empty();
86+
}
87+
88+
if (!phoneNumber.matches("^\\+7\\d{10}$")) {
89+
System.out.println("[WARN] Missing line (invalid phone format): " + line);
90+
return Optional.empty();
91+
}
92+
93+
Client.ClientBuilder builder = new Client.ClientBuilder()
94+
.name(name)
95+
.phoneNumber(phoneNumber)
96+
.idNumber(idNumber);
97+
return Optional.of(builder);
98+
99+
} catch (Exception e) {
100+
System.out.println("[ERROR] Error processing line: " + line);
101+
return Optional.empty();
102+
}
103+
}
104+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package input;
1+
package input.Strategy;
22

33
public class ManualInputReader {
44
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package input;
1+
package input.Strategy;
22

33
public class RandomDataGenerator {
44
}

0 commit comments

Comments
 (0)