diff --git a/.gitignore b/.gitignore
index 9cdb1dbb9..47b8f5fd2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,12 @@
.idea
**/*.iml
**/target
+.DS_Store
+0-0-intro/
+1-0-java-basics/1-5-0-hello-annotations/
+2-0-data-structures-and-algorithms/
+3-0-java-core/3-6-1-file-reader/
+3-0-java-core/3-6-2-file-stats/
+3-0-java-core/3-6-3-crazy-regex/
+4-0-object-oriented-programming/
+6-0-test-driven-development/
\ No newline at end of file
diff --git a/0-0-intro/README.md b/0-0-intro/README.md
deleted file mode 100644
index 488324028..000000000
--- a/0-0-intro/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# Introduction
-
-Learn how to use this course to build strong skill needed for enterprise Java development
-
-## The only way to learn effectively is to **learn by doing!** 💪
-
-Therefore, this whole repository consists of **various exercises grouped by topics**. By doing exercises you will **build strong skills and neven get stuck.** Introduction itself is an exercise, so you can understand the idea on the simplest example.
-
-Each exercise has three major parts:
-* **a task** – some logic that you implement in order build a certain skill 👨🏻💻
-* **a test** – a corresponding test that verifies if you implement the task correctly ▶️
-* **a completed solution** - a branch `completed` that holds implemented task ✅
-
-Go ahead and do this exercise by implementing a method in `Introduction` class. 💪
-_(we know it's silly, but we wanted to give you a simple example 😀)_
-
-## You should have installed on your local machine ❗️
-* [JDK 11+](https://jdk.java.net/15/)
-* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
-
-## How to start ❓
-* [clone](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository) this [repository](https://github.com/bobocode-projects/java-fundamentals-exercises) to your computer
-* **open** the project via IDE
-
-## Have questions? 🧐
-* take a look at **README** of the exercise
-* switch to branch `completed` and **see the correct implementation** of the exercise
-* [join the discussion](https://github.com/bobocode-projects/java-fundamentals-exercises/discussions) on the GitHub
-* contact us via info@bobocode.com
diff --git a/0-0-intro/pom.xml b/0-0-intro/pom.xml
deleted file mode 100644
index b62fec52e..000000000
--- a/0-0-intro/pom.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
- 4.0.0
-
-
- com.bobocode
- java-fundamentals-exercises
- 1.0-SNAPSHOT
-
- 0-0-intro
-
-
-
- com.bobocode
- java-fundamentals-util
- 1.0-SNAPSHOT
-
-
-
-
\ No newline at end of file
diff --git a/0-0-intro/src/main/java/com/bobocode/intro/ExerciseIntroduction.java b/0-0-intro/src/main/java/com/bobocode/intro/ExerciseIntroduction.java
deleted file mode 100644
index 35d925636..000000000
--- a/0-0-intro/src/main/java/com/bobocode/intro/ExerciseIntroduction.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.bobocode.intro;
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-/**
- * Welcome! This is an introduction exercise that will show you a simple example of Bobocode exercises.
- *
- * JavaDoc is a way of communication with other devs. We use Java Docs in every exercise to define the task.
- * So PLEASE MAKE SURE you read the Java Docs carefully.
- *
- * Every exercise is covered with tests, see {@link ExerciseIntroductionTest}.
- *
- * In this repo you'll find dozens of exercises covering various fundamental topics.
- * They all have the same structure helping you to focus on practice and build strong skills!
- *
- * @author Taras Boychuk
- */
-public class ExerciseIntroduction {
- /**
- * This method returns a very important message. If understood well, it can save you years of inefficient learning,
- * and unlock your potential!
- *
- * @return "The key to efficient learning is practice!"
- */
- public String getWelcomeMessage() {
- // todo: implement a method and return a message according to javadoc
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * Method encodeMessage accepts one {@link String} parameter and returns encoded {@link String}.
- *
- * PLEASE NOTE THAT YOU WILL GET STUCK ON THIS METHOD INTENTIONALLY! ;)
- *
- * Every exercise has a completed solution that is stored in the branch "completed". So in case you got stuck
- * and don't know what to do, go check out completed solution.
- *
- * @param message input message
- * @return encoded message
- */
- public String encodeMessage(String message) {
- // todo: switch to branch "completed" in order to see how it should be implemented
- throw new ExerciseNotCompletedException();
- }
-}
diff --git a/0-0-intro/src/test/java/com/bobocode/intro/ExerciseIntroductionTest.java b/0-0-intro/src/test/java/com/bobocode/intro/ExerciseIntroductionTest.java
deleted file mode 100644
index 093909fe9..000000000
--- a/0-0-intro/src/test/java/com/bobocode/intro/ExerciseIntroductionTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.bobocode.intro;
-
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.*;
-
-import java.util.Arrays;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * This is a {@link ExerciseIntroductionTest} that is meant to verify if you properly implement {@link ExerciseIntroduction}.
- * It is a simple example that shows how each exercise is organized: todo section + tests.
- *
- * A typical Java test uses JUnit framework to run the test, and may also use some other frameworks for assertions.
- * In our exercises we use JUnit 5 + AssertJ
- *
- * PLEASE NOTE:
- * - annotation @{@link Order} is used to help you to understand which method should be implemented first.
- * - annotation @{@link DisplayName} is used to provide you more detailed instructions.
- *
- * @author Taras Boychuk
- */
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class ExerciseIntroductionTest {
- private ExerciseIntroduction exerciseIntroduction = new ExerciseIntroduction();
- private String EXPECTED_MESSAGE = "The key to efficient learning is practice!";
-
- @Test
- @Order(1)
- @DisplayName("getWelcomeMessage method returns correct phrase")
- void getWelcomeMessage() {
- String message = exerciseIntroduction.getWelcomeMessage();
-
- assertThat(message).isEqualTo(EXPECTED_MESSAGE);
- }
-
- @Test
- @Order(2)
- @DisplayName("encodeMessage returns correct encoded message")
- @SneakyThrows
- void encodeMessageReturnsCorrectPhrase() {
- var encodeMessageMethod = Arrays.stream(ExerciseIntroduction.class.getDeclaredMethods())
- .filter(method -> method.getName().equals("encodeMessage"))
- .findAny()
- .orElseThrow();
-
- var encodedMessage = encodeMessageMethod.invoke(new ExerciseIntroduction(), EXPECTED_MESSAGE);
-
- assertThat(encodedMessage).isEqualTo("VGhlIGtleSB0byBlZmZpY2llbnQgbGVhcm5pbmcgaXMgcHJhY3RpY2Uh");
- }
-}
diff --git a/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/Box.java b/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/Box.java
index 5a2d860ee..180603a28 100644
--- a/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/Box.java
+++ b/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/Box.java
@@ -7,18 +7,18 @@
*
* todo: refactor this class so it uses generic type "T" and run {@link com.bobocode.basics.BoxTest} to verify it
*/
-public class Box {
- private Object value;
+public class Box {
+ private T value;
- public Box(Object value) {
+ public Box(T value) {
this.value = value;
}
- public Object getValue() {
+ public T getValue() {
return value;
}
- public void setValue(Object value) {
+ public void setValue(T value) {
this.value = value;
}
}
diff --git a/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/BoxDemoApp.java b/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/BoxDemoApp.java
index bc12174ee..5bdae783b 100644
--- a/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/BoxDemoApp.java
+++ b/1-0-java-basics/1-3-0-hello-generics/src/main/java/com/bobocode/basics/BoxDemoApp.java
@@ -9,11 +9,12 @@
*/
public class BoxDemoApp {
public static void main(String[] args) {
- Box intBox = new Box(123);
- Box intBox2 = new Box(321);
+ Box intBox = new Box(123);
+ Box intBox2 = new Box(321);
System.out.println((int) intBox.getValue() + (int) intBox2.getValue());
intBox.setValue(222);
+ // must not compile!!
intBox.setValue("abc"); // this should not be allowed
// the following code will compile, but will throw runtime exception
System.out.println((int) intBox.getValue() + (int) intBox2.getValue());
diff --git a/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/CrazyGenerics.java b/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/CrazyGenerics.java
index 751d5899f..c1aca7535 100644
--- a/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/CrazyGenerics.java
+++ b/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/CrazyGenerics.java
@@ -1,14 +1,11 @@
package com.bobocode.basics;
import com.bobocode.basics.util.BaseEntity;
-import com.bobocode.util.ExerciseNotCompletedException;
import lombok.Data;
import java.io.Serializable;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
+import java.util.*;
+import java.util.function.Predicate;
/**
* {@link CrazyGenerics} is an exercise class. It consists of classes, interfaces and methods that should be updated
@@ -33,8 +30,8 @@ public class CrazyGenerics {
* @param – value type
*/
@Data
- public static class Sourced { // todo: refactor class to introduce type parameter and make value generic
- private Object value;
+ public static class Sourced { // todo: refactor class to introduce type parameter and make value generic
+ private T value;
private String source;
}
@@ -45,11 +42,17 @@ public static class Sourced { // todo: refactor class to introduce type paramete
* @param – actual, min and max type
*/
@Data
- public static class Limited {
+ public static class Limited {
// todo: refactor class to introduce type param bounded by number and make fields generic numbers
- private final Object actual;
- private final Object min;
- private final Object max;
+ private final T actual;
+ private final T min;
+ private final T max;
+
+ public Limited(T actual, T min, T max) {
+ this.actual = actual;
+ this.min = min;
+ this.max = max;
+ }
}
/**
@@ -59,8 +62,8 @@ public static class Limited {
* @param – source object type
* @param - converted result type
*/
- public interface Converter { // todo: introduce type parameters
- // todo: add convert method
+ public interface Converter { // todo: introduce type parameters
+ R convert(T param);
}
/**
@@ -70,10 +73,10 @@ public interface Converter { // todo: introduce type parameters
*
* @param – value type
*/
- public static class MaxHolder { // todo: refactor class to make it generic
- private Object max;
+ public static class MaxHolder> { // todo: refactor class to make it generic
+ private T max;
- public MaxHolder(Object max) {
+ public MaxHolder(T max) {
this.max = max;
}
@@ -82,11 +85,11 @@ public MaxHolder(Object max) {
*
* @param val a new value
*/
- public void put(Object val) {
- throw new ExerciseNotCompletedException(); // todo: update parameter and implement the method
+ public void put(T val) {
+ max = (max == null || val.compareTo(max) > 0) ? val : max;
}
- public Object getMax() {
+ public T getMax() {
return max;
}
}
@@ -97,8 +100,8 @@ public Object getMax() {
*
* @param – the type of objects that can be processed
*/
- interface StrictProcessor { // todo: make it generic
- void process(Object obj);
+ interface StrictProcessor> { // todo: make it generic
+ void process(T obj);
}
/**
@@ -108,10 +111,10 @@ interface StrictProcessor { // todo: make it generic
* @param – a type of the entity that should be a subclass of {@link BaseEntity}
* @param – a type of any collection
*/
- interface CollectionRepository { // todo: update interface according to the javadoc
- void save(Object entity);
+ interface CollectionRepository> { // todo: update interface according to the javadoc
+ void save(T entity);
- Collection getEntityCollection();
+ C getEntityCollection();
}
/**
@@ -120,7 +123,7 @@ interface CollectionRepository { // todo: update interface according to the java
*
* @param – a type of the entity that should be a subclass of {@link BaseEntity}
*/
- interface ListRepository { // todo: update interface according to the javadoc
+ interface ListRepository extends CollectionRepository> { // todo: update interface according to the javadoc
}
/**
@@ -133,7 +136,11 @@ interface ListRepository { // todo: update interface according to the javadoc
*
* @param a type of collection elements
*/
- interface ComparableCollection { // todo: refactor it to make generic and provide a default impl of compareTo
+ // todo: refactor it to make generic and provide a default impl of compareTo
+ interface ComparableCollection extends Collection, Comparable> {
+ default int compareTo(Collection> other) {
+ return Integer.compare(this.size(), other.size());
+ }
}
/**
@@ -147,9 +154,8 @@ static class CollectionUtil {
*
* @param list
*/
- public static void print(List list) {
- // todo: refactor it so the list of any type can be printed, not only integers
- list.forEach(element -> System.out.println(" – " + element));
+ public static void print(List> list) {
+ list.forEach(element -> System.out.println(" – " + element)); // todo: refactor it so the list of any type can be printed, not only integers
}
/**
@@ -160,8 +166,11 @@ public static void print(List list) {
* @param entities provided collection of entities
* @return true if at least one of the elements has null id
*/
- public static boolean hasNewEntities(Collection entities) {
- throw new ExerciseNotCompletedException(); // todo: refactor parameter and implement method
+ public static boolean hasNewEntities(Collection extends BaseEntity> entities) {
+ for (BaseEntity entity : entities)
+ if (entity.getUuid() == null)
+ return true;
+ return false;
}
/**
@@ -173,8 +182,12 @@ public static boolean hasNewEntities(Collection entities) {
* @param validationPredicate criteria for validation
* @return true if all entities fit validation criteria
*/
- public static boolean isValidCollection() {
- throw new ExerciseNotCompletedException(); // todo: add method parameters and implement the logic
+ public static boolean isValidCollection(Collection extends BaseEntity> entities, Predicate super BaseEntity> validationPredicate) {
+ for (BaseEntity entity : entities) {
+ if (!validationPredicate.test(entity))
+ return false;
+ }
+ return true;
}
/**
@@ -187,8 +200,16 @@ public static boolean isValidCollection() {
* @param entity type
* @return true if entities list contains target entity more than once
*/
- public static boolean hasDuplicates() {
- throw new ExerciseNotCompletedException(); // todo: update method signature and implement it
+ public static boolean hasDuplicates(Collection entities, T targetEntity) {
+ // todo: update method signature and implement it
+ int count = 0;
+ for (BaseEntity entity : entities) {
+ if (entity.getUuid().equals(targetEntity.getUuid()))
+ count++;
+ if (count > 1)
+ return true;
+ }
+ return false;
}
/**
@@ -201,6 +222,19 @@ public static boolean hasDuplicates() {
* @return optional max value
*/
// todo: create a method and implement its logic manually without using util method from JDK
+ public static Optional findMax(Iterable elements, Comparator super T> comparator) {
+ Iterator it = elements.iterator();
+ if (it.hasNext()) {
+ T max = it.next();
+ while (it.hasNext()) {
+ T cur = it.next();
+ if (comparator.compare(cur, max) > 0)
+ max = cur;
+ }
+ return Optional.of(max);
+ }
+ return Optional.empty();
+ }
/**
* findMostRecentlyCreatedEntity is a generic util method that accepts a collection of entities and returns the
@@ -214,7 +248,10 @@ public static boolean hasDuplicates() {
* @param entity type
* @return an entity from the given collection that has the max createdOn value
*/
- // todo: create a method according to JavaDoc and implement it using previous method
+ public static T findMostRecentlyCreatedEntity(Collection entities) {
+ return findMax(entities, CREATED_ON_COMPARATOR)
+ .orElseThrow(java.util.NoSuchElementException::new);
+ }
/**
* An util method that allows to swap two elements of any list. It changes the list so the element with the index
@@ -228,7 +265,13 @@ public static boolean hasDuplicates() {
public static void swap(List> elements, int i, int j) {
Objects.checkIndex(i, elements.size());
Objects.checkIndex(j, elements.size());
- throw new ExerciseNotCompletedException(); // todo: complete method implementation
+ swapHelper(elements, i, j);
+ }
+
+ private static void swapHelper(List list, int i, int j) {
+ T temp = list.get(i);
+ list.set(i, list.get(j));
+ list.set(j, temp);
}
}
diff --git a/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/util/BaseEntity.java b/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/util/BaseEntity.java
index f961ab7a5..10e621415 100644
--- a/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/util/BaseEntity.java
+++ b/1-0-java-basics/1-3-1-crazy-generics/src/main/java/com/bobocode/basics/util/BaseEntity.java
@@ -18,4 +18,20 @@ public BaseEntity(UUID uuid) {
this.uuid = uuid;
this.createdOn = LocalDateTime.now();
}
+
+ public UUID getUuid() {
+ return uuid;
+ }
+
+ public void setUuid(UUID uuid) {
+ this.uuid = uuid;
+ }
+
+ public LocalDateTime getCreatedOn() {
+ return createdOn;
+ }
+
+ public void setCreatedOn(LocalDateTime createdOn) {
+ this.createdOn = createdOn;
+ }
}
diff --git a/1-0-java-basics/1-3-2-heterogeneous-max-holder/src/main/java/com/bobocode/basics/HeterogeneousMaxHolder.java b/1-0-java-basics/1-3-2-heterogeneous-max-holder/src/main/java/com/bobocode/basics/HeterogeneousMaxHolder.java
index 9ef839910..60c22ac27 100644
--- a/1-0-java-basics/1-3-2-heterogeneous-max-holder/src/main/java/com/bobocode/basics/HeterogeneousMaxHolder.java
+++ b/1-0-java-basics/1-3-2-heterogeneous-max-holder/src/main/java/com/bobocode/basics/HeterogeneousMaxHolder.java
@@ -1,6 +1,6 @@
package com.bobocode.basics;
-import java.util.Map;
+import java.util.*;
/**
* {@link HeterogeneousMaxHolder} is a multi-type container that holds maximum values per each type. It's kind of a
@@ -15,6 +15,7 @@
* @author Taras Boychuk
*/
public class HeterogeneousMaxHolder {
+ Map, Object> maxValues = new HashMap<>();
/**
* A method put stores a provided value by its type, if the value is greater than the current maximum. In other words, the logic
@@ -31,6 +32,19 @@ public class HeterogeneousMaxHolder {
* @return a smaller value among the provided value and the current maximum
*/
// todo: implement a method according to javadoc
+ public > T put(Class key, T value) {
+ T cur = (T) maxValues.get(key);
+ if (cur == null) {
+ maxValues.put(key, value);
+ return null;
+ }
+ if (cur.compareTo(value) < 0) {
+ maxValues.put(key, value);
+ return cur;
+ }
+ return value;
+ }
+
/**
* An overloaded method put implements the same logic using a custom comparator. A given comparator is wrapped with
@@ -45,6 +59,23 @@ public class HeterogeneousMaxHolder {
* @return a smaller value among the provided value and the current maximum
*/
// todo: implement a method according to javadoc
+ public T put(Class key, T value, Comparator super T> comparator) {
+ Objects.requireNonNull(key);
+ Objects.requireNonNull(value);
+ Objects.requireNonNull(comparator);
+
+ comparator = Comparator.nullsFirst(comparator);
+
+ T currentMax = (T) maxValues.get(key);
+
+ if (comparator.compare(currentMax, value) < 0) {
+ maxValues.put(key, (value));
+ return currentMax;
+ } else {
+ return value;
+ }
+ }
+
/**
* A method getMax returns a max value by the given type. If no value is stored by this type, then it returns null.
@@ -54,4 +85,9 @@ public class HeterogeneousMaxHolder {
* @return current max value or null
*/
// todo: implement a method according to javadoc
+ public T getMax(Class key) {
+ T value = (T) maxValues.get(key);
+ return (value == null) ? null : value;
+ }
+
}
diff --git a/1-0-java-basics/1-5-0-hello-annotations/README.MD b/1-0-java-basics/1-5-0-hello-annotations/README.MD
deleted file mode 100644
index 70290ad7f..000000000
--- a/1-0-java-basics/1-5-0-hello-annotations/README.MD
+++ /dev/null
@@ -1,20 +0,0 @@
-# Hello Annotations
-Learn annotations basics to better understand how the frameworks use them 💪
-
-### Objectives
-
-* **create a custom annotation** ✅
-* specify **where it can be used** ([`@Target`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/annotation/Target.html)) ✅
-* specify **where its information can be accessed** ([`@Retention`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/annotation/Retention.html)) ✅
-* add **annotation members** (methods that act like fields) ✅
-* set **default value** for a member ✅
-* **use custom annotation** on a class ✅
-
-
-### Exercise overview 🇺🇦
-[](https://www.youtube.com/watch?v=KF1H2EOCdD4)
-
----
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-##
-
\ No newline at end of file
diff --git a/1-0-java-basics/1-5-0-hello-annotations/pom.xml b/1-0-java-basics/1-5-0-hello-annotations/pom.xml
deleted file mode 100644
index 753aac6cf..000000000
--- a/1-0-java-basics/1-5-0-hello-annotations/pom.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- 1-0-java-basics
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 1-5-0-hello-annotations
-
-
\ No newline at end of file
diff --git a/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/HelloAnnotationsExercise.java b/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/HelloAnnotationsExercise.java
deleted file mode 100644
index 4dc8c4b22..000000000
--- a/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/HelloAnnotationsExercise.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.bobocode.basics;
-
-/**
- * {@link HelloAnnotationsExercise} is an exercise class that is marked with be corresponding @{@link Exercise}
- * annotation. The annotation value specifies exercise name "hello-annotation-basic". It does not specify any custom
- * complexity level, because this exercise is a basic, which correspond to the default value provided by annotation.
- *
- * todo: Create an annotation @{@link Exercise}.
- * todo: Set its retention policy so it is visible at runtime
- * todo: Set its target so it can only be applied to a class
- * todo: Add String value that will store exercise name
- * todo: Add complexityLevel with a default {@link Level} basic
- *
- * @author Taras Boychuk
- */
-public class HelloAnnotationsExercise { // todo: mark class with the annotation according to the javadoc
-}
diff --git a/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Level.java b/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Level.java
deleted file mode 100644
index 28a1deb00..000000000
--- a/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Level.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.bobocode.basics;
-
-/**
- * Enum that lists all possible exercise complexity levels.
- */
-public enum Level {
- BEGINNER, BASIC, ADVANCED, CRAZY
-}
diff --git a/1-0-java-basics/1-5-0-hello-annotations/src/test/java/com/bobocode/basics/HelloAnnotationsExerciseTest.java b/1-0-java-basics/1-5-0-hello-annotations/src/test/java/com/bobocode/basics/HelloAnnotationsExerciseTest.java
deleted file mode 100644
index b0d991543..000000000
--- a/1-0-java-basics/1-5-0-hello-annotations/src/test/java/com/bobocode/basics/HelloAnnotationsExerciseTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package com.bobocode.basics;
-
-
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.*;
-
-import java.lang.annotation.*;
-
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode;
-
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-public class HelloAnnotationsExerciseTest {
-
- @Test
- @Order(1)
- @DisplayName("Annotation @Exercise exists")
- void exerciseAnnotationExists() {
- assertThatCode(this::getExerciseAnnotation).doesNotThrowAnyException();
- }
-
- @Test
- @Order(2)
- @DisplayName("@Exercise can be applied to classes and interfaces but not to methods & fields")
- @SneakyThrows
- void exerciseAnnotationCanBeAppliedForClasses() {
- var exerciseAnnotation = getExerciseAnnotation();
-
- var target = exerciseAnnotation.getAnnotation(Target.class);
-
- assertThat(target.value()).hasSize(1);
- assertThat(target.value()[0]).isEqualTo(ElementType.TYPE);
- }
-
- @Test
- @Order(3)
- @DisplayName("@Exercise information is accessible at runtime")
- @SneakyThrows
- void exerciseAnnotationInfoIsAccessibleAtRuntime() {
- var exerciseAnnotation = getExerciseAnnotation();
-
- var retention = exerciseAnnotation.getAnnotation(Retention.class);
-
- assertThat(retention.value()).isEqualTo(RetentionPolicy.RUNTIME);
- }
-
- @Test
- @Order(4)
- @DisplayName("@Exercise has declared value")
- @SneakyThrows
- void exerciseAnnotationHasValueDeclared() {
- var exerciseAnnotation = getExerciseAnnotation();
-
- assertThatCode(() -> exerciseAnnotation.getDeclaredMethod("value"))
- .doesNotThrowAnyException();
- }
-
- @Test
- @Order(4)
- @DisplayName("@Exercise has complexityLevel declared")
- @SneakyThrows
- void exerciseAnnotationHasComplexityDeclared() {
- var exerciseAnnotation = getExerciseAnnotation();
-
- assertThatCode(() -> exerciseAnnotation.getDeclaredMethod("complexityLevel"))
- .doesNotThrowAnyException();
- }
-
- @Test
- @Order(5)
- @DisplayName("@Exercise complexityLevel is BASIC by default")
- @SneakyThrows
- void exerciseAnnotationComplexityLevelDefaultValue() {
- var exerciseAnnotation = getExerciseAnnotation();
-
- var complexityLevel = exerciseAnnotation.getDeclaredMethod("complexityLevel");
-
- assertThat(complexityLevel.getDefaultValue()).isEqualTo(Level.BASIC);
- }
-
- @Test
- @Order(6)
- @DisplayName("HelloAnnotationExercise is marked as @Exercise with name \"hello-annotation-basic\"")
- @SneakyThrows
- void helloAnnotationExerciseIsAnnotatedWithExercise() {
- var exerciseAnnotationClass = getExerciseAnnotation();
- var basicExerciseAnnotation = HelloAnnotationsExercise.class.getAnnotation(exerciseAnnotationClass);
-
- var valueMethod = exerciseAnnotationClass.getMethod("value");
- var exerciseName = valueMethod.invoke(basicExerciseAnnotation);
-
- assertThat(exerciseName).isEqualTo("hello-annotation-basic");
- }
-
- @SneakyThrows
- private Class extends Annotation> getExerciseAnnotation() {
- return Class.forName("com.bobocode.basics.Exercise")
- .asSubclass(Annotation.class);
- }
-
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-1-node/README.MD b/2-0-data-structures-and-algorithms/2-2-1-node/README.MD
deleted file mode 100644
index 036f631c6..000000000
--- a/2-0-data-structures-and-algorithms/2-2-1-node/README.MD
+++ /dev/null
@@ -1,22 +0,0 @@
-# Node exercise 💪
-
-Build strong skill of creating and linking **nodes – building blocks** that are used in order to create **LinkedList**, **LinkedQueue** and other
-important data structures 💪
-
-### Pre-conditions ❗
-You're supposed to be familiar **Java classes** and **generics**
-
-### Objectives
-* implement a generic class `Node` ✅
-* **link** two node objects ✅
-* create a **list of linked nodes** ✅
-* create a **circle of linked nodes** ✅
-
-### Exercise overview 🇺🇦
-[](https://www.youtube.com/watch?v=Ot5ma8NXcS0)
-
----
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-1-node/pom.xml b/2-0-data-structures-and-algorithms/2-2-1-node/pom.xml
deleted file mode 100644
index 6549f9d70..000000000
--- a/2-0-data-structures-and-algorithms/2-2-1-node/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 2-0-data-structures-and-algorithms
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 2-2-1-node
-
-
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Node.java b/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Node.java
deleted file mode 100644
index b01a4acfb..000000000
--- a/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Node.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.bobobode.cs;
-
-/**
- * Class {@link Node} is a very simple data structure that consists of an element itself and the reference to the next
- * node. An element can have any value since it's a generic. A reference to the next node allows to link {@link Node}
- * objects and build more comprehensive data structures on top of those liked nodes.
- *
- * @param a generic type T
- * @author Taras Boychuk
- */
-public class Node {
- // todo:
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Nodes.java b/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Nodes.java
deleted file mode 100644
index 5321aa53a..000000000
--- a/2-0-data-structures-and-algorithms/2-2-1-node/src/main/java/com/bobobode/cs/Nodes.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.bobobode.cs;
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-/**
- * A class that consists of static methods only and provides util methods for {@link Node}.
- *
- * TODO: to get the most out of your learning, visit our website
- *
- *
- * @author Taras Boychuk
- */
-public class Nodes {
- private Nodes() {
- }
-
- /**
- * Creates a new instance of {@link Node} that holds provided element
- *
- * @param element any element of type T
- * @param generic type
- * @return a new instance of {@link Node}
- */
- public static Node create(T element) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Create a connection between first and second nodes, so object first stores a reference to the second.
- *
- * @param first any {@link Node} object
- * @param second any {@link Node} object
- * @param a genetic type
- */
- public static void link(Node first, Node second) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Creates two new {@link Node} objects using provided firstElement and secondElement, and create a connection
- * between those two elements so the first node will hold a reference to a second one.
- *
- * @param firstElement any element of type T
- * @param secondElement any element of type T
- * @param a genetic type
- * @return a reference to a first node created based on firstElement
- */
- public static Node pairOf(T firstElement, T secondElement) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Creates two new {@link Node} objects using provided firstElement and secondElement, and creates connections
- * between those nodes so the first node will hold a reference to a second one, and a second node will hold
- * a reference to the first one.
- *
- * @param firstElement any element of type T
- * @param secondElement any element of type T
- * @param generic type T
- * @return a reference to the first node
- */
- public static Node closedPairOf(T firstElement, T secondElement) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Creates a linked chain of {@link Node} objects based on provided elements. Creates a connection between those
- * nodes so each node will hold a reference to the next one in the chain. HINT: it's basically a linked list.
- *
- * @param elements a array of elements of type T
- * @param generic type T
- * @return a reference to the first element of the chain
- */
- public static Node chainOf(T... elements) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Creates a linked circle of {@link Node} objects based on provided elements. Creates a connection between those
- * nodes so each node will hold a reference to the next one in the chain, and the last one will hold a reference to
- * the first one.
- *
- * @param elements a array of elements of type T
- * @param generic type T
- * @return a reference to the first element of the chain
- */
- public static Node circleOf(T... elements) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-1-node/src/test/java/com/bobocode/cs/NodesTest.java b/2-0-data-structures-and-algorithms/2-2-1-node/src/test/java/com/bobocode/cs/NodesTest.java
deleted file mode 100644
index e4c020ee8..000000000
--- a/2-0-data-structures-and-algorithms/2-2-1-node/src/test/java/com/bobocode/cs/NodesTest.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package com.bobocode.cs;
-
-import com.bobobode.cs.Node;
-import com.bobobode.cs.Nodes;
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.MethodOrderer;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.util.Arrays;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class NodesTest {
-
- @Test
- @Order(1)
- void create() {
- int element = 5;
-
- Node node = Nodes.create(element);
-
- assertThat(getNodeElement(node)).isEqualTo(element);
- assertThat(getNodeNext(node)).isNull();
- }
-
- @Test
- @Order(2)
- void link() {
- Node firstNode = createNodeOf(5);
- Node secondNode = createNodeOf(9);
- Node thirdNode = createNodeOf(100);
- setNodeNext(secondNode, thirdNode);
-
- Nodes.link(firstNode, secondNode);
-
- assertThat(getNodeNext(firstNode)).isEqualTo(secondNode);
- assertThat(getNodeNext(secondNode)).isEqualTo(thirdNode);
- }
-
- @Test
- @Order(3)
- void pair() {
- int firstElement = 8;
- int secondElement = 2;
-
- Node firstNode = Nodes.pairOf(firstElement, secondElement);
-
- Node secondNode = getNodeNext(firstNode);
- assertThat(getNodeElement(firstNode)).isEqualTo(firstElement);
- assertThat(getNodeElement(secondNode)).isEqualTo(secondElement);
- assertThat(getNodeNext(secondNode)).isNull();
- }
-
- @Test
- @Order(4)
- void closedPair() {
- int firstElement = 8;
- int secondElement = 2;
-
- Node firstNode = Nodes.closedPairOf(firstElement, secondElement);
-
- Node secondNode = getNodeNext(firstNode);
- assertThat(getNodeElement(firstNode)).isEqualTo(firstElement);
- assertThat(getNodeElement(secondNode)).isEqualTo(secondElement);
- assertThat(getNodeNext(secondNode)).isEqualTo(firstNode);
- }
-
- @Test
- @Order(5)
- void chain() {
- int firstElement = 8;
- int secondElement = 1;
- int thirdElement = 13;
- int fourthElement = 5;
-
- Node firstNode = Nodes.chainOf(firstElement, secondElement, thirdElement, fourthElement);
-
- Node secondNode = getNodeNext(firstNode);
- Node thirdNode = getNodeNext(secondNode);
- Node fourthNode = getNodeNext(thirdNode);
- assertThat(getNodeElement(firstNode)).isEqualTo(firstElement);
- assertThat(getNodeElement(secondNode)).isEqualTo(secondElement);
- assertThat(getNodeElement(thirdNode)).isEqualTo(thirdElement);
- assertThat(getNodeElement(fourthNode)).isEqualTo(fourthElement);
- assertThat(getNodeNext(fourthNode)).isNull();
- }
-
- @Test
- @Order(6)
- void circle() {
- int firstElement = 8;
- int secondElement = 1;
- int thirdElement = 13;
- int fourthElement = 5;
-
- Node firstNode = Nodes.circleOf(firstElement, secondElement, thirdElement, fourthElement);
-
- Node secondNode = getNodeNext(firstNode);
- Node thirdNode = getNodeNext(secondNode);
- Node fourthNode = getNodeNext(thirdNode);
- assertThat(getNodeElement(firstNode)).isEqualTo(firstElement);
- assertThat(getNodeElement(secondNode)).isEqualTo(secondElement);
- assertThat(getNodeElement(thirdNode)).isEqualTo(thirdElement);
- assertThat(getNodeElement(fourthNode)).isEqualTo(fourthElement);
- assertThat(getNodeNext(fourthNode)).isEqualTo(firstNode);
- }
-
- @SneakyThrows
- @SuppressWarnings("unchecked")
- private Node createNodeOf(int element) {
- Constructor> constructor = Arrays.stream(Node.class.getDeclaredConstructors())
- .findAny()
- .orElseThrow();
- constructor.setAccessible(true);
- Node node;
- if (constructor.getParameters().length > 0) {
- node = (Node) constructor.newInstance(element);
- } else {
- node = (Node) constructor.newInstance();
- setNodeElement(node, element);
- }
- return node;
- }
-
- @SneakyThrows
- @SuppressWarnings("unchecked")
- private T getNodeElement(Node node) {
- Field elementField = getAccessibleElementField();
- return (T) elementField.get(node);
- }
-
- @SneakyThrows
- private void setNodeElement(Node node, T element) {
- Field elementField = getAccessibleElementField();
- elementField.set(node, element);
- }
-
- @SneakyThrows
- @SuppressWarnings("unchecked")
- private Node getNodeNext(Node node) {
- Field nextField = getAccessibleNextField();
- return (Node) nextField.get(node);
- }
-
- @SneakyThrows
- private void setNodeNext(Node node, Node next) {
- Field elementField = getAccessibleNextField();
- elementField.set(node, next);
- }
-
- private Field getAccessibleElementField() {
- Field elementField = Arrays.stream(Node.class.getDeclaredFields())
- .filter(field -> field.getType().equals(Object.class))
- .findAny()
- .orElseThrow();
- elementField.setAccessible(true);
- return elementField;
- }
-
- private Field getAccessibleNextField() {
- Field nextField = Arrays.stream(Node.class.getDeclaredFields())
- .filter(field -> field.getType().equals(Node.class))
- .findAny()
- .orElseThrow();
- nextField.setAccessible(true);
- return nextField;
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-2-stack/README.md b/2-0-data-structures-and-algorithms/2-2-2-stack/README.md
deleted file mode 100644
index fb740f365..000000000
--- a/2-0-data-structures-and-algorithms/2-2-2-stack/README.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Stack 🥞
-Learn the Stack data structure and gain deep understanding implementing it on your own 💪
-
-
-### WHY ❓
-[Stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) is one of the most important data structures
-for software developers. It can be used in various algorithms, but the most important is that **JVM creates a stack
-for each thread.** 😯 Even if you don't know anything about concurrency, and you write a simple application, it is still
-**executed by one main thread.** So each thread has its own stack, and **that stack is used to store method frames.** 😲
-A [method frame](https://docs.oracle.com/javase/specs/jvms/se16/html/jvms-2.html#jvms-2.6) is just a term. It simply
-means all the information we operate with, when executing a method. E.g. **when you pass some arguments, or create
-local variable, all that data is stored to the stack.** So, **every a method is called, a new stack frame is created and
-stored to the stack.**
-
-> It is important to understand Stack, because otherwise you won't be able to understand fundamental things like **how JVM executes methods** and **how it uses memory**.
-
-### Objectives
-* implement a generic class `Node` ✅
-* **push an element onto the stack** ✅
-* **get an element from the stack** ✅
-* maintain stack **size** ✅
-
----
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-2-stack/pom.xml b/2-0-data-structures-and-algorithms/2-2-2-stack/pom.xml
deleted file mode 100644
index 1e7a91994..000000000
--- a/2-0-data-structures-and-algorithms/2-2-2-stack/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 2-0-data-structures-and-algorithms
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 2-2-2-stack
-
-
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/LinkedStack.java b/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/LinkedStack.java
deleted file mode 100644
index 05b0c724d..000000000
--- a/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/LinkedStack.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.bobocode.cs;
-
-import com.bobocode.cs.exception.EmptyStackException;
-import com.bobocode.util.ExerciseNotCompletedException;
-
-/**
- * {@link LinkedStack} is a stack implementation that is based on singly linked generic nodes.
- * A node is implemented as inner static class {@link Node}.
- *
- * TODO: to get the most out of your learning, visit our website
- *
- *
- * @param generic type parameter
- * @author Taras Boychuk
- * @author Serhii Hryhus
- */
-public class LinkedStack implements Stack {
-
- /**
- * This method creates a stack of provided elements
- *
- * @param elements elements to add
- * @param generic type
- * @return a new stack of elements that were passed as method parameters
- */
- public static LinkedStack of(T... elements) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * The method pushes an element onto the top of this stack. This has exactly the same effect as:
- * addElement(item)
- *
- * @param element elements to add
- */
- @Override
- public void push(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * This method removes the object at the top of this stack
- * and returns that object as the value of this function.
- *
- * @return The object at the top of this stack
- * @throws EmptyStackException - if this stack is empty
- */
- @Override
- public T pop() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Returns the number of elements in the stack
- *
- * @return number of elements
- */
- @Override
- public int size() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Checks if a stack is empty
- *
- * @return {@code true} if a stack is empty, {@code false} otherwise
- */
- @Override
- public boolean isEmpty() {
- throw new ExerciseNotCompletedException(); // todo: implement this method;
- }
-
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/Stack.java b/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/Stack.java
deleted file mode 100644
index bfa428ee7..000000000
--- a/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/Stack.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.bobocode.cs;
-
-/**
- * {@link Stack} is a fundamental data structure that follows last-in-first-out (LIFO) principle. This interface
- * represents a simple contact, that can be implemented in various ways (e.g. using existing collections, arrays or
- * custom linked nodes)
- *
- * @param type parameter
- * @author Taras Boychuk
- * @author Serhii Hryhus
- */
-public interface Stack {
-
- void push(T element);
-
- T pop();
-
- int size();
-
- boolean isEmpty();
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/exception/EmptyStackException.java b/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/exception/EmptyStackException.java
deleted file mode 100644
index d0cb33c91..000000000
--- a/2-0-data-structures-and-algorithms/2-2-2-stack/src/main/java/com/bobocode/cs/exception/EmptyStackException.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.bobocode.cs.exception;
-
-public class EmptyStackException extends RuntimeException{
-
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-2-stack/src/test/java/com/bobocode/cs/LinkedStackTest.java b/2-0-data-structures-and-algorithms/2-2-2-stack/src/test/java/com/bobocode/cs/LinkedStackTest.java
deleted file mode 100644
index 0311fd1db..000000000
--- a/2-0-data-structures-and-algorithms/2-2-2-stack/src/test/java/com/bobocode/cs/LinkedStackTest.java
+++ /dev/null
@@ -1,414 +0,0 @@
-package com.bobocode.cs;
-
-import com.bobocode.cs.exception.EmptyStackException;
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.*;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.function.Predicate;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatNullPointerException;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-/**
- * A reflection-based test class for {@link LinkedStack}.
- *
- * PLEASE NOTE: we use Reflection API only for learning purposes. It should NOT be used for production tests.
- *
- * @author Ivan Virchenko
- * @author Taras Boychuk
- */
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class LinkedStackTest {
- private static final String PROPER_CLASSNAME = "Node";
-
- private static final Predicate NODE_FIELD_PREDICATE = field ->
- field.getType().getSimpleName().equals(PROPER_CLASSNAME)
- && field.getName().toLowerCase().contains("head")
- || field.getName().toLowerCase().contains("first");
-
- private static final Predicate SIZE_FIELD_PREDICATE = field ->
- field.getName().toLowerCase().contains("size");
-
- private static final Predicate NODE_ELEMENT_FIELD_PREDICATE = field ->
- field.getName().toLowerCase().contains("element")
- || field.getName().toLowerCase().contains("value")
- || field.getName().toLowerCase().contains("item");
-
- private static final Predicate NODE_NEXT_FIELD_PREDICATE = field ->
- field.getType().getSimpleName().equals(PROPER_CLASSNAME)
- && field.getName().toLowerCase().contains("next");
-
- private Stack intStack = new LinkedStack<>();
-
- @Test
- @Order(1)
- @DisplayName("Inner class Node is created")
- void checkProperInnerClassName() {
- String name = getInnerClass().getSimpleName();
- assertThat(name).isEqualTo(PROPER_CLASSNAME);
- }
-
- @Test
- @Order(2)
- @DisplayName("Class Node is a generic class")
- void noteIsAGenericClass() {
- var nodeTypeParams = getInnerClass().getTypeParameters();
-
- assertThat(nodeTypeParams).hasSize(1);
- }
-
- @Test
- @Order(3)
- @DisplayName("LinkedStack class has a field that stores a reference to the first(head) element")
- void checkProperHeadFieldName() {
- Field[] fields = LinkedStack.class.getDeclaredFields();
-
- boolean hasNodeField = Arrays.stream(fields)
- .anyMatch(NODE_FIELD_PREDICATE);
-
- assertThat(hasNodeField).isTrue();
- }
-
- @Test
- @Order(4)
- @DisplayName("LinkedStack class has a field to store stack size")
- void checkProperSizeFieldName() {
- Field[] fields = LinkedStack.class.getDeclaredFields();
-
- boolean hasSizeField = Arrays.stream(fields)
- .anyMatch(SIZE_FIELD_PREDICATE);
-
- assertThat(hasSizeField).isTrue();
- }
-
- @Test
- @Order(5)
- @DisplayName("Node class has a field to store a generic element")
- void checkProperElementField() {
- var fields = getInnerClass().getDeclaredFields();
-
- var elementField = Arrays.stream(fields)
- .filter(NODE_ELEMENT_FIELD_PREDICATE)
- .findAny()
- .orElseThrow();
- var nodeTypeParameter = getInnerClass().getTypeParameters()[0];
-
-
- assertThat(elementField.getGenericType().getTypeName()).isEqualTo(nodeTypeParameter.getTypeName());
- }
-
- @Test
- @Order(6)
- @DisplayName("Node class has a field to store a reference to the next node")
- void checkProperNextField() {
- Field[] fields = getInnerClass().getDeclaredFields();
-
- boolean hasNext = Arrays.stream(fields)
- .anyMatch(NODE_NEXT_FIELD_PREDICATE);
-
- assertThat(hasNext).isTrue();
- }
-
- @Test
- @Order(7)
- @DisplayName("Method of() creates a new LinkedStack of given elements")
- void of() {
- intStack = LinkedStack.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
-
- for (int i = 1; i <= 10; i++) {
- assertThat(contains(i)).isTrue();
- }
- }
-
- @Test
- @Order(8)
- @DisplayName("Method push() adds new element on top of the stack")
- void push() {
- intStack.push(55);
-
- assertThat(contains(55)).isTrue();
- }
-
- @Test
- @Order(9)
- @DisplayName("Method push() adds new element on top of the stack")
- void pushAddsElementWhenStackIsEmpty() {
- intStack.push(243);
-
- assertThat(contains(243)).isTrue();
- }
-
- @Test
- @Order(10)
- @DisplayName("Method push() adds new element on top of the stack when it's empty")
- void pushAddsElementToHeadWhenStackIsEmpty() {
- intStack.push(10);
-
- Object head = getHeadObject();
- int innerElement = getNodeElementInt(head);
-
- assertThat(innerElement).isEqualTo(10);
- }
-
- @Test
- @Order(11)
- @DisplayName("Method push() adds new element on top of the stack when it's not empty")
- void pushAddsElementToHeadWhenStackIsNotEmpty() {
- intStack.push(10);
- intStack.push(15);
- intStack.push(20);
-
- Object head = getHeadObject();
- int innerElement = getNodeElementInt(head);
-
- assertThat(innerElement).isEqualTo(20);
- }
-
- @Test
- @Order(12)
- @DisplayName("Method push() links new element with the previous top (head) element")
- void pushPutsHeadToNextOfNewHead() {
- fillTestStack(10, 15, 20);
-
- assertThat(getNodeElementInt(getHeadObject())).isEqualTo(20);
-
- intStack.push(30);
-
- Object head = getHeadObject();
- Object next = getNodeNextObject(head);
- int nextElement = getNodeElementInt(next);
-
- assertThat(nextElement).isEqualTo(20);
- }
-
- @Test
- @Order(13)
- @DisplayName("Method push() throws exception when element is null")
- void pushThrowsExceptionWhenElementIsNull() {
- assertThatNullPointerException().isThrownBy(() -> intStack.push(null));
- }
-
- @Test
- @Order(14)
- @DisplayName("Method pop() throws exception when stack is empty")
- void popElementWhenStackIsEmpty() {
- assertThrows(EmptyStackException.class, () -> intStack.pop());
- }
-
- @Test
- @Order(15)
- @DisplayName("Method pop() retrieves top element from the stack (LIFO)")
- void pop() {
- fillTestStack(55, 17, 66, 234);
-
- int lastElement = intStack.pop();
-
- assertThat(lastElement).isEqualTo(234);
- }
-
- @Test
- @Order(16)
- @DisplayName("Method pop() assigns next element to be a head")
- void popResetsHeadFromNextOfOldHead() {
- fillTestStack(10, 15, 20);
- Object head = getHeadObject();
-
- assertThat(getNodeElementInt(head)).isEqualTo(20);
-
- intStack.pop();
- head = getHeadObject();
-
- assertThat(getNodeElementInt(head)).isEqualTo(15);
- }
-
- @Test
- @Order(17)
- @DisplayName("Method size() returns 0 when stack is empty")
- void sizeWhenStackIsEmpty() {
- int actualSize = getInnerSize();
-
- assertThat(actualSize).isEqualTo(0);
- }
-
- @Test
- @Order(18)
- @DisplayName("Method size() returns number of element in the stack")
- void size() {
- fillTestStack(1, 5, 7);
-
- assertThat(intStack.size()).isEqualTo(3);
- }
-
- @Test
- @Order(19)
- @DisplayName("Method size() returns correct value when stack was created via method of()")
- void sizeIncreasesWhenUseOfMethod() {
- intStack = LinkedStack.of(1, 2, 3, 4, 5, 6, 7, 8);
-
- assertThat(intStack.size()).isEqualTo(8);
- }
-
- @Test
- @Order(20)
- @DisplayName("Method size() correct value when elements were added via push()")
- void sizeIncreasesWhenPush() {
- intStack.push(1);
- intStack.push(2);
- intStack.push(3);
-
- assertThat(intStack.size()).isEqualTo(3);
- }
-
- @Test
- @Order(21)
- @DisplayName("Method size() correct value when elements were removed via pop()")
- void sizeDecreasesWhenPop() {
- fillTestStack(1, 2, 3, 4, 5);
- intStack.pop();
-
- assertThat(intStack.size()).isEqualTo(4);
- }
-
- @Test
- @Order(22)
- @DisplayName("Method isEmpty() returns true when stack contains elements")
- void isEmpty() {
- fillTestStack(87, 53, 66);
-
- boolean stackEmpty = intStack.isEmpty();
-
- assertThat(stackEmpty).isEqualTo(false);
- }
-
- @Test
- @Order(23)
- @DisplayName("Method isEmpty() returns false when stack contains no elements")
- void isEmptyWhenStackIsEmpty() {
- boolean stackEmpty = intStack.isEmpty();
- assertThat(stackEmpty).isEqualTo(true);
- }
-
- private Class> getInnerClass() {
- return Arrays.stream(LinkedStack.class.getDeclaredClasses())
- .filter(Class::isMemberClass)
- .findAny().orElseThrow();
- }
-
- private Field getHeadField() {
- Field headField = Arrays.stream(LinkedStack.class.getDeclaredFields())
- .filter(NODE_FIELD_PREDICATE)
- .findAny()
- .orElseThrow();
- headField.setAccessible(true);
- return headField;
- }
-
- private Field getNodeElementField(Object node) {
- Field fieldElement = Arrays.stream(node.getClass().getDeclaredFields())
- .filter(NODE_ELEMENT_FIELD_PREDICATE)
- .findAny()
- .orElseThrow();
- fieldElement.setAccessible(true);
- return fieldElement;
- }
-
- private Field getNodeNextField(Object node) {
- Field field = Arrays.stream(node.getClass().getDeclaredFields())
- .filter(NODE_NEXT_FIELD_PREDICATE)
- .findAny()
- .orElseThrow();
- field.setAccessible(true);
- return field;
- }
-
- @SneakyThrows
- private Object getHeadObject() {
- return getHeadField().get(intStack);
- }
-
- @SneakyThrows
- private int getNodeElementInt(Object node) {
- return (int) getNodeElementField(node).get(node);
- }
-
- @SneakyThrows
- private Object getNodeNextObject(Object node) {
- return getNodeNextField(node).get(node);
- }
-
- private boolean contains(int element) {
- Object head = getHeadObject();
- if (head == null) {
- return false;
- }
-
- if (getNodeNextObject(head) != null) {
- return checkNext(head, element);
- } else {
- return getNodeElementInt(head) == element;
- }
- }
-
- private boolean checkNext(Object node, int element) {
- if (getNodeElementInt(node) == element) {
- return true;
- } else {
- return checkNext(getNodeNextObject(node), element);
- }
- }
-
- @SneakyThrows
- private Object newNode(int element) {
- Constructor> constructor = getInnerClass().getDeclaredConstructors()[0];
- constructor.setAccessible(true);
-
- if (constructor.getParameters().length == 1) {
- return constructor.newInstance(element);
- } else if (constructor.getParameters().length == 2) {
- return constructor.newInstance(element, null);
- } else {
- Object node = constructor.newInstance();
- getNodeElementField(node).set(node, element);
- return node;
- }
- }
-
- private void fillTestStack(int... elements) {
- for (int element : elements) {
- addToStack(element);
- }
- setInnerSize(elements.length);
- }
-
- @SneakyThrows
- private void addToStack(int element) {
- Object newNode = newNode(element);
- if (getHeadObject() != null) {
- getNodeNextField(newNode).set(newNode, getHeadObject());
- }
- getHeadField().set(intStack, newNode);
- }
-
- private Field getInnerSizeField() {
- Field size = Arrays.stream(LinkedStack.class.getDeclaredFields())
- .filter(SIZE_FIELD_PREDICATE)
- .findAny()
- .orElseThrow();
- size.setAccessible(true);
- return size;
- }
-
- @SneakyThrows
- private void setInnerSize(int size) {
- getInnerSizeField().set(intStack, size);
- }
-
- @SneakyThrows
- private int getInnerSize() {
- return (int) getInnerSizeField().get(intStack);
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/README.MD b/2-0-data-structures-and-algorithms/2-2-3-linked-queue/README.MD
deleted file mode 100644
index a5419bbae..000000000
--- a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/README.MD
+++ /dev/null
@@ -1,17 +0,0 @@
-# Linked Queue
-Learn the idea of a queue and build strong skills implementing a queue based on linked nodes 💪
-
-### Pre-conditions ❗
-You're supposed to be familiar [Queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) data structure and generics in Java
-
-### Objectives
-* implement a generic class `Node` ✅
-* **add an element** to the end of the queue ✅
-* **retrieve an element** from the begging of the queue ** ✅
-* maintain queue **size** ✅
-
----
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/pom.xml b/2-0-data-structures-and-algorithms/2-2-3-linked-queue/pom.xml
deleted file mode 100644
index 860b6ee24..000000000
--- a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 2-0-data-structures-and-algorithms
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 2-2-3-linked-queue
-
-
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/LinkedQueue.java b/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/LinkedQueue.java
deleted file mode 100644
index 7b4a79667..000000000
--- a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/LinkedQueue.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.bobocode.cs;
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-/**
- * {@link LinkedQueue} implements FIFO {@link Queue}, using singly linked nodes. Nodes are stores in instances of nested
- * class Node. In order to perform operations {@link LinkedQueue#add(Object)} and {@link LinkedQueue#poll()}
- * in a constant time, it keeps to references to the head and tail of the queue.
- *
- * TODO: to get the most out of your learning, visit our website
- *
- *
- * @param a generic parameter
- * @author Taras Boychuk
- * @author Ivan Virchenko
- */
-public class LinkedQueue implements Queue {
-
- /**
- * Adds an element to the end of the queue.
- *
- * @param element the element to add
- */
- public void add(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Retrieves and removes queue head.
- *
- * @return an element that was retrieved from the head or null if queue is empty
- */
- public T poll() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Returns a size of the queue.
- *
- * @return an integer value that is a size of queue
- */
- public int size() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Checks if the queue is empty.
- *
- * @return {@code true} if the queue is empty, returns {@code false} if it's not
- */
- public boolean isEmpty() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/Queue.java b/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/Queue.java
deleted file mode 100644
index 4aa0a28d1..000000000
--- a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/main/java/com/bobocode/cs/Queue.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.bobocode.cs;
-
-/**
- * Queue is a data structure that follows "first in, first out" rule (FIFO). Operations {@link Queue#add(Object)} and
- * {@link Queue#poll()} are performed in constant time O(1)
- */
-public interface Queue {
- /**
- * Adds an element to the end of the queue.
- *
- * @param element the element to add
- */
- void add(T element);
-
- /**
- * Retrieves and removes queue head.
- *
- * @return an element that was retrieved from the head or null if queue is empty
- */
- T poll();
-
- /**
- * Returns a size of the queue.
- *
- * @return an integer value that is a size of queue
- */
- int size();
-
- /**
- * Checks if the queue is empty.
- *
- * @return {@code true} if the queue is empty, returns {@code false} if it's not
- */
- boolean isEmpty();
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/test/java/com/bobocode/cs/LinkedQueueTest.java b/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/test/java/com/bobocode/cs/LinkedQueueTest.java
deleted file mode 100644
index 88c1a7d9d..000000000
--- a/2-0-data-structures-and-algorithms/2-2-3-linked-queue/src/test/java/com/bobocode/cs/LinkedQueueTest.java
+++ /dev/null
@@ -1,377 +0,0 @@
-package com.bobocode.cs;
-
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.MethodOrderer;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.function.Predicate;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * A reflection-based test class for {@link LinkedQueue}.
- *
- * PLEASE NOTE: we use Reflection API only for learning purposes. It should NOT be used for production tests.
- *
- * @author Victor Kuzma
- * @author Taras Boychuk
- * @author Ivan Virchenko
- */
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-public class LinkedQueueTest {
- private static final String NODE_NAME = "Node";
- private static final String SIZE_NAME = "size";
-
- private static final Predicate NODE_FIELD = field ->
- field.getType().getSimpleName().equals(NODE_NAME) && (field.getName().contains("next"));
-
- private static final Predicate ELEMENT_FIELD = field ->
- field.getGenericType().getTypeName().equals("T")
- && (field.getName().contains("elem") || field.getName().contains("value") || field.getName().contains("item"));
-
- private static final Predicate NEXT_FIELD = field ->
- field.getGenericType().getTypeName().endsWith("Node") && (field.getName().contains("next"));
-
- private static final Predicate SIZE_FIELD = field ->
- field.getType().getSimpleName().equals("int") && (field.getName().equals(SIZE_NAME));
-
- private static final Predicate HEAD_FIELD = field ->
- field.getType().getSimpleName().equals(NODE_NAME)
- && (field.getName().contains("head") || field.getName().contains("first"));
-
- private static final Predicate TAIL_FIELD = field ->
- field.getType().getSimpleName().equals(NODE_NAME)
- && (field.getName().contains("tail") || field.getName().contains("last"));
-
- private Queue integerQueue = new LinkedQueue<>();
-
- @Test
- @Order(1)
- void createNodeClass() {
- Class> innerClass = getInnerStaticNodeClass();
- String name = innerClass.getSimpleName();
-
- assertThat(name).isEqualTo(NODE_NAME);
- }
-
- @Test
- @Order(2)
- void checkFieldsNameInNodeClass() {
- Class> innerClass = getInnerStaticNodeClass();
- boolean hasElementField = hasField(innerClass, ELEMENT_FIELD);
- boolean hasNodeField = hasField(innerClass, NODE_FIELD);
-
- assertThat(hasElementField).isTrue();
- assertThat(hasNodeField).isTrue();
- }
-
- @Test
- @Order(3)
- void checkFieldsInQueueCLass() {
- Class> baseClass = this.integerQueue.getClass();
- boolean hasHeadField = hasField(baseClass, HEAD_FIELD);
- boolean hasSizeFiled = hasField(baseClass, SIZE_FIELD);
- boolean hasTailFiled = hasField(baseClass, TAIL_FIELD);
-
- assertThat(hasHeadField).isTrue();
- assertThat(hasSizeFiled).isTrue();
- assertThat(hasTailFiled).isTrue();
- }
-
- @Test
- @Order(4)
- void addFillsQueueWhenItIsEmpty() {
- integerQueue.add(1);
- integerQueue.add(228);
- int size = getInternalSize();
- boolean isEmpty = isEmptyQueue();
- Integer firstElement = (Integer) pollElementFromQueue();
- Integer secondElement = (Integer) pollElementFromQueue();
-
- assertThat(size).isEqualTo(2);
- assertThat(isEmpty).isEqualTo(false);
- assertThat(firstElement).isEqualTo(1);
- assertThat(secondElement).isEqualTo(228);
- }
-
- @Test
- @Order(5)
- void addFillsQueueWhenItIsNotEmpty() {
- addIntElementToQueue(12);
- addIntElementToQueue(13);
- integerQueue.add(111);
- int size = getInternalSize();
- boolean isEmpty = isEmptyQueue();
- Integer firstElement = (Integer) pollElementFromQueue();
- Integer secondElement = (Integer) pollElementFromQueue();
- Integer tailValue = (Integer) getNodeValue(TAIL_FIELD);
-
- assertThat(size).isEqualTo(3);
- assertThat(isEmpty).isEqualTo(false);
- assertThat(firstElement).isEqualTo(12);
- assertThat(secondElement).isEqualTo(13);
- assertThat(tailValue).isEqualTo(111);
- }
-
- @Test
- @Order(6)
- void addIncreasesQueueSize() {
- integerQueue.add(1);
- integerQueue.add(2);
- int size = getInternalSize();
-
- assertThat(size).isEqualTo(2);
- }
-
- @Test
- @Order(7)
- void pollReturnsNullWhenQueueIsEmpty() {
- Integer firstElement = this.integerQueue.poll();
-
- assertThat(firstElement).isEqualTo(null);
- }
-
- @Test
- @Order(8)
- void pollDeletesElementFromHead() {
- addIntElementToQueue(11);
- addIntElementToQueue(111);
- Integer firstElement = this.integerQueue.poll();
- Integer secondElement = this.integerQueue.poll();
- boolean isEmpty = isEmptyQueue();
-
- assertThat(isEmpty).isEqualTo(true);
- assertThat(firstElement).isEqualTo(11);
- assertThat(secondElement).isEqualTo(111);
- }
-
- @Test
- @Order(9)
- void pollDecreasesQueueSize() {
- addIntElementToQueue(11);
- addIntElementToQueue(111);
- this.integerQueue.poll();
- int size = getInternalSize();
-
- assertThat(size).isEqualTo(1);
- }
-
- @Test
- @Order(10)
- void pollMakesSizeZeroWhenQueueHasSingleElement() {
- addIntElementToQueue(12);
- Integer element = this.integerQueue.poll();
- int size = getInternalSize();
-
- assertThat(size).isEqualTo(0);
- assertThat(element).isEqualTo(12);
- }
-
- @Test
- @SneakyThrows
- @Order(11)
- void pollMakesQueueEmptyWhenQueueHasSingleElement() {
- addIntElementToQueue(1);
- this.integerQueue.poll();
- boolean isEmpty = isEmptyQueue();
-
- Object tail = getAccessibleFieldByPredicate(integerQueue, TAIL_FIELD).get(integerQueue);
- Object head = getAccessibleFieldByPredicate(integerQueue, HEAD_FIELD).get(integerQueue);
-
- assertThat(isEmpty).isEqualTo(true);
- assertThat(tail).isNull();
- assertThat(head).isNull();
- }
-
- @Test
- @Order(12)
- void sizeReturnsZeroWhenQueueIsEmpty() {
- int size = this.integerQueue.size();
-
- assertThat(size).isEqualTo(0);
- }
-
- @Test
- @Order(13)
- void size() {
- addIntElementToQueue(1);
- int size = this.integerQueue.size();
-
- assertThat(size).isEqualTo(1);
- }
-
- @Test
- @Order(14)
- void isEmptyReturnsTrueWhenQueueIsEmpty() {
- boolean isEmpty = this.integerQueue.isEmpty();
-
- assertThat(isEmpty).isEqualTo(true);
- }
-
- @Test
- @Order(15)
- void isEmpty() {
- addIntElementToQueue(1);
- boolean isEmpty = integerQueue.isEmpty();
-
- assertThat(isEmpty).isEqualTo(false);
- }
-
-
- private Class> getInnerStaticNodeClass() {
- return Arrays.stream(integerQueue.getClass().getDeclaredClasses())
- .filter(aClass -> Modifier.isStatic(aClass.getModifiers()))
- .findAny()
- .orElseThrow();
- }
-
- private boolean hasField(Class> classToSearch, Predicate targetField) {
- return Arrays.stream(classToSearch.getDeclaredFields())
- .anyMatch(targetField);
- }
-
- @SneakyThrows
- private int getInternalSize() {
- return (int) getAccessibleFieldByPredicate(this.integerQueue, SIZE_FIELD)
- .get(this.integerQueue);
- }
-
-
- @SneakyThrows
- private Object pollElementFromQueue() {
- Object element;
- Object nextElement;
- Object tail;
- Object head = getAccessibleFieldByPredicate(this.integerQueue,
- HEAD_FIELD)
- .get(this.integerQueue);
-
- Integer size = (Integer) getAccessibleFieldByPredicate(this.integerQueue,
- SIZE_FIELD)
- .get(this.integerQueue);
-
- if (head != null) {
- element = getAccessibleFieldByPredicate(head, ELEMENT_FIELD)
- .get(head);
-
- nextElement = getAccessibleFieldByPredicate(head, NODE_FIELD)
- .get(head);
-
- head = nextElement;
- setHead(head);
-
- if (head == null) {
- tail = null;
- setTail(tail);
- }
-
- if (size != null) {
- int tmpInt = size;
- tmpInt--;
- setInternalSize(tmpInt);
- }
-
- return element;
- } else {
- return null;
- }
- }
-
- @SneakyThrows
- private void addIntElementToQueue(int value) {
- Object newNode = createNode(value);
- Object head = getAccessibleFieldByPredicate(this.integerQueue, HEAD_FIELD).get(this.integerQueue);
- Object tail = getAccessibleFieldByPredicate(this.integerQueue, TAIL_FIELD).get(this.integerQueue);
- Integer size = (Integer) getAccessibleFieldByPredicate(this.integerQueue, SIZE_FIELD).get(this.integerQueue);
-
- if (head == null) {
- setHead(newNode);
- } else {
- setNextNode(tail, newNode);
- }
- setTail(newNode);
-
- if (size == null) {
- setInternalSize(1);
- } else {
- int tmpInt = size;
- tmpInt++;
- setInternalSize(tmpInt);
- }
- }
-
- @SneakyThrows
- private Object createNode(int value) {
- Object nodeObject;
- Class> innerClass = getInnerStaticNodeClass();
- Constructor>[] declaredConstructors = innerClass.getDeclaredConstructors();
- Constructor> constructor = declaredConstructors[0];
- constructor.setAccessible(true);
-
- if (constructor.getParameterTypes().length == 1) {
- nodeObject = constructor.newInstance(value);
- } else {
- nodeObject = constructor.newInstance();
- Field nodeElement = getAccessibleFieldByPredicate(nodeObject, ELEMENT_FIELD);
- nodeElement.set(nodeObject, value);
- }
-
- return nodeObject;
- }
-
- @SneakyThrows
- private boolean isEmptyQueue() {
- Object head = getAccessibleFieldByPredicate(this.integerQueue,
- HEAD_FIELD)
- .get(this.integerQueue);
- return head == null;
- }
-
- @SneakyThrows
- private void setInternalSize(int size) {
- Field sizeField = getAccessibleFieldByPredicate(this.integerQueue,
- SIZE_FIELD);
- sizeField.setInt(this.integerQueue, size);
- }
-
- @SneakyThrows
- private void setHead(Object obj) {
- Field head = getAccessibleFieldByPredicate(this.integerQueue, HEAD_FIELD);
- head.set(this.integerQueue, obj);
- }
-
- @SneakyThrows
- private void setTail(Object obj) {
- Field tail = getAccessibleFieldByPredicate(this.integerQueue, TAIL_FIELD);
- tail.set(this.integerQueue, obj);
- }
-
- @SneakyThrows
- private void setNextNode(Object current, Object next) {
- Field nodeNextField = getAccessibleFieldByPredicate(current, NEXT_FIELD);
- nodeNextField.set(current, next);
- }
-
- private Field getAccessibleFieldByPredicate(Object object, Predicate predicate) {
- Field field = Arrays.stream(object.getClass().getDeclaredFields())
- .filter(predicate)
- .findAny()
- .orElseThrow();
- field.setAccessible(true);
- return field;
- }
-
- @SneakyThrows
- private Object getNodeValue(Predicate predicate) {
- Object field = getAccessibleFieldByPredicate(integerQueue, predicate).get(integerQueue);
- final Field value = getAccessibleFieldByPredicate(field, ELEMENT_FIELD);
- value.setAccessible(true);
- return value.get(field);
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-4-linked-list/README.MD b/2-0-data-structures-and-algorithms/2-2-4-linked-list/README.MD
deleted file mode 100644
index 7ef45a4bb..000000000
--- a/2-0-data-structures-and-algorithms/2-2-4-linked-list/README.MD
+++ /dev/null
@@ -1,22 +0,0 @@
-# Linked List
-Build strong skills implementing a well known Linked List data structure 💪
-
-### Pre-conditions ❗
-You're supposed to be familiar [Linked List](https://en.wikipedia.org/wiki/Linked_list) data structure and generics in Java
-
-### Objectives
-* implement a generic class `Node` ✅
-* **add an element** to the end of the list in **O(1)** ✅
-* **add an element by index** (relink nodes when adding a new one inside the chain) ✅
-* **set element** by index (find the correct node by index starting from `head`) ✅
-* **remove element** by index (link prev and next nodes to get rid of the one that should be removed) ✅
-* maintain list **size** ✅
-
-### Exercise overview 🇺🇦
-[](https://www.youtube.com/watch?v=knhSNO3bAHo)
-
----
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-4-linked-list/pom.xml b/2-0-data-structures-and-algorithms/2-2-4-linked-list/pom.xml
deleted file mode 100644
index d6e007661..000000000
--- a/2-0-data-structures-and-algorithms/2-2-4-linked-list/pom.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
- 2-0-data-structures-and-algorithms
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 2-2-4-linked-list
-
-
-
-
- com.bobocode
- data-structures-and-algorithms-util
- 1.0-SNAPSHOT
-
-
-
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/main/java/com/bobocode/cs/LinkedList.java b/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/main/java/com/bobocode/cs/LinkedList.java
deleted file mode 100644
index 502fefbdf..000000000
--- a/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/main/java/com/bobocode/cs/LinkedList.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.bobocode.cs;
-
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-/**
- * {@link LinkedList} is a list implementation that is based on singly linked generic nodes. A node is implemented as
- * inner static class {@link Node}.
- *
- * TODO: to get the most out of your learning, visit our website
- *
- *
- * @param generic type parameter
- * @author Taras Boychuk
- * @author Serhii Hryhus
- */
-public class LinkedList implements List {
-
- /**
- * This method creates a list of provided elements
- *
- * @param elements elements to add
- * @param generic type
- * @return a new list of elements the were passed as method parameters
- */
- public static LinkedList of(T... elements) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Adds an element to the end of the list.
- *
- * @param element element to add
- */
- @Override
- public void add(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Adds a new element to the specific position in the list. In case provided index in out of the list bounds it
- * throws {@link IndexOutOfBoundsException}
- *
- * @param index an index of new element
- * @param element element to add
- */
- @Override
- public void add(int index, T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Changes the value of an list element at specific position. In case provided index in out of the list bounds it
- * throws {@link IndexOutOfBoundsException}
- *
- * @param index an position of element to change
- * @param element a new element value
- */
- @Override
- public void set(int index, T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Retrieves an elements by its position index. In case provided index in out of the list bounds it
- * throws {@link IndexOutOfBoundsException}
- *
- * @param index element index
- * @return an element value
- */
- @Override
- public T get(int index) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Returns the first element of the list. Operation is performed in constant time O(1)
- *
- * @return the first element of the list
- * @throws java.util.NoSuchElementException if list is empty
- */
- @Override
- public T getFirst() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Returns the last element of the list. Operation is performed in constant time O(1)
- *
- * @return the last element of the list
- * @throws java.util.NoSuchElementException if list is empty
- */
- @Override
- public T getLast() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Removes an elements by its position index. In case provided index in out of the list bounds it
- * throws {@link IndexOutOfBoundsException}
- *
- * @param index element index
- * @return deleted element
- */
- @Override
- public T remove(int index) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
-
- /**
- * Checks if a specific exists in he list
- *
- * @return {@code true} if element exist, {@code false} otherwise
- */
- @Override
- public boolean contains(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Checks if a list is empty
- *
- * @return {@code true} if list is empty, {@code false} otherwise
- */
- @Override
- public boolean isEmpty() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Returns the number of elements in the list
- *
- * @return number of elements
- */
- @Override
- public int size() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Removes all list elements
- */
- @Override
- public void clear() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/test/java/com/bobocode/cs/LinkedListTest.java b/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/test/java/com/bobocode/cs/LinkedListTest.java
deleted file mode 100644
index 3f9ec1f9d..000000000
--- a/2-0-data-structures-and-algorithms/2-2-4-linked-list/src/test/java/com/bobocode/cs/LinkedListTest.java
+++ /dev/null
@@ -1,614 +0,0 @@
-package com.bobocode.cs;
-
-
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.MethodOrderer;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.NoSuchElementException;
-import java.util.function.Predicate;
-
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
-
-/**
- * A reflection-based test class for {@link LinkedList}.
- *
- * PLEASE NOTE: we use Reflection API only for learning purposes. It should NOT be used for production tests.
- *
- * @author Serhii Hryhus
- * @author Taras Boychuk
- */
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-public class LinkedListTest {
- private static final Predicate NODE_FIELD = field ->
- field.getType().getSimpleName().equals("Node");
-
- private static final Predicate HEAD_NODE_FIELD = field ->
- field.getType().getSimpleName().equals("Node")
- && (field.getName().contains("head") || field.getName().contains("first"));
-
- private static final Predicate TAIL_NODE_FIELD = field ->
- field.getType().getSimpleName().equals("Node")
- && (field.getName().equals("tail") || field.getName().contains("last"));
-
- private static final Predicate SIZE_FIELD = field ->
- field.getName().equals("size");
-
- private static final Predicate ELEMENT_FIELD = field ->
- field.getGenericType().getTypeName().equals("T")
- && (field.getName().contains("elem") || field.getName().contains("value") || field.getName().contains("item"));
-
- private LinkedList intList = new LinkedList<>();
-
- @Test
- @Order(1)
- void properNodeName() {
- Class> innerClass = getInnerClass();
-
- String name = innerClass.getSimpleName();
-
- assertThat(name).isEqualTo("Node");
- }
-
- @Test
- @Order(2)
- void properNodeFields() {
- Class> innerClass = getInnerClass();
-
- boolean hasElementField = Arrays.stream(innerClass.getDeclaredFields())
- .anyMatch(ELEMENT_FIELD);
-
- boolean hasNodeField = Arrays.stream(innerClass.getDeclaredFields())
- .anyMatch(NODE_FIELD);
-
- assertThat(hasElementField).isTrue();
- assertThat(hasNodeField).isTrue();
- }
-
- private Class> getInnerClass() {
- return Arrays.stream(intList.getClass().getDeclaredClasses())
- .filter(aClass -> Modifier.isStatic(aClass.getModifiers()))
- .findAny()
- .orElseThrow();
- }
-
- @Test
- @Order(3)
- void addIntoEmptyList() {
- intList.add(41);
-
- int element = getInternalElement(0);
-
- assertThat(element).isEqualTo(41);
- }
-
- @Test
- @Order(4)
- void addIntoEmptyListChangesSize() {
- intList.add(41);
-
- int size = getInternalSize();
-
- assertThat(size).isEqualTo(1);
- }
-
- @Test
- @Order(5)
- void add() {
- intList.add(41);
- intList.add(30);
- intList.add(75);
-
- int firstElement = getInternalElement(0);
- int secondElement = getInternalElement(1);
- int thirdElement = getInternalElement(2);
-
- assertThat(firstElement).isEqualTo(41);
- assertThat(secondElement).isEqualTo(30);
- assertThat(thirdElement).isEqualTo(75);
- }
-
- @Test
- @Order(6)
- void addChangesSize() {
- intList.add(41);
- intList.add(30);
- intList.add(75);
-
- int size = getInternalSize();
-
- assertThat(size).isEqualTo(3);
- }
-
- @Test
- @Order(7)
- void addByIndex() {
- addInternalElements(43, 5, 6, 8);
-
- int newElementIdx = 2;
- intList.add(newElementIdx, 66);
-
- int elementByNewElementIndex = getInternalElement(newElementIdx);
- int size = getInternalSize();
-
- assertThat(elementByNewElementIndex).isEqualTo(66);
- assertThat(getInternalElement(0)).isEqualTo(43);
- assertThat(getInternalElement(1)).isEqualTo(5);
- assertThat(getInternalElement(3)).isEqualTo(6);
- assertThat(getInternalElement(4)).isEqualTo(8);
- assertThat(size).isEqualTo(5);
- }
-
- @Test
- @Order(8)
- void addByZeroIndexWhenListIsEmpty() {
- intList.add(0, 45);
-
- int element = getInternalElement(0);
- int size = getInternalSize();
-
- assertThat(element).isEqualTo(45);
- assertThat(size).isEqualTo(1);
- }
-
- @Test
- @Order(9)
- void addByIndexToTheEndOfList() {
- addInternalElements(98, 64, 23, 1, 3, 4);
-
- int newElementIndex = getInternalSize();
- intList.add(newElementIndex, 44);
-
- assertThat(getInternalElement(newElementIndex)).isEqualTo(44);
- assertThat(getInternalSize()).isEqualTo(7);
- }
-
- @Test
- @Order(10)
- void addToHeadWhenListIsNotEmpty() {
- addInternalElements(4, 6, 8, 9, 0, 2);
-
- intList.add(0, 53);
-
- int firstElement = getInternalElement(0);
- int secondElement = getInternalElement(1);
- int size = getInternalSize();
-
- assertThat(firstElement).isEqualTo(53);
- assertThat(secondElement).isEqualTo(4);
- assertThat(size).isEqualTo(7);
- }
-
- @Test
- @Order(11)
- void addThrowsExceptionWhenIndexIsNegative() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> intList.add(-1, 66));
- }
-
- @Test
- @Order(12)
- void addThrowsExceptionWhenIndexLargerThanSize() {
- addInternalElements(4, 6, 11, 9);
-
- int newElementIdx = 5;
-
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> intList.add(newElementIdx, 88));
- }
-
- @Test
- @Order(13)
- void addWhenIndexEqualToSize() {
- addInternalElements(1, 2, 3, 4, 5); // size = 5
-
- intList.add(5, 111);
-
- int element = getInternalElement(5);
- int size = getInternalSize();
-
- assertThat(element).isEqualTo(111);
- assertThat(size).isEqualTo(6);
- }
-
- @Test
- @Order(14)
- void of() {
- intList = LinkedList.of(43, 233, 54);
-
- assertThat(getInternalElement(0)).isEqualTo(43);
- assertThat(getInternalElement(1)).isEqualTo(233);
- assertThat(getInternalElement(2)).isEqualTo(54);
- }
-
- @Test
- @Order(15)
- void ofChangeSize() {
- intList = LinkedList.of(43, 233, 54);
-
- int size = getInternalSize();
-
- assertThat(size).isEqualTo(3);
- }
-
- @Test
- @Order(16)
- void setByIndex() {
- addInternalElements(34, 78, 9, 8);
-
- int index = 2; //element = 78
- intList.set(index, 99);
-
- int elementOnNewElementIndex = getInternalElement(index);
- int nextElementToNewElementIndex = getInternalElement(3);
- int internalSize = getInternalSize();
-
- assertThat(elementOnNewElementIndex).isEqualTo(99);
- assertThat(nextElementToNewElementIndex).isEqualTo(8);
- assertThat(getInternalElement(0)).isEqualTo(34);
- assertThat(getInternalElement(1)).isEqualTo(78);
- assertThat(internalSize).isEqualTo(4);
- }
-
- @Test
- @Order(17)
- void setFirstElementWhenListIsEmpty() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> intList.set(0, 34));
- }
-
- @Test
- @Order(18)
- void setByIndexEqualToSize() {
- addInternalElements(2, 3, 4); // size = 3
-
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> intList.set(3, 222));
- }
-
- @Test
- @Order(19)
- void get() {
- addInternalElements(25, 87, 45);
-
- int firstElement = intList.get(0);
- int secondElement = intList.get(1);
- int thirdElement = intList.get(2);
-
- assertThat(firstElement).isEqualTo(25);
- assertThat(secondElement).isEqualTo(87);
- assertThat(thirdElement).isEqualTo(45);
-
- }
-
- @Test
- @Order(20)
- void getByZeroIndexWhenListHasSingleElement() {
- addInternalElements(25);
-
- int element = intList.get(0);
-
- assertThat(element).isEqualTo(25);
- }
-
- @Test
- @Order(21)
- void getByZeroIndexWhenListIsEmpty() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> intList.get(0));
- }
-
- @Test
- @Order(22)
- void getWhenIndexIsNegative() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> intList.get(-1));
- }
-
- @Test
- @Order(23)
- void getWhenIndexIsEqualToListSize() {
- addInternalElements(33, 46, 25, 87, 45);
-
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> intList.get(5));
- }
-
- @Test
- @Order(24)
- void getFirst() {
- addInternalElements(31, 32, 5);
-
- int firstElement = intList.getFirst();
-
- assertThat(firstElement).isEqualTo(31);
- }
-
- @Test
- @Order(25)
- void getLast() {
- addInternalElements(41, 6, 42);
-
- int lastElement = intList.getLast();
-
- assertThat(lastElement).isEqualTo(42);
- }
-
- @Test
- @Order(26)
- void getFirstWhenListIsEmpty() {
- assertThatExceptionOfType(NoSuchElementException.class)
- .isThrownBy(() -> intList.getFirst());
- }
-
- @Test
- @Order(27)
- void getLastWhenListIsEmpty() {
- assertThatExceptionOfType(NoSuchElementException.class)
- .isThrownBy(() -> intList.getLast());
- }
-
-
- @Test
- @Order(28)
- void remove() {
- addInternalElements(1, 2, 3, 4, 5);
-
- int elementIndex = 2;
- int deletedElement = intList.remove(elementIndex); // element = 3
-
- int replacedElement = getInternalElement(elementIndex);
-
- assertThat(deletedElement).isEqualTo(3);
- assertThat(replacedElement).isEqualTo(4);
- }
-
- @Test
- @Order(29)
- void removeChangesSize() {
- addInternalElements(1, 2, 3, 4, 5);
-
- int elementIndex = 2;
- int deletedElement = intList.remove(elementIndex); // element = 3
-
- int size = getInternalSize();
-
- assertThat(deletedElement).isEqualTo(3);
- assertThat(size).isEqualTo(4);
- }
-
- @Test
- @Order(30)
- void removeFirst() {
- addInternalElements(4, 6, 8, 9);
-
- int deletedElement = intList.remove(0);
-
- int replacedElement = getInternalElement(0);
- int size = getInternalSize();
-
- assertThat(deletedElement).isEqualTo(4);
- assertThat(replacedElement).isEqualTo(6);
- assertThat(size).isEqualTo(3);
- }
-
- @Test
- @Order(31)
- void removeLast() {
- addInternalElements(4, 6, 8, 9);
-
- int deletedElement = intList.remove(getInternalSize() - 1);
-
- int newLastElement = getInternalElement(getInternalSize() - 1);
- int tailElement = (int) getNodeValue(TAIL_NODE_FIELD);
-
- int size = getInternalSize();
-
- assertThat(deletedElement).isEqualTo(9);
- assertThat(newLastElement).isEqualTo(8);
- assertThat(tailElement).isEqualTo(8);
- assertThat(size).isEqualTo(3);
- }
-
- @Test
- @Order(32)
- void removeWhenListIsEmpty() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> intList.remove(234));
- }
-
- @Test
- @Order(33)
- void removeByZeroIndexWhenListIsEmpty() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> intList.remove(0));
- }
-
- @Test
- @Order(34)
- void size() {
- setInternalSize(5);
-
- int sizeFromMethod = intList.size();
-
- assertThat(sizeFromMethod).isEqualTo(5);
- }
-
- @Test
- @Order(35)
- void sizeWhenListIsEmpty() {
- int size = getInternalSize();
-
- assertThat(size).isEqualTo(0);
- }
-
- @Test
- @Order(36)
- void contains() {
- addInternalElements(45, 6, 3, 6);
-
- boolean containsExistingElement = intList.contains(3);
- boolean containsNotExistingElement = intList.contains(54);
-
- assertThat(containsExistingElement).isTrue();
- assertThat(containsNotExistingElement).isFalse();
- }
-
- @Test
- @Order(37)
- void containsWhenListIsEmpty() {
- boolean contains = intList.contains(34);
-
- assertThat(contains).isFalse();
- }
-
- @Test
- @Order(38)
- void isEmpty() {
- addInternalElements(34, 5, 6);
-
- boolean empty = intList.isEmpty();
-
- assertThat(empty).isFalse();
- }
-
- @Test
- @Order(39)
- void isEmptyWhenListIsEmpty() {
- boolean empty = intList.isEmpty();
-
- assertThat(empty).isTrue();
- }
-
- @Test
- @Order(40)
- void clearWhenListIsEmpty() {
- intList.clear();
-
- int size = getInternalSize();
-
- assertThat(size).isEqualTo(0);
- }
-
- @Test
- @Order(41)
- void clearChangesSize() {
- addInternalElements(4, 5, 6);
-
- intList.clear();
-
- int size = getInternalSize();
-
- assertThat(size).isEqualTo(0);
- }
-
- @Test
- @Order(42)
- void clearRemovesAllElements() {
- addInternalElements(4, 5, 6);
-
- intList.clear();
-
- assertThatExceptionOfType(NullPointerException.class)
- .isThrownBy(() -> getInternalElement(0));
- }
-
- @SneakyThrows
- private int getInternalElement(int index) {
-
- Object head = getAccessibleFieldByPredicate(intList, HEAD_NODE_FIELD).get(intList);
-
- for (int j = 0; j < index; j++) {
- head = getAccessibleFieldByPredicate(head, NODE_FIELD).get(head);
- }
- return (int) getAccessibleFieldByPredicate(head, ELEMENT_FIELD).get(head);
- }
-
- @SneakyThrows
- private int getInternalSize() {
- return (int) getAccessibleFieldByPredicate(intList, SIZE_FIELD).get(intList);
- }
-
- @SneakyThrows
- private void addInternalElements(int... elements) {
- Field nodeField = getInternalHeadField();
- Field tailNode = getInternalTailField();
- Class> nodeType = nodeField.getType();
-
- Object previousObject = intList;
- Object nodeObject = null;
-
- for (int element : elements) {
- nodeObject = createNodeObjectWithInternalElement(nodeType, element);
- nodeField.set(previousObject, nodeObject);
- nodeField = getAccessibleFieldByPredicate(nodeObject, NODE_FIELD);
- previousObject = nodeObject;
- }
-
- tailNode.set(intList, nodeObject);
- setInternalSize(elements.length);
- }
-
- private Field getInternalHeadField() {
- return getAccessibleFieldByPredicate(intList, HEAD_NODE_FIELD);
- }
-
- private Field getInternalTailField() {
- return getAccessibleFieldByPredicate(intList, TAIL_NODE_FIELD);
- }
-
- @SneakyThrows
- private void setInternalSize(int size) {
- Field sizeField = getAccessibleFieldByPredicate(intList, SIZE_FIELD);
- sizeField.setInt(intList, size);
- }
-
- @SneakyThrows
- private Object createNodeObjectWithInternalElement(Class> nodeClass, int element) {
- Object nodeObject;
- Constructor>[] declaredConstructors = nodeClass.getDeclaredConstructors();
- Constructor> constructor;
-
- constructor = declaredConstructors[0];
- constructor.setAccessible(true);
- if (constructor.getParameterTypes().length == 1) {
- nodeObject = constructor.newInstance(element);
- } else {
- nodeObject = createNodeByConstructorWithoutParameters(element, constructor);
- }
- return nodeObject;
- }
-
- @SneakyThrows
- private Object createNodeByConstructorWithoutParameters(int element, Constructor> constructor) {
- Object nodeObject;
- nodeObject = constructor.newInstance();
- Field nodeElement = getAccessibleFieldByPredicate(nodeObject, ELEMENT_FIELD);
- nodeElement.set(nodeObject, element);
- return nodeObject;
- }
-
- private Field getAccessibleFieldByPredicate(Object object, Predicate predicate) {
- Field field = Arrays.stream(object.getClass().getDeclaredFields())
- .filter(predicate)
- .findAny()
- .orElseThrow();
- field.setAccessible(true);
- return field;
- }
-
- @SneakyThrows
- private Object getNodeValue(Predicate predicate) {
- Object field = getAccessibleFieldByPredicate(intList, predicate).get(intList);
- final Field value = getAccessibleFieldByPredicate(field, ELEMENT_FIELD);
- value.setAccessible(true);
- return value.get(field);
- }
-}
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-5-array-list/README.MD b/2-0-data-structures-and-algorithms/2-2-5-array-list/README.MD
deleted file mode 100644
index 8b925f53a..000000000
--- a/2-0-data-structures-and-algorithms/2-2-5-array-list/README.MD
+++ /dev/null
@@ -1,27 +0,0 @@
-# Array List
-
-Build strong skills implementing a well known Array List data structure 💪
-
-### Pre-conditions ❗
-
-* You're supposed to be familiar `List` collection and generics in Java
-
-### Objectives
-
-* use array of type `Object` to store any elements ✅
-* resize array using native method `System.arrayCopy()` ✅
-* **add an element** to the end of array ✅
-* **add an element by index** (shift whole array tail to the right) ✅
-* **set element** by index ✅
-* **remove element** by index (shift whole array tail to the left) ✅
-* maintain list **size** ✅
-
-### Exercise overview 🇺🇦
-[](https://www.youtube.com/watch?v=jFBKToSC3ag)
-
----
-
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-5-array-list/pom.xml b/2-0-data-structures-and-algorithms/2-2-5-array-list/pom.xml
deleted file mode 100644
index 7637723fb..000000000
--- a/2-0-data-structures-and-algorithms/2-2-5-array-list/pom.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
- 2-0-data-structures-and-algorithms
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 2-2-5-array-list
-
-
-
-
- com.bobocode
- data-structures-and-algorithms-util
- 1.0-SNAPSHOT
-
-
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-5-array-list/src/main/java/com/bobocode/cs/ArrayList.java b/2-0-data-structures-and-algorithms/2-2-5-array-list/src/main/java/com/bobocode/cs/ArrayList.java
deleted file mode 100644
index 384ca81e5..000000000
--- a/2-0-data-structures-and-algorithms/2-2-5-array-list/src/main/java/com/bobocode/cs/ArrayList.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package com.bobocode.cs;
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-/**
- * {@link ArrayList} is an implementation of {@link List} interface. This resizable data structure
- * based on an array and is simplified version of {@link java.util.ArrayList}.
- *
- * TODO: to get the most out of your learning, visit our website
- *
- *
- * @author Serhii Hryhus
- */
-public class ArrayList implements List {
-
- /**
- * This constructor creates an instance of {@link ArrayList} with a specific capacity of an array inside.
- *
- * @param initCapacity - the initial capacity of the list
- * @throws IllegalArgumentException – if the specified initial capacity is negative or 0.
- */
- public ArrayList(int initCapacity) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * This constructor creates an instance of {@link ArrayList} with a default capacity of an array inside.
- * A default size of inner array is 5;
- */
- public ArrayList() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Creates and returns an instance of {@link ArrayList} with provided elements
- *
- * @param elements to add
- * @return new instance
- */
- public static List of(T... elements) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Adds an element to the array.
- *
- * @param element element to add
- */
- @Override
- public void add(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Adds an element to the specific position in the array where
- *
- * @param index index of position
- * @param element element to add
- */
- @Override
- public void add(int index, T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Retrieves an element by its position index. In case provided index in out of the list bounds it
- * throws {@link IndexOutOfBoundsException}
- *
- * @param index index of element
- * @return en element
- */
- @Override
- public T get(int index) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Returns the first element of the list. Operation is performed in constant time O(1)
- *
- * @return the first element of the list
- * @throws java.util.NoSuchElementException if list is empty
- */
- @Override
- public T getFirst() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Returns the last element of the list. Operation is performed in constant time O(1)
- *
- * @return the last element of the list
- * @throws java.util.NoSuchElementException if list is empty
- */
- @Override
- public T getLast() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Changes the value of array at specific position. In case provided index in out of the list bounds it
- * throws {@link IndexOutOfBoundsException}
- *
- * @param index position of value
- * @param element a new value
- */
- @Override
- public void set(int index, T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Removes an elements by its position index. In case provided index in out of the list bounds it
- * throws {@link IndexOutOfBoundsException}
- *
- * @param index element index
- * @return deleted element
- */
- @Override
- public T remove(int index) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Checks for existing of a specific element in the list.
- *
- * @param element is element
- * @return If element exists method returns true, otherwise it returns false
- */
- @Override
- public boolean contains(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Checks if a list is empty
- *
- * @return {@code true} if list is empty, {@code false} otherwise
- */
- @Override
- public boolean isEmpty() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * @return amount of saved elements
- */
- @Override
- public int size() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-
- /**
- * Removes all list elements
- */
- @Override
- public void clear() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-5-array-list/src/test/java/com/bobocode/cs/ArrayListTest.java b/2-0-data-structures-and-algorithms/2-2-5-array-list/src/test/java/com/bobocode/cs/ArrayListTest.java
deleted file mode 100644
index 3db9b465b..000000000
--- a/2-0-data-structures-and-algorithms/2-2-5-array-list/src/test/java/com/bobocode/cs/ArrayListTest.java
+++ /dev/null
@@ -1,406 +0,0 @@
-package com.bobocode.cs;
-
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.MethodOrderer;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
-
-import java.lang.reflect.Field;
-import java.util.NoSuchElementException;
-
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
-
-/**
- * A reflection-based test class for {@link ArrayList}.
- *
- * PLEASE NOTE: we use Reflection API only for learning purposes. It should NOT be used for production tests.
- *
- * @author Serhii Hryhus
- * @author Ivan Virchenko
- */
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class ArrayListTest {
-
- private List arrayList = new ArrayList<>();
-
- @Test
- @Order(1)
- void add() {
- arrayList.add(10);
- arrayList.add(15);
- arrayList.add(20);
-
- Object[] internalArray = getTestArray();
-
- assertThat(internalArray[0]).isEqualTo(10);
- assertThat(internalArray[1]).isEqualTo(15);
- assertThat(internalArray[2]).isEqualTo(20);
- }
-
- @Test
- @Order(2)
- void sizeOfEmptyArrayWrapper() {
- assertThat(arrayList.size()).isEqualTo(0);
- }
-
- @Test
- @Order(3)
- void size() {
- setTestSize(3);
- assertThat(arrayList.size()).isEqualTo(3);
- }
-
- @Test
- @Order(4)
- void getElementsByIndex() {
- fillTestArray(10, 15, 20);
-
- assertThat(arrayList.get(0)).isEqualTo(10);
- assertThat(arrayList.get(1)).isEqualTo(15);
- assertThat(arrayList.get(2)).isEqualTo(20);
- assertThat(arrayList.size()).isEqualTo(3);
- }
-
- @Test
- @Order(5)
- void getFirstElement() {
- fillTestArray(31, 24);
- assertThat(arrayList.getFirst()).isEqualTo(31);
- }
-
- @Test
- @Order(6)
- void getLastElement() {
- fillTestArray(31, 34);
- assertThat(arrayList.getLast()).isEqualTo(34);
- }
-
- @Test
- @Order(7)
- void getFirstOfEmptyList() {
- assertThatExceptionOfType(NoSuchElementException.class)
- .isThrownBy(() -> arrayList.getFirst());
- }
-
- @Test
- @Order(8)
- void getLastOfEmptyList() {
- assertThatExceptionOfType(NoSuchElementException.class)
- .isThrownBy(() -> arrayList.getLast());
- }
-
- @Test
- @Order(9)
- void createListWithSpecificArrayCapacity() {
- arrayList = new ArrayList<>(8);
- assertThat(getTestArray().length).isEqualTo(8);
- }
-
- @Test
- @Order(10)
- void createListWithWrongCapacity() {
- assertThatExceptionOfType(IllegalArgumentException.class)
- .isThrownBy(() -> arrayList = new ArrayList<>(-2));
- }
-
- @Test
- @Order(11)
- void addElements() {
- arrayList = ArrayList.of(15, 69, 58, 78);
-
- assertThat(getTestArray()[0]).isEqualTo(15);
- assertThat(getTestArray()[1]).isEqualTo(69);
- assertThat(getTestArray()[2]).isEqualTo(58);
- assertThat(getTestArray()[3]).isEqualTo(78);
- assertThat(getTestSize()).isEqualTo(4);
- }
-
- @Test
- @Order(12)
- void addShouldResizeDefaultCapacityWhenArrayIsFull() {
- arrayList = new ArrayList<>();
- int defaultCapacity = getTestArray().length;
-
- arrayList.add(15);
- arrayList.add(69);
- arrayList.add(58);
- arrayList.add(78);
- arrayList.add(6);
- arrayList.add(33);
- arrayList.add(21);
-
- assertThat(getTestArray().length).isGreaterThan(defaultCapacity);
- assertThat(getTestSize()).isEqualTo(7);
- }
-
- @Test
- @Order(13)
- void addShouldResizeSpecificCapacityWhenArrayIsFull() {
- arrayList = new ArrayList<>(4);
-
- arrayList.add(15);
- arrayList.add(69);
- arrayList.add(58);
- arrayList.add(78);
- arrayList.add(6);
- arrayList.add(33);
- arrayList.add(21);
-
- assertThat(getTestArray().length).isGreaterThan(4);
- assertThat(getTestSize()).isEqualTo(7);
- }
-
- @Test
- @Order(14)
- void addElementByIndex() {
- fillTestArray(15, 69, 58, 78, 68);
-
- arrayList.add(50);
- arrayList.add(2, 10);
-
- Object[] internalArray = getTestArray();
-
- assertThat(internalArray[2]).isEqualTo(10);
- assertThat(internalArray[5]).isEqualTo(68);
- assertThat(getTestSize()).isEqualTo(7);
- }
-
- @Test
- @Order(15)
- void addElementByNegativeIndex() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.add(-1, 66));
- }
-
- @Test
- @Order(16)
- void addElementByIndexLargerThanListSize() {
- setTestSize(4);
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.add(5, 88));
- }
-
- @Test
- @Order(17)
- void addElementByIndexEqualToSize() {
- fillTestArray(1, 2, 3, 4, 5);
-
- arrayList.add(5, 111);
-
- Object[] internalArray = getTestArray();
-
- assertThat(internalArray[5]).isEqualTo(111);
- assertThat(getTestSize()).isEqualTo(6);
- }
-
- @Test
- @Order(18)
- void getFirstElementFromEmptyList() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.get(0));
- }
-
- @Test
- @Order(19)
- void getElementByNegativeIndex() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.get(-1));
- }
-
- @Test
- @Order(20)
- void getElementByIndexThrowsExceptionWhenIndexIsOutOfBound() {
- fillTestArray(1, 2, 3, 4);
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.get(4));
- }
-
- @Test
- @Order(21)
- void setElementByIndex() {
- fillTestArray(15, 69, 58, 78);
- Object[] internalArray = getTestArray();
-
- arrayList.set(2, 10);
-
- assertThat(internalArray[2]).isEqualTo(10);
- assertThat(internalArray[3]).isEqualTo(78);
- assertThat(getTestSize()).isEqualTo(4);
- }
-
- @Test
- @Order(22)
- void setElementByIndexThrowsExceptionWhenIndexIsOutOfBound() {
- fillTestArray(15, 69, 58, 78);
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.set(4, 10));
- }
-
- @Test
- @Order(23)
- void setFirstElementOnEmptyList() {
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.set(0, 34));
- }
-
- @Test
- @Order(24)
- void removeElementByIndex() {
- fillTestArray(15, 69, 58, 78, 100);
- Object[] internalArray = getTestArray();
-
- int removedElement = arrayList.remove(2);
-
- assertThat(internalArray[2]).isEqualTo(78);
- assertThat(internalArray[1]).isEqualTo(69);
- assertThat(getTestSize()).isEqualTo(4);
- assertThat(removedElement).isEqualTo(58);
- }
-
- @Test
- @Order(25)
- void removeElementByIndexThrowsExceptionWhenIndexEqualsSize() {
- fillTestArray(15, 69, 58, 78);
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.remove(4));
- }
-
- @Test
- @Order(26)
- void removeLastElementByIndex() {
- fillTestArray(15, 69, 58, 78, 100);
- Object[] internalArray = getTestArray();
-
- int removedElement = arrayList.remove(4);
-
- assertThat(internalArray[3]).isEqualTo(78);
- assertThat(getTestSize()).isEqualTo(4);
- assertThat(removedElement).isEqualTo(100);
- }
-
- @Test
- @Order(27)
- void removeElementByIndexThrowsExceptionWhenIndexIsOutOfBounds() {
- fillTestArray(15, 69, 58, 78, 100);
-
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.remove(6));
- }
-
- @Test
- @Order(28)
- void containsOnEmptyList() {
- assertThat(arrayList.contains(8)).isEqualTo(false);
- }
-
- @Test
- @Order(29)
- void containsElement() {
- fillTestArray(15, 69, 58, 78, 100);
- assertThat(arrayList.contains(58)).isEqualTo(true);
- }
-
- @Test
- @Order(30)
- void containsNotExistingWhenArrayIsNotFilled() {
- arrayList = new ArrayList<>(100);
- Object[] internalArray = getTestArray();
- internalArray[0] = 5;
- internalArray[1] = 10;
-
- boolean result = arrayList.contains(3);
-
- assertThat(result).isFalse();
- }
-
- @Test
- @Order(31)
- void findNotExistingElement() {
- fillTestArray(15, 69, 58, 78, 100);
- assertThat(arrayList.contains(200)).isEqualTo(false);
- }
-
- @Test
- @Order(32)
- void isEmptyOnEmptyList() {
- assertThat(arrayList.isEmpty()).isEqualTo(true);
- }
-
- @Test
- @Order(33)
- void isEmpty() {
- setTestSize(3);
- assertThat(arrayList.isEmpty()).isEqualTo(false);
- }
-
- @Test
- @Order(34)
- void clearOnEmptyList() {
- assertThat(arrayList.isEmpty()).isEqualTo(true);
- }
-
- @Test
- @Order(35)
- void clearChangesTheSize() {
- setTestSize(100);
- arrayList.clear();
-
- assertThat(arrayList.size()).isEqualTo(0);
- }
-
- @Test
- @Order(36)
- void clearRemovesElements() {
- fillTestArray(4, 5, 6);
-
- arrayList.clear();
-
- assertThatExceptionOfType(IndexOutOfBoundsException.class)
- .isThrownBy(() -> arrayList.get(0));
- }
-
- @SneakyThrows
- private void setTestSize(int size) {
- Field sizeField = arrayList.getClass().getDeclaredField("size");
- sizeField.setAccessible(true);
- sizeField.set(arrayList, size);
- }
-
- @SneakyThrows
- private int getTestSize() {
- Field testSize = arrayList.getClass().getDeclaredField("size");
- testSize.setAccessible(true);
- return (int) testSize.get(arrayList);
- }
-
- @SneakyThrows
- private Object[] getTestArray() {
- Field field = arrayList.getClass().getDeclaredField(getTestArrayName());
- field.setAccessible(true);
- return (Object[]) field.get(arrayList);
- }
-
- private String getTestArrayName() {
- Field[] fields = arrayList.getClass().getDeclaredFields();
- String name = null;
- for (Field field : fields) {
- if (field.getType().isArray()) {
- field.setAccessible(true);
- name = field.getName();
- }
- }
- return name;
- }
-
- @SneakyThrows
- private void fillTestArray(Object... elements) {
- Field arrayField = arrayList.getClass().getDeclaredField(getTestArrayName());
- Field sizeField = arrayList.getClass().getDeclaredField("size");
- arrayField.setAccessible(true);
- sizeField.setAccessible(true);
- arrayField.set(arrayList, elements);
- sizeField.set(arrayList, elements.length);
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/README.md b/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/README.md
deleted file mode 100644
index 4a86347ae..000000000
--- a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Binary Search Tree
-Learn tree data structures and build strong skills implementing binary search tree using recursion 💪
-
-### Pre-conditions ❗️
-* You're supposed to be familiar with trees like [Binary Search Tree](https://en.wikipedia.org/wiki/Binary_search_tree)
-* You should understand the [recursion](https://en.wikipedia.org/wiki/Recursion_(computer_science))
-
-### Objectives
-* implement a generic class `Node` with left and right child nodes ✅
-* **insert an element** to the tree using recursion ✅
-* **search an element** in the tree ✅
-* **traverse tree elements** in a ascending order ✅
-* calculate tree **depth** ✅
-* maintain tree **size** ✅
-
-
-### Exercise overview 🇺🇦
-[](https://www.youtube.com/watch?v=alxzyWswCVg)
-
----
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/pom.xml b/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/pom.xml
deleted file mode 100644
index ea8608159..000000000
--- a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 2-0-data-structures-and-algorithms
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 2-2-6-binary-search-tree
-
-
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/BinarySearchTree.java b/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/BinarySearchTree.java
deleted file mode 100644
index d7462484d..000000000
--- a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/BinarySearchTree.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.bobocode.cs;
-
-import java.util.function.Consumer;
-
-public interface BinarySearchTree> {
- /**
- * insert an element
- * @return true if element did not exist in the tree and was inserted successfully
- */
- boolean insert(T element);
-
- /**
- * @return true if tree contains element
- */
- boolean contains(T element);
-
- /**
- * @return number of elements in the tree
- */
- int size();
-
- /**
- * @return max. number of transition between root node and any other node; 0 - if tree is empty or contains 1 element
- */
- int depth();
-
- /**
- * traverse the tree in element's natural order
- * @param consumer accepts ref. to node during traversing
- */
- void inOrderTraversal(Consumer consumer);
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/RecursiveBinarySearchTree.java b/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/RecursiveBinarySearchTree.java
deleted file mode 100644
index a4e394b0b..000000000
--- a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/main/java/com/bobocode/cs/RecursiveBinarySearchTree.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.bobocode.cs;
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-import java.util.function.Consumer;
-
-/**
- * {@link RecursiveBinarySearchTree} is an implementation of a {@link BinarySearchTree} that is based on a linked nodes
- * and recursion. A tree node is represented as a nested class {@link Node}. It holds an element (a value) and
- * two references to the left and right child nodes.
- *
- * TODO: to get the most out of your learning, visit our website
- *
- *
- * @param a type of elements that are stored in the tree
- * @author Taras Boychuk
- * @author Maksym Stasiuk
- */
-public class RecursiveBinarySearchTree> implements BinarySearchTree {
-
- public static > RecursiveBinarySearchTree of(T... elements) {
- throw new ExerciseNotCompletedException();
- }
-
- @Override
- public boolean insert(T element) {
- throw new ExerciseNotCompletedException();
- }
-
- @Override
- public boolean contains(T element) {
- throw new ExerciseNotCompletedException();
- }
-
- @Override
- public int size() {
- throw new ExerciseNotCompletedException();
- }
-
- @Override
- public int depth() {
- throw new ExerciseNotCompletedException();
- }
-
- @Override
- public void inOrderTraversal(Consumer consumer) {
- throw new ExerciseNotCompletedException();
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/test/java/com/bobocode/cs/RecursiveBinarySearchTreeTest.java b/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/test/java/com/bobocode/cs/RecursiveBinarySearchTreeTest.java
deleted file mode 100644
index ac58a0b41..000000000
--- a/2-0-data-structures-and-algorithms/2-2-6-binary-search-tree/src/test/java/com/bobocode/cs/RecursiveBinarySearchTreeTest.java
+++ /dev/null
@@ -1,447 +0,0 @@
-package com.bobocode.cs;
-
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.MethodOrderer;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatNullPointerException;
-import static org.junit.jupiter.params.provider.Arguments.arguments;
-
-/**
- * A reflection-based test class for {@link ArrayList}.
- *
- * PLEASE NOTE: we use Reflection API only for learning purposes. It should NOT be used for production tests.
- *
- * @author Ivan Virchenko
- * @author Maksym Stasiuk
- */
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class RecursiveBinarySearchTreeTest {
- private static final Predicate SIZE_FIELD = field ->
- field.getName().toLowerCase().contains("size") || field.getName().toLowerCase().contains("length");
-
- private static final Predicate NODE_FIELD = field ->
- field.getType().getSimpleName().equals("Node");
-
- private static final Predicate ELEMENT_FIELD = field ->
- field.getName().toLowerCase().contains("element")
- || field.getName().toLowerCase().contains("item")
- || field.getName().toLowerCase().contains("value");
-
- private static final Predicate LEFT_FIELD = field ->
- field.getName().toLowerCase().contains("left")
- && field.getType().getSimpleName().equals("Node");
-
- private static final Predicate RIGHT_FIELD = field ->
- field.getName().toLowerCase().contains("right")
- && field.getType().getSimpleName().equals("Node");
-
- private static final Integer[] someElements = {10, 9, 11, 8, 12, 7};
-
- private BinarySearchTree tree = new RecursiveBinarySearchTree<>();
-
- @Test
- @Order(1)
- void properNodeClassNameCheck() {
- Class> innerClass = getInnerClass();
- String name = innerClass.getSimpleName();
-
- assertThat(name).isEqualTo("Node");
- }
-
- @Test
- @Order(2)
- void properTreeFieldsCheck() {
- Class> treeClass = tree.getClass();
-
- boolean hasSizeField = Arrays.stream(treeClass.getDeclaredFields())
- .anyMatch(SIZE_FIELD);
-
- boolean hasNodeField = Arrays.stream(treeClass.getDeclaredFields())
- .anyMatch(NODE_FIELD);
-
- assertThat(hasSizeField).isTrue();
- assertThat(hasNodeField).isTrue();
- }
-
- @Test
- @Order(3)
- void properNodeFieldsCheck() {
- Class> innerClass = getInnerClass();
-
- boolean isElement = Arrays.stream(innerClass.getDeclaredFields())
- .anyMatch(ELEMENT_FIELD);
-
- boolean isLeft = Arrays.stream(innerClass.getDeclaredFields())
- .anyMatch(LEFT_FIELD);
-
- boolean isRight = Arrays.stream(innerClass.getDeclaredFields())
- .anyMatch(RIGHT_FIELD);
-
- assertThat(isElement).isTrue();
- assertThat(isLeft).isTrue();
- assertThat(isRight).isTrue();
- }
-
- @Test
- @Order(4)
- void of() {
- tree = RecursiveBinarySearchTree.of(someElements);
- for (var e : someElements) {
- assertThat(contains(getRootObject(), e)).isTrue();
- }
- assertThat(getInnerSize()).isEqualTo(someElements.length);
- }
-
- @Test
- @Order(5)
- void insert() {
- for (Integer e : someElements) {
- assertThat(contains(getRootObject(), e)).isFalse(); //does not contain
- assertThat(tree.insert(e)).isTrue(); //do insert
- assertThat(contains(getRootObject(), e)).isTrue(); //and contains
- }
- }
-
- @Test
- @Order(6)
- void insertToRootIfTreeIsEmpty() {
- assertThat(getRootObject()).isNull();
- tree.insert(10);
- assertThat(getRootObject()).isNotNull();
- }
-
- @Test
- @Order(7)
- void insertLeftIfLessThanRoot() {
- tree.insert(10); //root
- tree.insert(5); //left
-
- assertThat(getLeftNode(getRootObject())).isNotNull();
- }
-
- @Test
- @Order(8)
- void insertRightIfGreaterThanRoot() {
- tree.insert(10); //root
- tree.insert(15); //right
-
- assertThat(getRightNode(getRootObject())).isNotNull();
- }
-
- @Test
- @Order(9)
- void insertDoesNotAddDuplicateElements() {
- fillTestTree(10, 11, 12);
-
- assertThat(tree.insert(10)).isFalse();
- assertThat(tree.insert(11)).isFalse();
- assertThat(tree.insert(12)).isFalse();
- }
-
- @Test
- @Order(10)
- void insertThrowsExceptionWhenArgumentIsNull() {
- fillTestTree(someElements);
- assertThatNullPointerException().isThrownBy(
- () -> tree.insert(null)
- );
- }
-
- @Test
- @Order(11)
- void containsReturnsTrueIfElementExist() {
- fillTestTree(9, 10, 11);
-
- assertThat(tree.contains(10)).isTrue();
- assertThat(tree.contains(9)).isTrue();
- assertThat(tree.contains(11)).isTrue();
- }
-
- @Test
- @Order(12)
- void containsReturnsFalseIfElementDoesntExist() {
- fillTestTree(someElements);
- assertThat(tree.contains(100)).isFalse();
- }
-
- @Test
- @Order(13)
- void containsThrowsExceptionIFParameterIsNull() {
- assertThatNullPointerException().isThrownBy(() -> tree.contains(null));
- }
-
- @Test
- @Order(14)
- void sizeIsGrowingWhenInserting() {
- tree.insert(10);
- tree.insert(15);
- tree.insert(20);
-
- assertThat(getInnerSize()).isEqualTo(3);
- }
-
- @Test
- @Order(15)
- void sizeDoesNotGrowWhenInsertingNotUnique() {
- fillTestTree(10, 11, 12);
-
- assertThat(getInnerSize()).isEqualTo(3);
-
- tree.insert(10);
- tree.insert(11);
- tree.insert(12);
-
- assertThat(getInnerSize()).isEqualTo(3);
- }
-
- @Order(16)
- @ParameterizedTest
- @MethodSource("depthArguments")
- void depth(Integer[] elements, int depth) {
- fillTestTree(elements);
- assertThat(tree.depth()).isEqualTo(depth);
- }
-
- @Test
- @Order(17)
- void depthGrowWhenInsert() {
-
- tree.insert(13);
- tree.insert(11);
- tree.insert(12);
- tree.insert(15);
- tree.insert(-15);
-
- assertThat(tree.depth()).isGreaterThan(0);
- }
-
- @Test
- @Order(18)
- void depthIsZeroIfRootIsNull() {
- assertThat(tree.depth()).isEqualTo(0);
- }
-
- @Test
- @Order(19)
- void inorderTraversal() {
- fillTestTree(someElements);
- Integer[] sortedElements = Arrays.copyOf(someElements, someElements.length);
- Arrays.sort(sortedElements);
-
- List traversedElements = new ArrayList<>(getInnerSize());
- tree.inOrderTraversal(traversedElements::add);
-
- assertThat(traversedElements).isEqualTo(List.of(sortedElements));
- }
-
- public static Stream depthArguments() {
- return Stream.of(
- //empty tree
- arguments(new Integer[]{}, 0),
- //tree with a single element
- arguments(new Integer[]{24}, 0),
- /*
- * .......10
- * ....../ \
- * .....5 15
- * ..../ \
- * ...1 20
- */
- arguments(new Integer[]{10, 5, 15, 1, 20}, 2),
- /*
- * ..1
- * ...\
- * ....2
- * .....\
- * ..... 3
- * .......\
- * ........4
- * .........\
- * ..........5
- */
- arguments(new Integer[]{1, 2, 3, 4, 5}, 4),
- /*
- * .........6
- * ....../.....\
- * .....2.......7
- * .../...\......\
- * ..1.....5......8
- * ......./........\
- * ......4..........9
- * ...../.............
- * ....3...............
- */
- arguments(new Integer[]{6, 2, 7, 1, 5, 8, 4, 9, 3}, 4));
- }
-
-
- @SneakyThrows
- private int getInnerSize() {
- return (int) getInnerSizeField().get(tree);
- }
-
- private Field getInnerSizeField() {
- Field sizeField = Arrays.stream(tree.getClass().getDeclaredFields())
- .filter(SIZE_FIELD)
- .findAny()
- .orElseThrow();
- sizeField.setAccessible(true);
- return sizeField;
- }
-
- private Class> getInnerClass() {
- return Arrays.stream(tree.getClass().getDeclaredClasses())
- .filter(Class::isMemberClass)
- .findAny()
- .orElseThrow();
- }
-
- @SneakyThrows
- private Field getRootField() {
- Field nodeField = Arrays.stream(tree.getClass().getDeclaredFields())
- .filter(NODE_FIELD)
- .findAny()
- .orElseThrow();
- nodeField.setAccessible(true);
- return nodeField;
- }
-
- @SneakyThrows
- private Object getRootObject() {
- Field nodeField = Arrays.stream(tree.getClass().getDeclaredFields())
- .filter(NODE_FIELD)
- .findAny()
- .orElseThrow();
- nodeField.setAccessible(true);
- return nodeField.get(tree);
- }
-
- @SneakyThrows
- private boolean contains(Object node, int element) {
- return findNodeByElement(node, element) != null;
- }
-
- private Object findNodeByElement(Object node, int element) {
- if (node == null) {
- return null;
- }
- if (element == getElement(node)) {
- return node;
- } else if (element < getElement(node)) {
- return findNodeByElement(getLeftNode(node), element);
- } else if (element > getElement(node)) {
- return findNodeByElement(getRightNode(node), element);
- } else {
- return node;
- }
- }
-
- @SneakyThrows
- private Field getNodesField(Object node, Predicate option) {
- Field field = Arrays.stream(node.getClass().getDeclaredFields())
- .filter(option)
- .findAny()
- .orElseThrow();
- field.setAccessible(true);
- return field;
- }
-
- @SneakyThrows
- private int getElement(Object node) {
- return (int) getNodesField(node, ELEMENT_FIELD).get(node);
- }
-
- @SneakyThrows
- private Object getLeftNode(Object node) {
- return getNodesField(node, LEFT_FIELD).get(node);
- }
-
- @SneakyThrows
- private Object getRightNode(Object node) {
- return getNodesField(node, RIGHT_FIELD).get(node);
- }
-
- @SneakyThrows
- private Object newNode(int element) {
- Object nodeInstance;
- Constructor>[] constructors = getInnerClass().getDeclaredConstructors();
- Constructor> constructor;
-
- constructor = constructors[0];
- constructor.setAccessible(true);
- if (constructor.getParameters().length == 1) {
- nodeInstance = constructor.newInstance(element);
- } else {
- nodeInstance = constructor.newInstance();
- Field nodeElement = getNodesField(nodeInstance, ELEMENT_FIELD);
- nodeElement.set(nodeInstance, element);
- }
- return nodeInstance;
- }
-
- @SneakyThrows
- private void insertElement(int element) {
-
- Object root = getRootObject();
-
- if (root == null) {
- getRootField().set(tree, newNode(element));
- } else {
- insertToSubtree(root, element);
- }
- }
-
- private boolean insertToSubtree(Object node, int element) {
- if (element < getElement(node)) {
- return insertLeft(node, element);
- } else if (element > getElement(node)) {
- return insertRight(node, element);
- } else {
- return false;
- }
- }
-
- @SneakyThrows
- private boolean insertLeft(Object node, int element) {
- if (getLeftNode(node) != null) {
- return insertToSubtree(getLeftNode(node), element);
- } else {
- getNodesField(node, LEFT_FIELD).set(node, newNode(element));
- return true;
- }
- }
-
- @SneakyThrows
- private boolean insertRight(Object node, int element) {
- if (getRightNode(node) != null) {
- return insertToSubtree(getRightNode(node), element);
- } else {
- getNodesField(node, RIGHT_FIELD).set(node, newNode(element));
- return true;
- }
- }
-
- @SneakyThrows
- private void fillTestTree(Integer... elements) {
- tree = new RecursiveBinarySearchTree<>();
- for (Integer e : elements) {
- insertElement(e);
- }
- getInnerSizeField().set(tree, elements.length);
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-9-hash-table/README.md b/2-0-data-structures-and-algorithms/2-2-9-hash-table/README.md
deleted file mode 100644
index f1bc7ca37..000000000
--- a/2-0-data-structures-and-algorithms/2-2-9-hash-table/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Hash Table
-Learn a Hash Table data structures and build strong skills creating a hash table-based implementation of a Map interface 💪
-
-### Objectives (at the end of the training you will be able to...)
-* understand the **main idea** behind the **Hash Table** data structure ✅
-* explain why do we need a `hashCode` method and how it speeds up the search ✅
-* implement key-value class `Node` ✅
-* implement a simple `HashTable` based on the array of linked `Node` objects
-* realize the limitations of the Hash Table ✅
-* understand why do we need the resizing logic and how does it work ✅
-
----
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-9-hash-table/pom.xml b/2-0-data-structures-and-algorithms/2-2-9-hash-table/pom.xml
deleted file mode 100644
index 0453cee6a..000000000
--- a/2-0-data-structures-and-algorithms/2-2-9-hash-table/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 2-0-data-structures-and-algorithms
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 2-2-9-hash-table
-
-
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/HashTable.java b/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/HashTable.java
deleted file mode 100644
index ade9cea4d..000000000
--- a/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/HashTable.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.bobocode.cs;
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-/**
- * {@link HashTable} is a simple Hashtable-based implementation of {@link Map} interface with some additional methods.
- * It is based on the array of {@link Node} objects. Both {@link HashTable} and {@link Node} have two type parameters:
- * K and V, which represent key and value.
- *
- * Elements are stored int the table by their key. A table is basically an array, and fast access is possible due to
- * array capabilities. (You can access an array element by its index in O(1) time). In order to find an index for any
- * given key, it uses calculateIndex method which is based on the element's hash code.
- *
- * If two elements (keys) have the same array index, they form a linked list. That's why class {@link Node} requires
- * a reference to the next field.
- *
- * Since you don't always know the number of elements in advance, the table can be resized. You can do that manually by
- * calling method resizeTable, or it will be done automatically once the table reach resize threshold.
- *
- * The initial array size (initial capacity) is 8.
- *
- * TODO: to get the most out of your learning, visit our website
- *
- *
- * @param key type
- * @param value type
- * @author Taras Boychuk
- */
-public class HashTable implements Map {
-
- /**
- * This method is a critical part of the hast table. The main idea is that having a key, you can calculate its index
- * in the array using the hash code. Since the computation is done in constant time (O(1)), it's faster than
- * any other kind search.
- *
- * It's a function that accepts a key and calculates its index using a hash code. Please note that index cannot be
- * equal or greater than array size (table capacity).
- *
- * This method is used for all other operations (put, get, remove).
- *
- * @param key
- * @param tableCapacity underlying array size
- * @return array index of the given key
- */
- public static int calculateIndex(Object key, int tableCapacity) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Creates a mapping between provided key and value, and returns the old value. If there was no such key, it returns
- * null. {@link HashTable} does not support duplicate keys, so if you put the same key it just overrides the value.
- *
- * It uses calculateIndex method to find the corresponding array index. Please note, that even different keys can
- * produce the same array index.
- *
- * @param key
- * @param value
- * @return old value or null
- */
- @Override
- public V put(K key, V value) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Retrieves a value by the given key. It uses calculateIndex method to find the corresponding array index.
- * Then it iterates though all elements that are stored by that index, and uses equals to compare its keys.
- *
- * @param key
- * @return value stored in the table by the given key or null if there is no such key
- */
- @Override
- public V get(K key) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Checks if the table contains a given key.
- *
- * @param key
- * @return true is there is such key in the table or false otherwise
- */
- @Override
- public boolean containsKey(K key) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Checks if the table contains a given value.
- *
- * @param value
- * @return true is there is such value in the table or false otherwise
- */
- @Override
- public boolean containsValue(V value) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Return a number of elements in the table.
- *
- * @return size
- */
- @Override
- public int size() {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Checks is the table is empty.
- *
- * @return true is table size is zero or false otherwise
- */
- @Override
- public boolean isEmpty() {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Removes an element by its key and returns a removed value. If there is no such key in the table, it returns null.
- *
- * @param key
- * @return removed value or null
- */
- @Override
- public V remove(K key) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * It's a special toString method dedicated to help you visualize a hash table. It creates a string that represents
- * an underlying array as a table. It has multiples rows. Every row starts with an array index followed by ": ".
- * Then it adds every key and value (key=value) that have a corresponding index. Every "next" reference is
- * represented as an arrow like this " -> ".
- *
- * E.g. imagine a table, where the key is a string username, and the value is the number of points of that user.
- * Is this case method toString can return something like this:
- *
- * 0: johnny=439
- * 1:
- * 2: madmax=833 -> leon=886
- * 3:
- * 4: altea=553
- * 5:
- * 6:
- * 7:
- *
- *
- * @return
- */
- @Override
- public String toString() {
- throw new ExerciseNotCompletedException(); // todo:
- }
-
- /**
- * Creates a new underlying table with a given size and adds all elements to the new table.
- *
- * In order to allow a fast access, this hash table needs to have a sufficient capacity.
- * (You can imagine a hash table, with a default capacity of 8 that stores hundreds of thousands of elements.
- * In that case it's just 8 huge linked lists. That's why we need this method.)
- *
- * PLEASE NOTE that such method should not be a part of the public API , but it was made public
- * for learning purposes. You can create a table, print it using toString, then resizeTable and print it again.
- * It will help you to understand how it works.
- *
- * @param newCapacity a size of the new underlying array
- */
- public void resizeTable(int newCapacity) {
- throw new ExerciseNotCompletedException(); // todo:
- }
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/Map.java b/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/Map.java
deleted file mode 100644
index ede146ae0..000000000
--- a/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/main/java/com/bobocode/cs/Map.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.bobocode.cs;
-
-/**
- * A {@link Map} is a simplified interface of so-called dictionary. It maps keys to values and provides an API for data
- * access and manipulation. Please note that a map does not support duplicate keys.
- *
- * It was added as a simple contact on top of a {@link HashTable} class.
- *
- * @param key type
- * @param value type
- * @author Taras Boychuk
- */
-public interface Map {
- /**
- * Creates or updates a mapping for a given key and value. If the key is new, it creates a mapping and return null.
- * If the key exists, it updates the value and returns the old value.
- *
- * @param key
- * @param value
- * @return an old value or null
- */
- V put(K key, V value);
-
- /**
- * Returns the value that is mapped to the given key, or null if there is no such key.
- *
- * @param key
- * @return the value that is mapped to the given key, or null if there is no such key
- */
- V get(K key);
-
- /**
- * Returns true if a given key exist or false otherwise.
- *
- * @param key
- * @return true if a given key exist or false otherwise
- */
- boolean containsKey(K key);
-
- /**
- * Returns true if a given value exist or false otherwise.
- *
- * @param value
- * @return true if a given value exist or false otherwise
- */
- boolean containsValue(V value);
-
- /**
- * Returns the number of entries (key-value mappings).
- *
- * @return the number of entries
- */
- int size();
-
- /**
- * Returns true if there is no entries or false otherwise.
- *
- * @return true if there is no entries or false otherwise
- */
- boolean isEmpty();
-
- /**
- * Removes a mapping for a given key, and returns a removed value. If there is no such key, it just returns null.
- *
- * @param key
- * @return a removed value or null
- */
- V remove(K key);
-}
diff --git a/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/test/java/com/bobocode/cs/HashTableTest.java b/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/test/java/com/bobocode/cs/HashTableTest.java
deleted file mode 100644
index b7355496c..000000000
--- a/2-0-data-structures-and-algorithms/2-2-9-hash-table/src/test/java/com/bobocode/cs/HashTableTest.java
+++ /dev/null
@@ -1,677 +0,0 @@
-package com.bobocode.cs;
-
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.ClassOrderer.OrderAnnotation;
-import org.junit.jupiter.api.*;
-
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static java.lang.reflect.Modifier.isStatic;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.jupiter.api.Assertions.*;
-
-/**
- * A Reflection-based step by step test for a {@link HashTable} class. PLEASE NOTE that Reflection API should not be used
- * for testing a production code. We use it for learning purposes only!
- *
- * @author Taras Boychuk
- */
-@TestClassOrder(OrderAnnotation.class)
-@DisplayName("HashTable Test")
-class HashTableTest {
-
- private HashTable hashTable = new HashTable<>();
-
- @Nested
- @Order(1)
- @DisplayName("1. Node Test")
- @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
- class NodeClassTest {
-
- @Test
- @Order(1)
- @DisplayName("A nested class Node exists")
- void nodeClassExists() {
- var nestedClassList = Arrays.stream(HashTable.class.getDeclaredClasses())
- .map(Class::getSimpleName)
- .toList();
-
- assertThat(nestedClassList).contains("Node");
- }
-
- @Test
- @Order(2)
- @DisplayName("Node is a static nested class")
- @SneakyThrows
- void nodeIsStaticClass() {
- var nodeClass = Class.forName("com.bobocode.cs.HashTable$Node");
-
- assertTrue(isStatic(nodeClass.getModifiers()));
- }
-
- @Test
- @Order(3)
- @DisplayName("Node class has two type parameters")
- @SneakyThrows
- void nodeHasTwoTypeParams() {
- var nodeClass = Class.forName("com.bobocode.cs.HashTable$Node");
- var typeParametersList = nodeClass.getTypeParameters();
-
- assertThat(typeParametersList).hasSize(2);
- }
-
- @Test
- @Order(4)
- @DisplayName("Node class has 'key' and 'value' fields")
- @SneakyThrows
- void nodeHasKeyValuesFields() {
- var nodeClass = Class.forName("com.bobocode.cs.HashTable$Node");
- var fieldNames = Arrays.stream(nodeClass.getDeclaredFields())
- .map(Field::getName)
- .toList();
-
- assertThat(fieldNames).contains("key").contains("value");
- }
-
- @Test
- @Order(5)
- @DisplayName("Node class has a field 'next'")
- @SneakyThrows
- void nodeHasReferenceToNext() {
- var nodeClass = Class.forName("com.bobocode.cs.HashTable$Node");
- var fieldNames = Arrays.stream(nodeClass.getDeclaredFields())
- .map(Field::getName)
- .toList();
-
- assertThat(fieldNames).contains("next");
- }
-
- @Test
- @Order(6)
- @DisplayName("Node class has one constructor")
- @SneakyThrows
- void nodeHasOneConstructor() {
- var nodeClass = Class.forName("com.bobocode.cs.HashTable$Node");
-
- var constructors = nodeClass.getDeclaredConstructors();
-
- assertThat(constructors).hasSize(1);
- }
-
- @Test
- @Order(7)
- @DisplayName("Node constructor accept key and value")
- @SneakyThrows
- void nodeConstructorAcceptKeyValue() {
- var nodeClass = Class.forName("com.bobocode.cs.HashTable$Node");
-
- var constructor = nodeClass.getDeclaredConstructors()[0];
-
- assertThat(constructor.getParameters()).hasSize(2);
- assertThat(constructor.getParameters()[0].getName()).isEqualTo("key");
- assertThat(constructor.getParameters()[1].getName()).isEqualTo("value");
- }
- }
-
- @Nested
- @Order(2)
- @DisplayName("2. HashTable fields Test")
- @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
- class HashTableFieldsTest {
-
- @Test
- @Order(1)
- @DisplayName("HastTable has a field 'table' which is an array of nodes")
- @SneakyThrows
- void tableFieldExists() {
- var tableField = HashTable.class.getDeclaredField("table");
- var tableType = tableField.getType();
- var nodeClass = Class.forName("com.bobocode.cs.HashTable$Node");
-
- assertTrue(tableType.isArray());
- assertThat(tableType.getComponentType()).isEqualTo(nodeClass);
- }
-
- @Test
- @Order(2)
- @DisplayName("HashTable has an integer field 'size'")
- @SneakyThrows
- void sizeFieldExists() {
- var sizeField = HashTable.class.getDeclaredField("size");
-
- assertThat(sizeField.getType()).isEqualTo(int.class);
- }
- }
-
- @Nested
- @Order(3)
- @DisplayName("3. HashTable constructors Test")
- @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
- class HashTableConstructorsTest {
-
- @Test
- @Order(1)
- @SneakyThrows
- @DisplayName("A default constructor initializes an array with default size 8")
- void defaultConstructor() {
- var defaultConstructor = HashTable.class.getConstructor();
-
- var hashTable = defaultConstructor.newInstance();
- var table = getInternalTable(hashTable);
-
- assertThat(table).hasSize(8);
- }
-
- @Test
- @Order(2)
- @SneakyThrows
- @DisplayName("An additional constructor accepts an initial array size")
- void constructorWithTableCapacity() {
- var constructor = HashTable.class.getConstructor(int.class);
-
- var hashTable = constructor.newInstance(16);
- var table = getInternalTable(hashTable);
-
- assertThat(table).hasSize(16);
- }
-
- @Test
- @Order(3)
- @SneakyThrows
- @DisplayName("An additional constructor throws exception when argument is negative")
- void constructorWithTableCapacityWhenArgumentIsNegative() {
- var constructor = HashTable.class.getConstructor(int.class);
-
- assertThatThrownBy(() -> constructor.newInstance(-2))
- .hasCauseInstanceOf(IllegalArgumentException.class);
- }
- }
-
- @Nested
- @Order(4)
- @DisplayName("4. Hash Function Test")
- @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
- class HashFunctionTest {
-
- @Test
- @Order(1)
- @DisplayName("calculateIndex returns the same value for the same key")
- void calculateIndexReturnTheSameValueWhenKeyIsTheSame() {
- var indexSet = Stream.generate(() -> "ASDFDFSD34234234")
- .limit(10)
- .map(key -> HashTable.calculateIndex(key, 8))
- .collect(Collectors.toSet());
-
- assertThat(indexSet).hasSize(1);
- }
-
- @Test
- @Order(2)
- @DisplayName("calculateIndex returns different values for different keys")
- void calculateIndexReturnDifferentValuesWheKeysAreDifferent() {
- var arrayCapacity = 8;
- var indexSet = Stream.of("A", "Aa", "AaB", "4234", "2234fasdf", "ASDFDFSD34234234", "afsd-fdfd-ae43-5gd3")
- .map(str -> HashTable.calculateIndex(str, arrayCapacity))
- .collect(Collectors.toSet());
-
- assertThat(indexSet)
- .hasSizeGreaterThan(1);
- }
-
- @Test
- @Order(3)
- @DisplayName("calculateIndex returns values in array bounds")
- void calculateIndexReturnIndexInArrayBounds() {
- var arrayCapacity = 8;
- var keys = Stream.generate(() -> ThreadLocalRandom.current().nextLong())
- .limit(100)
- .toList();
-
- var indexes = keys.stream()
- .map(key -> HashTable.calculateIndex(key, arrayCapacity))
- .toList();
-
- assertThat(indexes)
- .isNotEmpty()
- .allMatch(i -> i >= 0 && i < arrayCapacity);
- }
-
- @Test
- @Order(4)
- @DisplayName("calculateIndex return non-negative value when hashCode is negative")
- void calculateIndexReturnPositiveIndexWhenHashCodeIsNegative() {
- var key = Long.MAX_VALUE;
-
- var index = HashTable.calculateIndex(key, 8);
-
- assertThat(index).isNotNegative();
- }
- }
-
- @Nested
- @Order(5)
- @DisplayName("5. HashTable methods Test")
- @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
- class HashTableMethodsTest {
-
- @Test
- @SneakyThrows
- @Order(1)
- @DisplayName("put creates new entry and returns null when the table is empty, should increase the table size")
- void putWhenTableIsEmpty() {
- var previousValue = hashTable.put("madmax", 833);
-
- var keyValueExists = checkKeyValueExists("madmax", 833);
-
- assertNull(previousValue);
- assertTrue(keyValueExists);
- assertEquals(1, getSize());
- }
-
- @Test
- @Order(2)
- @DisplayName("put elements adds entry to the same bucket and increases table size when the hash code is the same")
- @SneakyThrows
- void putTwoElementsWithTheSameHashCode() {
- var table = getInternalTable(hashTable);
- var prevValueA = hashTable.put("AaAa", 123);
- var prevValueB = hashTable.put("BBBB", 456);
- var containsKeyValueA = checkKeyValueExists("AaAa", 123);
- var containsKeyValueB = checkKeyValueExists("BBBB", 456);
- var bucketIndexA = HashTable.calculateIndex("AaAa", table.length);
- var bucketIndexB = HashTable.calculateIndex("BBBB", table.length);
-
- assertNull(prevValueA);
- assertNull(prevValueB);
- assertTrue(containsKeyValueA);
- assertTrue(containsKeyValueB);
- assertThat(bucketIndexA).isEqualTo(bucketIndexB);
- assertEquals(2, getSize());
- }
-
- @Test
- @Order(3)
- @DisplayName(
- "put element updates the value and returns the previous one when key is the same, should not increase table size")
- void putElementWithTheSameKey() {
- hashTable.put("madmax", 833);
-
- var previousValue = hashTable.put("madmax", 876);
- var containsNewValueByKey = checkKeyValueExists("madmax", 876);
-
- assertThat(previousValue).isEqualTo(833);
- assertTrue(containsNewValueByKey);
- assertEquals(1, getSize());
- }
-
- @Test
- @Order(4)
- @DisplayName("get returns null when given key does not exists")
- void getElementWhenKeyDoesNotExists() {
- var foundValue = hashTable.get("xxx");
-
- assertNull(foundValue);
- }
-
- @Test
- @Order(5)
- @DisplayName("get returns a corresponding value by the given key")
- void getWhenKeyExists() {
- addToTable("madmax", 833);
-
- var foundValue = hashTable.get("madmax");
-
- assertThat(foundValue).isEqualTo(833);
- }
-
- @Test
- @Order(6)
- @DisplayName("get returns a corresponding value when there are other keys with the same index")
- void getWhenOtherKeyHaveTheSameIndex() {
- addToTable("madmax", 833);
- addToTable("AaAa", 654);
- addToTable("BBBB", 721);
-
- var foundValue = hashTable.get("BBBB");
-
- assertThat(foundValue).isEqualTo(721);
- }
-
- @Test
- @Order(7)
- @DisplayName("containsKey returns true if element exists")
- void containsKeyWhenElementExists() {
- addToTable("madmax", 833);
-
- var result = hashTable.containsKey("madmax");
-
- assertThat(result).isTrue();
- }
-
- @Test
- @Order(8)
- @DisplayName("containsKey returns false if element does not exist")
- void containsKeyWhenElementDoesNotExist() {
- var result = hashTable.containsKey("madmax");
-
- assertThat(result).isFalse();
- }
-
- @Test
- @Order(9)
- @DisplayName("containsValue returns true if value exists")
- void containsValue() {
- addToTable("madmax", 833);
-
- var result = hashTable.containsValue(833);
-
- assertThat(result).isTrue();
- }
-
- @Test
- @Order(9)
- @DisplayName("containsValue returns false if value does not exist")
- void containsValueWhenItDoesNotExist() {
- addToTable("madmax", 833);
-
- var result = hashTable.containsValue(666);
-
- assertThat(result).isFalse();
- }
-
- @Test
- @Order(10)
- @DisplayName("containsValue returns true if the same value appears multiple times")
- void containsValueWhenValueAppearsMultipleTimes() {
- addToTable("madmax", 833);
- addToTable("bobby", 833);
- addToTable("altea", 833);
-
- var result = hashTable.containsValue(833);
-
- assertThat(result).isTrue();
- }
-
- @Test
- @Order(11)
- @SneakyThrows
- @DisplayName("size returns the number of entries in the table")
- void size() {
- setSize(12);
-
- var size = hashTable.size();
-
- assertThat(size).isEqualTo(12);
- }
-
- @Test
- @Order(12)
- @DisplayName("isEmpty returns false when there are some elements")
- void isEmptyWhenTableGetsElements() {
- addToTable("madmax", 833);
- setSize(1);
-
- var empty = hashTable.isEmpty();
-
- assertFalse(empty);
- }
-
- @Test
- @Order(13)
- @DisplayName("isEmpty returns true when there is no elements")
- void isEmptyWhenThereIsNoElements() {
- var empty = hashTable.isEmpty();
-
- assertTrue(empty);
- }
-
- @Test
- @Order(13)
- @DisplayName("remove deletes the entry, decreases table size and returns a value")
- void remove() {
- addToTable("madmax", 833);
- setSize(1);
- var result = hashTable.remove("madmax");
-
- assertThat(result).isEqualTo(833);
- assertFalse(checkKeyValueExists("madmaxx", 833));
- assertEquals(0, getSize());
- }
-
- @Test
- @Order(14)
- @DisplayName("remove returns null when key does not exists")
- void removeWhenKeyDoesNotExists() {
- var result = hashTable.remove("madmax");
-
- assertNull(result);
- }
-
- @Test
- @Order(15)
- @DisplayName("remove deletes the element when it's in the middle of the list and decreases the size of table")
- void removeFromTheMiddleOfTheList() {
- addToTable("AaAa", 843);
- addToTable("BBBB", 434);
- addToTable("AaBB", 587);
-
- var size = 3;
- setSize(size);
- var removedValue = hashTable.remove("BBBB");
-
- assertTrue(checkKeyValueExists("AaAa", 843));
- assertFalse(checkKeyExists("BBBB"));
- assertTrue(checkKeyValueExists("AaBB", 587));
- assertThat(removedValue).isEqualTo(434);
- assertEquals(size - 1, getSize());
- }
-
- @Test
- @Order(16)
- @DisplayName("remove deletes the element when it's in the end of the list and decreases the size of table")
- void removeFromTheEndOfTheList() {
- addToTable("AaAa", 843);
- addToTable("BBBB", 434);
- addToTable("AaBB", 587);
- var size = 3;
- setSize(size);
-
- var removedValue = hashTable.remove("AaBB");
-
- assertTrue(checkKeyValueExists("AaAa", 843));
- assertTrue(checkKeyValueExists("BBBB", 434));
- assertFalse(checkKeyExists("AaBB"));
- assertThat(removedValue).isEqualTo(587);
- assertEquals(2, getSize());
- }
- }
-
- @Nested
- @Order(6)
- @DisplayName("6. Helper methods Test")
- @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
- class HashTableHelperMethodsTest {
-
- @Test
- @Order(1)
- @DisplayName("resizeTable creates a new array and put there all elements")
- void resizeTable() {
- addToTable("madmax", 833);
- addToTable("altea", 553);
- addToTable("AaAa", 123);
- addToTable("BBBB", 456);
-
- hashTable.resizeTable(16);
-
- assertThat(getInternalTable(hashTable)).hasSize(16);
- assertTrue(checkKeyValueExists("madmax", 833));
- assertTrue(checkKeyValueExists("altea", 553));
- assertTrue(checkKeyValueExists("AaAa", 123));
- assertTrue(checkKeyValueExists("BBBB", 456));
- }
-
- @Test
- @DisplayName("toString returns a string that represents an underlying table")
- void toStringTest() {
- addToTable("madmax", 833);
- addToTable("altea", 553);
- addToTable("johnny", 439);
- addToTable("leon", 886);
- var table = getInternalTable(hashTable);
- var expectedString = tableToString(table);
-
- String tableStr = hashTable.toString();
-
- assertThat(tableStr).isEqualTo(expectedString);
- }
-
- }
-
- // Util methods
- @SneakyThrows
- private Object[] getInternalTable(HashTable, ?> hashTable) {
- var tableField = HashTable.class.getDeclaredField("table");
- tableField.setAccessible(true);
- return (Object[]) tableField.get(hashTable);
- }
-
- private void addToTable(String key, Integer value) {
- var table = getInternalTable(hashTable);
- var index = HashTable.calculateIndex(key, table.length);
- var newNode = createNewNode(key, value);
- if (table[index] == null) {
- table[index] = newNode;
- } else {
- var current = new NodeProxy(table[index]);
- while (current.next() != null && !current.key().equals(key)) {
- current = current.next();
- }
- if (current.key().equals(key)) {
- current.setValue(value);
- } else {
- current.setNext(newNode);
- }
- }
- }
-
- private NodeProxy getNodeByKey(Object key) {
- var table = getInternalTable(hashTable);
- for (var head : table) {
- if (head != null) {
- var current = new NodeProxy(head);
- while (current != null) {
- if (current.key().equals(key)) {
- return current;
- }
- current = current.next();
- }
- }
- }
- return null;
- }
-
- private boolean checkKeyValueExists(Object key, Object value) {
- var node = getNodeByKey(key);
- return node != null && node.value().equals(value);
- }
-
- private boolean checkKeyExists(Object key) {
- var node = getNodeByKey(key);
- return node != null;
- }
-
- @SneakyThrows
- private void setSize(int size) {
- var sizeField = HashTable.class.getDeclaredField("size");
- sizeField.setAccessible(true);
- sizeField.set(hashTable, size);
- }
-
- @SneakyThrows
- private int getSize() {
- var sizeField = HashTable.class.getDeclaredField("size");
- sizeField.setAccessible(true);
- return sizeField.getInt(hashTable);
- }
-
- private String tableToString(Object[] table) {
- StringBuilder result = new StringBuilder();
- var n = table.length;
- for (int i = 0; i < n; i++) {
- result.append(i).append(": ");
- if (table[i] != null) {
- var current = new NodeProxy(table[i]);
- while (current.next() != null) {
- result.append(current.key()).append("=").append(current.value()).append(" -> ");
- current = current.next();
- }
- result.append(current.key()).append("=").append(current.value());
- }
- result.append("\n");
- }
- return result.toString();
- }
-
- @SneakyThrows
- private Object createNewNode(String key, Integer value) {
- var nodeClass = Class.forName("com.bobocode.cs.HashTable$Node");
- var constructor = nodeClass.getConstructor(Object.class, Object.class);
- return constructor.newInstance(key, value);
- }
-
- static class NodeProxy {
-
- Class> targetClass;
- Field keyField;
- Field valueField;
- Field nextField;
- Object target;
-
- @SneakyThrows
- public NodeProxy(Object target) {
- Objects.requireNonNull(target);
- this.targetClass = Class.forName("com.bobocode.cs.HashTable$Node");
- this.target = target;
- this.keyField = targetClass.getDeclaredField("key");
- this.keyField.setAccessible(true);
- this.valueField = targetClass.getDeclaredField("value");
- this.valueField.setAccessible(true);
- this.nextField = targetClass.getDeclaredField("next");
- this.nextField.setAccessible(true);
- }
-
- @SneakyThrows
- public Object key() {
- return keyField.get(target);
- }
-
- @SneakyThrows
- public Object value() {
- return valueField.get(target);
- }
-
- @SneakyThrows
- public NodeProxy next() {
- return Optional.ofNullable(nextField.get(target))
- .map(NodeProxy::new)
- .orElse(null);
- }
-
- @SneakyThrows
- public void setValue(Object value) {
- valueField.set(target, value);
- }
-
- @SneakyThrows
- public void setNext(Object newNode) {
- nextField.set(target, newNode);
- }
- }
-}
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/README.md b/2-0-data-structures-and-algorithms/README.md
deleted file mode 100644
index f00ce989c..000000000
--- a/2-0-data-structures-and-algorithms/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# Data Structures & Angorithms
-Learn Data Structures & Algorithms and build strong related skills needed for enterprise Java development 💪
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/data-structures-and-algorithms-util/pom.xml b/2-0-data-structures-and-algorithms/data-structures-and-algorithms-util/pom.xml
deleted file mode 100644
index 87de65e23..000000000
--- a/2-0-data-structures-and-algorithms/data-structures-and-algorithms-util/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 2-0-data-structures-and-algorithms
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- data-structures-and-algorithms-util
-
-
-
\ No newline at end of file
diff --git a/2-0-data-structures-and-algorithms/data-structures-and-algorithms-util/src/main/java/com/bobocode/cs/List.java b/2-0-data-structures-and-algorithms/data-structures-and-algorithms-util/src/main/java/com/bobocode/cs/List.java
deleted file mode 100644
index dfa0a7cd8..000000000
--- a/2-0-data-structures-and-algorithms/data-structures-and-algorithms-util/src/main/java/com/bobocode/cs/List.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.bobocode.cs;
-
-
-public interface List {
- void add(T element);
-
- void add(int index, T element);
-
- void set(int index, T element);
-
- T get(int index);
-
- T getFirst();
-
- T getLast();
-
- T remove(int index);
-
- boolean contains(T element);
-
- boolean isEmpty();
-
- int size();
-
- void clear();
-}
diff --git a/2-0-data-structures-and-algorithms/pom.xml b/2-0-data-structures-and-algorithms/pom.xml
deleted file mode 100644
index a08d31d22..000000000
--- a/2-0-data-structures-and-algorithms/pom.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
- 4.0.0
- pom
-
- 2-2-1-node
- 2-2-2-stack
- 2-2-3-linked-queue
- 2-2-4-linked-list
- 2-2-5-array-list
- 2-2-6-binary-search-tree
- 2-2-9-hash-table
- data-structures-and-algorithms-util
-
-
-
- com.bobocode
- java-fundamentals-exercises
- 1.0-SNAPSHOT
-
- 2-0-data-structures-and-algorithms
-
-
-
-
- com.bobocode
- java-fundamentals-util
- 1.0-SNAPSHOT
- compile
-
-
-
-
\ No newline at end of file
diff --git a/3-0-java-core/3-6-1-file-reader/README.MD b/3-0-java-core/3-6-1-file-reader/README.MD
deleted file mode 100644
index 5d6989629..000000000
--- a/3-0-java-core/3-6-1-file-reader/README.MD
+++ /dev/null
@@ -1,17 +0,0 @@
-# File Reader
-Improve your Java SE skills by implementing a logic that reads file content using Stream API 💪
-
-### Pre-conditions ❗
-You're supposed to know the basics of Stream API and how to work with files in Java
-
-### Objectives
-* **find a text file** in the classpath ✅
-* **open a** `Stream` of file lines ✅
-* **collect** file content into a single `String` ✅
-* **deal with exceptions** when accessing the file ✅
-
----
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/3-0-java-core/3-6-1-file-reader/pom.xml b/3-0-java-core/3-6-1-file-reader/pom.xml
deleted file mode 100644
index 67b2f5f5b..000000000
--- a/3-0-java-core/3-6-1-file-reader/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 3-0-java-core
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 3-6-1-file-reader
-
-
-
\ No newline at end of file
diff --git a/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaders.java b/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaders.java
deleted file mode 100644
index 6370a3638..000000000
--- a/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaders.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.bobocode.se;
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-/**
- * {@link FileReaders} provides an API that allow to read whole file into a {@link String} by file name.
- */
-public class FileReaders {
-
- /**
- * Returns a {@link String} that contains whole text from the file specified by name.
- *
- * @param fileName a name of a text file
- * @return string that holds whole file content
- */
- public static String readWholeFile(String fileName) {
- throw new ExerciseNotCompletedException(); //todo
- }
-}
diff --git a/3-0-java-core/3-6-1-file-reader/src/test/java/com/bobocode/se/FileReadersTest.java b/3-0-java-core/3-6-1-file-reader/src/test/java/com/bobocode/se/FileReadersTest.java
deleted file mode 100644
index 1c24b9d2d..000000000
--- a/3-0-java-core/3-6-1-file-reader/src/test/java/com/bobocode/se/FileReadersTest.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.bobocode.se;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-public class FileReadersTest {
-
- @Test
- void testReadWholeFileOnEmptyFile() {
- String fileContent = FileReaders.readWholeFile("empty.txt");
-
- assertEquals("", fileContent);
-
- }
-
- @Test
- void testReadWholeFileOnFileWithEmptyLines() {
- String fileContent = FileReaders.readWholeFile("lines.txt");
-
- assertEquals("Hey!\n" +
- "\n" +
- "What's up?\n" +
- "\n" +
- "Hi!", fileContent);
- }
-
- @Test
- void testReadWholeFile() {
- String fileContent = FileReaders.readWholeFile("simple.txt");
-
- assertEquals("Hello!\n" + "It's a test file.", fileContent);
- }
-}
diff --git a/3-0-java-core/3-6-1-file-reader/src/test/resources/empty.txt b/3-0-java-core/3-6-1-file-reader/src/test/resources/empty.txt
deleted file mode 100644
index e69de29bb..000000000
diff --git a/3-0-java-core/3-6-1-file-reader/src/test/resources/lines.txt b/3-0-java-core/3-6-1-file-reader/src/test/resources/lines.txt
deleted file mode 100644
index 7c294a97f..000000000
--- a/3-0-java-core/3-6-1-file-reader/src/test/resources/lines.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Hey!
-
-What's up?
-
-Hi!
\ No newline at end of file
diff --git a/3-0-java-core/3-6-1-file-reader/src/test/resources/simple.txt b/3-0-java-core/3-6-1-file-reader/src/test/resources/simple.txt
deleted file mode 100644
index ac906f0b9..000000000
--- a/3-0-java-core/3-6-1-file-reader/src/test/resources/simple.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Hello!
-It's a test file.
\ No newline at end of file
diff --git a/3-0-java-core/3-6-2-file-stats/README.MD b/3-0-java-core/3-6-2-file-stats/README.MD
deleted file mode 100644
index 4cfa45009..000000000
--- a/3-0-java-core/3-6-2-file-stats/README.MD
+++ /dev/null
@@ -1,20 +0,0 @@
-# Files Stats
-Improve your Stream API skills calculating character statistic using a text file 💪
-
-### Pre-conditions ❗
-You're supposed to know how to work with text files and be able to write Java code
-
-### Objectives
-
-* **find a text file** in the classpath ✅
-* **open a** `Stream` of file lines ✅
-* **transform** a stream of lines into a stream of characters
-* **group** characters by value and calculate needed stats ✅
-* **deal with exceptions** when accessing the file ✅
-
----
-
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/3-0-java-core/3-6-2-file-stats/pom.xml b/3-0-java-core/3-6-2-file-stats/pom.xml
deleted file mode 100644
index 448ac3179..000000000
--- a/3-0-java-core/3-6-2-file-stats/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 3-0-java-core
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 3-6-2-file-stats
-
-
-
\ No newline at end of file
diff --git a/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStats.java b/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStats.java
deleted file mode 100644
index 56b4aa596..000000000
--- a/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStats.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.bobocode.se;
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-/**
- * {@link FileStats} provides an API that allow to get character statistic based on text file. All whitespace characters
- * are ignored.
- */
-public class FileStats {
- /**
- * Creates a new immutable {@link FileStats} objects using data from text file received as a parameter.
- *
- * @param fileName input text file name
- * @return new FileStats object created from text file
- */
- public static FileStats from(String fileName) {
- throw new ExerciseNotCompletedException(); //todo
- }
-
- /**
- * Returns a number of occurrences of the particular character.
- *
- * @param character a specific character
- * @return a number that shows how many times this character appeared in a text file
- */
- public int getCharCount(char character) {
- throw new ExerciseNotCompletedException(); //todo
- }
-
- /**
- * Returns a character that appeared most often in the text.
- *
- * @return the most frequently appeared character
- */
- public char getMostPopularCharacter() {
- throw new ExerciseNotCompletedException(); //todo
- }
-
- /**
- * Returns {@code true} if this character has appeared in the text, and {@code false} otherwise
- *
- * @param character a specific character to check
- * @return {@code true} if this character has appeared in the text, and {@code false} otherwise
- */
- public boolean containsCharacter(char character) {
- throw new ExerciseNotCompletedException(); //todo
- }
-}
diff --git a/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStatsException.java b/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStatsException.java
deleted file mode 100644
index d2f03c253..000000000
--- a/3-0-java-core/3-6-2-file-stats/src/main/java/com/bobocode/se/FileStatsException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.bobocode.se;
-
-public class FileStatsException extends RuntimeException{
- public FileStatsException(String message) {
- super(message);
- }
-
- public FileStatsException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git a/3-0-java-core/3-6-2-file-stats/src/test/java/com/bobocode/se/FileStatsTest.java b/3-0-java-core/3-6-2-file-stats/src/test/java/com/bobocode/se/FileStatsTest.java
deleted file mode 100644
index b1eb222af..000000000
--- a/3-0-java-core/3-6-2-file-stats/src/test/java/com/bobocode/se/FileStatsTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.bobocode.se;
-
-import org.junit.jupiter.api.MethodOrderer;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
-
-import static org.assertj.core.api.Assertions.*;
-
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-public class FileStatsTest {
-
- @Test
- @Order(1)
- void createFileStatsFromExistingFile() {
- FileStats fileStats = FileStats.from("sotl.txt");
- }
-
- @Test
- @Order(2)
- void createFileStatsFromNonExistingFile() {
- assertThatThrownBy(() -> FileStats.from("blahblah.txt")).isInstanceOf(FileStatsException.class);
- }
-
- @Test
- @Order(3)
- void getCharCount() {
- FileStats lambdaArticleFileStats = FileStats.from("sotl.txt");
- FileStats springCloudArticleFileStats = FileStats.from("scosb.txt");
-
- int aCharCountInLambdaArticle = lambdaArticleFileStats.getCharCount('a');
- int bCharCountInSpringArticle = springCloudArticleFileStats.getCharCount('b');
-
- assertThat(aCharCountInLambdaArticle).isEqualTo(2345);
- assertThat(bCharCountInSpringArticle).isEqualTo(4);
- }
-
- @Test
- @Order(4)
- void getMostPopularCharacter() {
- FileStats lambdaArticleFileStats = FileStats.from("sotl.txt");
- FileStats springCloudArticleFileStats = FileStats.from("scosb.txt");
-
- char mostPopularCharacterInLambdaArticle = lambdaArticleFileStats.getMostPopularCharacter();
- char mostPopularCharacterInSpringArticle = springCloudArticleFileStats.getMostPopularCharacter();
-
- System.out.println(mostPopularCharacterInSpringArticle);
-
- assertThat(mostPopularCharacterInLambdaArticle).isEqualTo('e');
- assertThat(mostPopularCharacterInSpringArticle).isEqualTo('e');
- }
-
- @Test
- @Order(5)
- void containsCharacter() {
- FileStats lambdaArticleFileStats = FileStats.from("sotl.txt");
- FileStats springCloudArticleFileStats = FileStats.from("scosb.txt");
-
- boolean lambdaArticleContainsExistingCharacter = lambdaArticleFileStats.containsCharacter('a');
- boolean lambdaArticleContainsWhitespace = lambdaArticleFileStats.containsCharacter(' ');
- boolean springArticleContainsExistingCharacter = springCloudArticleFileStats.containsCharacter('b');
- boolean springArticleContainsWhitespace = springCloudArticleFileStats.containsCharacter(' ');
-
- assertThat(lambdaArticleContainsExistingCharacter).isTrue();
- assertThat(lambdaArticleContainsWhitespace).isFalse();
- assertThat(springArticleContainsExistingCharacter).isTrue();
- assertThat(springArticleContainsWhitespace).isFalse();
- }
-}
\ No newline at end of file
diff --git a/3-0-java-core/3-6-2-file-stats/src/test/resources/scosb.txt b/3-0-java-core/3-6-2-file-stats/src/test/resources/scosb.txt
deleted file mode 100644
index 44e38c020..000000000
--- a/3-0-java-core/3-6-2-file-stats/src/test/resources/scosb.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-We’re pleased to announce that the 2.0.1 release of Spring Cloud Open Service Broker is now available. This release resolves a few issues that were raised since the 2.0.0 release. Thank you to the community for your interest and feedback!
-
-Spring Cloud Open Service Broker is a framework for building Spring Boot applications that implement the Open Service Broker API. The Open Service Broker API project allows developers to deliver services to applications running within cloud native platforms such as Cloud Foundry, Kubernetes, and OpenShift.
\ No newline at end of file
diff --git a/3-0-java-core/3-6-2-file-stats/src/test/resources/sotl.txt b/3-0-java-core/3-6-2-file-stats/src/test/resources/sotl.txt
deleted file mode 100644
index c00c796f2..000000000
--- a/3-0-java-core/3-6-2-file-stats/src/test/resources/sotl.txt
+++ /dev/null
@@ -1,411 +0,0 @@
-State of the Lambda
-September 2013
-Java SE 8 Edition
-This is an informal overview of the enhancements to the Java programming language specified by JSR 335 and implemented in the OpenJDK Lambda Project. It refines the previous iteration posted in December 2011. A formal description of some of the language changes may be found in the Early Draft Specification for the JSR; an OpenJDK Developer Preview is also available. Additional historical design documents can be found at the OpenJDK project page. There is also a companion document, State of the Lambda, Libraries Edition, describing the library enhancements added as part of JSR 335.
-
-The high-level goal of Project Lambda is to enable programming patterns that require modeling code as data to be convenient and idiomatic in Java. The principal new language features include:
-
-Lambda expressions (informally, "closures" or "anonymous methods")
-Method and constructor references
-Expanded target typing and type inference
-Default and static methods in interfaces
-These are described and illustrated below.
-
-1. Background
-Java is, primarily, an object-oriented programming language. In both object-oriented and functional languages, basic values can dynamically encapsulate program behavior: object-oriented languages have objects with methods, and functional languages have functions. This similarity may not be obvious, however, because Java objects tend to be relatively heavyweight: instantiations of separately-declared classes wrapping a handful of fields and many methods.
-
-Yet it is common for some objects to essentially encode nothing more than a function. In a typical use case, a Java API defines an interface, sometimes described as a "callback interface," expecting the user to provide an instance of the interface when invoking the API. For example:
-
-public interface ActionListener {
- void actionPerformed(ActionEvent e);
-}
-Rather than declaring a class that implements ActionListener for the sole purpose of allocating it once at an invocation site, a user typically instantiates the implementing class inline, anonymously:
-
-button.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- ui.dazzle(e.getModifiers());
- }
-});
-Many useful libraries rely on this pattern. It is particularly important for parallel APIs, in which the code to execute must be expressed independently of the thread in which it will run. The parallel-programming domain is of special interest, because as Moore's Law continues to give us more cores but not faster cores, serial APIs are limited to a shrinking fraction of available processing power.
-
-Given the increasing relevance of callbacks and other functional-style idioms, it is important that modeling code as data in Java be as lightweight as possible. In this respect, anonymous inner classes are imperfect for a number of reasons, primarily:
-
-Bulky syntax
-Confusion surrounding the meaning of names and this
-Inflexible class-loading and instance-creation semantics
-Inability to capture non-final local variables
-Inability to abstract over control flow
-This project addresses many of these issues. It eliminates (1) and (2) by introducing new, much more concise expression forms with local scoping rules, sidesteps (3) by defining the semantics of the new expressions in a more flexible, optimization-friendly manner, and ameliorates (4) by allowing the compiler to infer finality (allowing capture of effectively final local variables).
-
-However, it is not a goal of this project to address all the problems of inner classes. Neither arbitrary capture of mutable variables (4) nor nonlocal control flow (5) are within this project's scope (though such features may be revisited in a future iteration of the language.)
-
-2. Functional interfaces
-The anonymous inner class approach, despite its limitations, has the nice property of fitting very cleanly into Java's type system: a function value with an interface type. This is convenient for a number of reasons: interfaces are already an intrinsic part of the type system; they naturally have a runtime representation; and they carry with them informal contracts expressed by Javadoc comments, such as an assertion that an operation is commutative.
-
-The interface ActionListener, used above, has just one method. Many common callback interfaces have this property, such as Runnable and Comparator. We'll give all interfaces that have just one method a name: functional interfaces. (These were previously called SAM Types, which stood for "Single Abstract Method".)
-
-Nothing special needs to be done to declare an interface as functional; the compiler identifies it as such based on its structure. (This identification process is a little more than just counting method declarations; an interface might redundantly declare a method that is automatically provided by the class Object, such as toString(), or might declare static or default methods, none of which count against the one-method limit.) However, API authors may additionally capture the design intent that an interface be functional (as opposed to accidentally having only one method) with the @FunctionalInterface annotation, in which case the compiler will validate that the interface meets the structural requirements to be a functional interface.
-
-An alternative (or complementary) approach to function types, suggested by some early proposals, would have been to introduce a new, structural function type, sometimes called arrow types. A type like "function from a String and an Object to an int" might be expressed as (String,Object)->int. This idea was considered and rejected, at least for now, due to several disadvantages:
-
-It would add complexity to the type system and further mix structural and nominal types (Java is almost entirely nominally typed).
-It would lead to a divergence of library styles -- some libraries would continue to use callback interfaces, while others would use structural function types.
-The syntax could be unwieldy, especially when checked exceptions were included.
-It is unlikely that there would be a runtime representation for each distinct function type, meaning developers would be further exposed to and limited by erasure. For example, it would not be possible (perhaps surprisingly) to overload methods m(T->U) and m(X->Y).
-So, we have instead followed the path of "use what you know" -- since existing libraries use functional interfaces extensively, we codify and leverage this pattern. This enables existing libraries to be used with lambda expressions.
-
-To illustrate, here is a sampling of some of the functional interfaces already in Java SE 7 that are well-suited for being used with the new language features; the examples that follow illustrate the use of a few of them.
-
-java.lang.Runnable
-java.util.concurrent.Callable
-java.security.PrivilegedAction
-java.util.Comparator
-java.io.FileFilter
-java.beans.PropertyChangeListener
-In addition, Java SE 8 adds a new package, java.util.function, which contains functional interfaces that are expected to be commonly used, such as:
-
-Predicate -- a boolean-valued property of an object
-Consumer -- an action to be performed on an object
-Function -- a function transforming a T to a R
-Supplier -- provide an instance of a T (such as a factory)
-UnaryOperator -- a function from T to T
-BinaryOperator -- a function from (T, T) to T
-In addition to these basic "shapes", there are also primitive specializations such as IntSupplier or LongBinaryOperator. (Rather than provide the full complement of primitive specializations, we provide only specializations for int, long, and double; the other primitive types can be accomodated through conversions.) Similarly, there are some specializations for multiple arities, such as BiFunction, which represents a function from (T,U) to R.
-
-3. Lambda expressions
-The biggest pain point for anonymous classes is bulkiness. They have what we might call a "vertical problem": the ActionListener instance from section 1 uses five lines of source code to encapsulate a single aspect of behavior.
-
-Lambda expressions are anonymous methods, aimed at addressing the "vertical problem" by replacing the machinery of anonymous inner classes with a lighter-weight mechanism.
-
-Here are some examples of lambda expressions:
-
-(int x, int y) -> x + y
-
-() -> 42
-
-(String s) -> { System.out.println(s); }
-The first expression takes two integer arguments, named x and y, and returns their sum. The second takes no arguments and returns the integer 42. The third takes a string and prints it to the console, returning nothing.
-
-The general syntax consists of an argument list, the arrow token ->, and a body. The body can either be a single expression, or a statement block. In the expression form, the body is simply evaluated and returned. In the block form, the body is evaluated like a method body -- a return statement returns control to the caller of the anonymous method; break and continue are illegal at the top level, but are of course permitted within loops; and if the body produces a result, every control path must return something or throw an exception.
-
-The syntax is optimized for the common case in which a lambda expression is quite small, as illustrated above. For example, the expression-body form eliminates the need for a return keyword, which could otherwise represent a substantial syntactic overhead relative to the size of the expression.
-
-It is also expected that lambda expressions will frequently appear in nested contexts, such as the argument to a method invocation or the result of another lambda expression. To minimize noise in these cases, unnecessary delimiters are avoided. However, for situations in which it is useful to set the entire expression apart, it can be surrounded with parentheses, just like any other expression.
-
-Here are some examples of lambda expressions appearing in statements:
-
-FileFilter java = (File f) -> f.getName().endsWith(".java");
-
-String user = doPrivileged(() -> System.getProperty("user.name"));
-
-new Thread(() -> {
- connectToService();
- sendNotification();
-}).start();
-4. Target typing
-Note that the name of a functional interface is not part of the lambda expression syntax. So what kind of object does a lambda expression represent? Its type is inferred from the surrounding context. For example, the following lambda expression is an ActionListener:
-
-ActionListener l = (ActionEvent e) -> ui.dazzle(e.getModifiers());
-An implication of this approach is that the same lambda expression can have different types in different contexts:
-
-Callable c = () -> "done";
-
-PrivilegedAction a = () -> "done";
-In the first case, the lambda expression () -> "done" represents an instance of Callable. In the second case, the same expression represents an instance of PrivilegedAction.
-
-The compiler is responsible for inferring the type of each lambda expression. It uses the type expected in the context in which the expression appears; this type is called the target type. A lambda expression can only appear in a context whose target type is a functional interface.
-
-Of course, no lambda expression will be compatible with every possible target type. The compiler checks that the types used by the lambda expression are consistent with the target type's method signature. That is, a lambda expression can be assigned to a target type T if all of the following conditions hold:
-
-T is a functional interface type
-The lambda expression has the same number of parameters as T's method, and those parameters' types are the same
-Each expression returned by the lambda body is compatible with T's method's return type
-Each exception thrown by the lambda body is allowed by T's method's throws clause
-Since a functional interface target type already "knows" what types the lambda expression's formal parameters should have, it is often unnecessary to repeat them. The use of target typing enables the lambda parameters' types to be inferred:
-
-Comparator c = (s1, s2) -> s1.compareToIgnoreCase(s2);
-Here, the compiler infers that the type of s1 and s2 is String. In addition, when there is just one parameter whose type is inferred (a very common case), the parentheses surrounding a single parameter name are optional:
-
-FileFilter java = f -> f.getName().endsWith(".java");
-
-button.addActionListener(e -> ui.dazzle(e.getModifiers()));
-These enhancements further a desirable design goal: "Don't turn a vertical problem into a horizontal problem." We want the reader of the code to have to wade through as little syntax as possible before arriving at the "meat" of the lambda expression.
-
-Lambda expressions are not the first Java expressions to have context-dependent types: generic method invocations and "diamond" constructor invocations, for example, are similarly type-checked based on an assignment's target type.
-
-List ls = Collections.emptyList();
-List li = Collections.emptyList();
-
-Map m1 = new HashMap<>();
-Map m2 = new HashMap<>();
-5. Contexts for target typing
-We stated earlier that lambda expressions can only appear in contexts that have target types. The following contexts have target types:
-
-Variable declarations
-Assignments
-Return statements
-Array initializers
-Method or constructor arguments
-Lambda expression bodies
-Conditional expressions (?:)
-Cast expressions
-In the first three cases, the target type is simply the type being assigned to or returned.
-
-Comparator c;
-c = (String s1, String s2) -> s1.compareToIgnoreCase(s2);
-
-public Runnable toDoLater() {
- return () -> {
- System.out.println("later");
- };
-}
-Array initializer contexts are like assignments, except that the "variable" is an array component and its type is derived from the array's type.
-
-filterFiles(new FileFilter[] {
- f -> f.exists(), f -> f.canRead(), f -> f.getName().startsWith("q")
- });
-In the method argument case, things are more complicated: target type determination interacts with two other language features, overload resolution and type argument inference.
-
-Overload resolution involves finding the best method declaration for a particular method invocation. Since different declarations have different signatures, this can impact the target type of a lambda expression used as an argument. The compiler will use what it knows about the lambda expression to make this choice. If a lambda expression is explicitly typed (specifies the types of its parameters), the compiler will know not only the parameter types but also the type of all return expressions in its body. If the lambda is implicitly typed (inferred parameter types), overload resolution will ignore the lambda body and only use the number of lambda parameters.
-
-If the choice of a best method declaration is ambiguous, casts or explicit lambdas can provide additional type information for the compiler to disambiguate. If the return type targeted by a lambda expression depends on type argument inference, then the lambda body may provide information to the compiler to help infer the type arguments.
-
-List ps = ...
-String names = ps.stream().map(p -> p.getName());
-Here, ps is a List, so ps.stream() is a Stream. The map() method is generic in R, where the parameter of map() is a Function, where T is the stream element type. (T is known to be Person at this point.) Once the overload is selected and the lambda's target type is known, we need to infer R; we do this by type-checking the lambda body, and discovering that its return type is String, and hence R is String, and therefore the map() expression has a type of Stream. Most of the time, the compiler just figures this all out, but if it gets stuck, we can provide additional type information via an explicit lambda (give the argument p an explicit type), casting the lambda to an explicit target type such as Function, or providing an explicit type witness for the generic parameter R (.map(p -> p.getName())).
-
-Lambda expressions themselves provide target types for their bodies, in this case by deriving that type from the outer target type. This makes it convenient to write functions that return other functions:
-
-Supplier c = () -> () -> { System.out.println("hi"); };
-Similarly, conditional expressions can "pass down" a target type from the surrounding context:
-
-Callable c = flag ? (() -> 23) : (() -> 42);
-Finally, cast expressions provide a mechanism to explicitly provide a lambda expression's type if none can be conveniently inferred from context:
-
-// Illegal: Object o = () -> { System.out.println("hi"); };
-Object o = (Runnable) () -> { System.out.println("hi"); };
-Casts are also useful to help resolve ambiguity when a method declaration is overloaded with unrelated functional interface types.
-
-The expanded role of target typing in the compiler is not limited to lambda expressions: generic method invocations and "diamond" constructor invocations can also take advantage of target types wherever they are available. The following declarations are illegal in Java SE 7 but valid in Java SE 8:
-
-List ls =
- Collections.checkedList(new ArrayList<>(), String.class);
-
-Set si = flag ? Collections.singleton(23)
- : Collections.emptySet();
-6. Lexical scoping
-Determining the meaning of names (and this) in inner classes is significantly more difficult and error-prone than when classes are limited to the top level. Inherited members -- including methods of class Object -- can accidentally shadow outer declarations, and unqualified references to this always refer to the inner class itself.
-
-Lambda expressions are much simpler: they do not inherit any names from a supertype, nor do they introduce a new level of scoping. Instead, they are lexically scoped, meaning names in the body are interpreted just as they are in the enclosing environment (with the addition of new names for the lambda expression's formal parameters). As a natural extension, the this keyword and references to its members have the same meaning as they would immediately outside the lambda expression.
-
-To illustrate, the following program prints "Hello, world!" twice to the console:
-
-public class Hello {
- Runnable r1 = () -> { System.out.println(this); }
- Runnable r2 = () -> { System.out.println(toString()); }
-
- public String toString() { return "Hello, world!"; }
-
- public static void main(String... args) {
- new Hello().r1.run();
- new Hello().r2.run();
- }
-}
-The equivalent using anonymous inner classes would instead, perhaps to the programmer's surprise, print something like Hello$1@5b89a773 and Hello$2@537a7706.
-
-Consistent with the lexical-scoping approach, and following the pattern set by other local parameterized constructs like for loops and catch clauses, the parameters of a lambda expression must not shadow any local variables in the enclosing context.
-
-7. Variable capture
-The compiler check for references to local variables of enclosing contexts in inner classes (captured variables) is quite restrictive in Java SE 7: an error occurs if the captured variable is not declared final. We relax this restriction -- for both lambda expressions and inner classes -- by also allowing the capture of effectively final local variables.
-
-Informally, a local variable is effectively final if its initial value is never changed -- in other words, declaring it final would not cause a compilation failure.
-
-Callable helloCallable(String name) {
- String hello = "Hello";
- return () -> (hello + ", " + name);
-}
-References to this -- including implicit references through unqualified field references or method invocations -- are, essentially, references to a final local variable. Lambda bodies that contain such references capture the appropriate instance of this. In other cases, no reference to this is retained by the object.
-
-This has a beneficial implication for memory management: while inner class instances always hold a strong reference to their enclosing instance, lambdas that do not capture members from the enclosing instance do not hold a reference to it. This characteristic of inner class instances can often be a source of memory leaks.
-
-While we relax the syntactic restrictions on captured values, we still prohibit capture of mutable local variables. The reason is that idioms like this:
-
-int sum = 0;
-list.forEach(e -> { sum += e.size(); }); // ERROR
-are fundamentally serial; it is quite difficult to write lambda bodies like this that do not have race conditions. Unless we are willing to enforce -- preferably at compile time -- that such a function cannot escape its capturing thread, this feature may well cause more trouble than it solves. Lambda expressions close over values, not variables.
-
-Another reason to not support capture of mutable variables is that there's a better way to address accumulation problems without mutation, and instead treat this problem as a reduction. The java.util.stream package provides both general and specialized (such as sum, min, and max) reductions on collections and other data structures. For example, instead of using forEach and mutation, we could do a reduction which is safe both sequentially or in parallel:
-
-int sum = list.stream()
- .mapToInt(e -> e.size())
- .sum();
-The sum() method is provided for convenience, but is equivalent to the more general form of reduction:
-
-int sum = list.stream()
- .mapToInt(e -> e.size())
- .reduce(0, (x,y) -> x+y);
-Reduction takes a base value (in case the input is empty) and an operator (here, addition), and computes the following expression:
-
-0 + list[0] + list[1] + list[2] + ...
-Reduction can be done with other operations as well, such as minimum, maximum, product, etc, and if the operator is associative, is easily and safely parallelized. So, rather than supporting an idiom that is fundamentally sequential and prone to data races (mutable accumulators), we instead choose to provide library support to express accumulations in a more parallelizable and less error-prone way.
-
-8. Method references
-Lambda expressions allow us to define an anonymous method and treat it as an instance of a functional interface. It is often desirable to do the same with an existing method.
-
-Method references are expressions which have the same treatment as lambda expressions (i.e., they require a target type and encode functional interface instances), but instead of providing a method body, they refer an existing method by name.
-
-For example, consider a Person class that can be sorted by name or by age.
-
-class Person {
- private final String name;
- private final int age;
-
- public int getAge() { return age; }
- public String getName() { return name; }
- ...
-}
-
-Person[] people = ...
-Comparator byName = Comparator.comparing(p -> p.getName());
-Arrays.sort(people, byName);
-We can rewrite this to use a method reference to Person.getName() instead:
-
-Comparator byName = Comparator.comparing(Person::getName);
-Here, the expression Person::getName can be considered shorthand for a lambda expression which simply invokes the named method with its arguments, and returns the result. While the method reference may not (in this case) be any more syntactically compact, it is clearer -- the method that we want to call has a name, and so we can refer to it directly by name.
-
-Because the functional interface method's parameter types act as arguments in an implicit method invocation, the referenced method signature is allowed to manipulate the parameters -- via widening, boxing, grouping as a variable-arity array, etc. -- just like a method invocation.
-
-Consumer b1 = System::exit; // void exit(int status)
-Consumer b2 = Arrays::sort; // void sort(Object[] a)
-Consumer b3 = MyProgram::main; // void main(String... args)
-Runnable r = MyProgram::main; // void main(String... args)
-9. Kinds of method references
-There are several different kinds of method references, each with slightly different syntax:
-
-A static method (ClassName::methName)
-An instance method of a particular object (instanceRef::methName)
-A super method of a particular object (super::methName)
-An instance method of an arbitrary object of a particular type (ClassName::methName)
-A class constructor reference (ClassName::new)
-An array constructor reference (TypeName[]::new)
-For a static method reference, the class to which the method belongs precedes the :: delimiter, such as in Integer::sum.
-
-For a reference to an instance method of a particular object, an expression evaluating to an object reference precedes the delimiter:
-
-Set knownNames = ...
-Predicate isKnown = knownNames::contains;
-Here, the implicit lambda expression would capture the String object referred to by knownNames, and the body would invoke Set.contains using that object as the receiver.
-
-The ability to reference the method of a specific object provides a convenient way to convert between different functional interface types:
-
-Callable c = ...
-PrivilegedAction a = c::call;
-For a reference to an instance method of an arbitrary object, the type to which the method belongs precedes the delimiter, and the invocation's receiver is the first parameter of the functional interface method:
-
-Function upperfier = String::toUpperCase;
-Here, the implicit lambda expression has one parameter, the string to be converted to upper case, which becomes the receiver of the invocation of the toUpperCase() method.
-
-If the class of the instance method is generic, its type parameters can be provided before the :: delimiter or, in most cases, inferred from the target type.
-
-Note that the syntax for a static method reference might also be interpreted as a reference to an instance method of a class. The compiler determines which is intended by attempting to identify an applicable method of each kind (noting that the instance method has one less argument).
-
-For all forms of method references, method type arguments are inferred as necessary, or they can be explicitly provided following the :: delimiter.
-
-Constructors can be referenced in much the same was as static methods by using the name new:
-
-SocketImplFactory factory = MySocketImpl::new;
-If a class has multiple constructors, the target type's method signature is used to select the best match in the same way that a constructor invocation is resolved.
-
-For inner classes, no syntax supports explicitly providing an enclosing instance parameter at the site of the constructor reference.
-
-If the class to instantiate is generic, type arguments can be provided after the class name, or they are inferred as for a "diamond" constructor invocation.
-
-There is a special syntactic form of constructor references for arrays, which treats arrays as if they had a constructor that accepts an int parameter. For example:
-
-IntFunction arrayMaker = int[]::new;
-int[] array = arrayMaker.apply(10); // creates an int[10]
-10. Default and static interface methods
-Lambda expressions and method references add a lot of expressiveness to the Java language, but the key to really achieving our goal of making code-as-data patterns convenient and idiomatic is to complement these new features with libraries tailored to take advantage of them.
-
-Adding new functionality to existing libraries is somewhat difficult in Java SE 7. In particular, interfaces are essentially set in stone once they are published; unless one can update all possible implementations of an interface simultaneously, adding a new method to an interface can cause existing implementations to break. The purpose of default methods (previously referred to as virtual extension methods or defender methods) is to enable interfaces to be evolved in a compatible manner after their initial publication.
-
-To illustrate, the standard collections API obviously ought to provide new lambda-friendly operations. For example, the removeAll method could be generalized to remove any of a collection's elements for which an arbitrary property held, where the property was expressed as an instance of a functional interface Predicate. But where would this new method be defined? We can't add an abstract method to the Collection interface -- many existing implementations wouldn't know about the change. We could make it a static method in the Collections utility class, but that would relegate these new operations to a sort of second-class status.
-
-Default methods provide a more object-oriented way to add concrete behavior to an interface. These are a new kind of method: interface method can either be abstract or default. Default methods have an implementation that is inherited by classes that do not override it (see the next section for the details). Default methods in a functional interface don't count against its limit of one abstract method. For example, we could have (though did not) add a skip method to Iterator, as follows:
-
-interface Iterator {
- boolean hasNext();
- E next();
- void remove();
-
- default void skip(int i) {
- for (; i > 0 && hasNext(); i--) next();
- }
-}
-Given the above definition of Iterator, all classes that implement Iterator would inherit a skip method. From a client's perspective, skip is just another virtual method provided by the interface. Invoking skip on an instance of a subclass of Iterator that does not provide a body for skip has the effect of invoking the default implementation: calling hasNext and next up to a certain number of times. If a class wants to override skip with a better implementation -- by advancing a private cursor directly, for example, or incorporating an atomicity guarantee -- it is free to do so.
-
-When one interface extends another, it can add a default to an inherited abstract method, provide a new default for an inherited default method, or reabstract a default method by redeclaring the method as abstract.
-
-In addition to allowing code in interfaces in the form of default methods, Java SE 8 also introduces the ability to place static methods in interfaces as well. This allows helper methods that are specific to an interface to live with the interface, rather than in a side class (which is often named for the plural of the interface). For example, Comparator acquired static helper methods for making comparators, which takes a function that extracts a Comparable sort key and produces a Comparator:
-
-public static >
-Comparator comparing(Function keyExtractor) {
- return (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
-}
-11. Inheritance of default methods
-Default methods are inherited just like other methods; in most cases, the behavior is just as one would expect. However, when a class's or interface's supertypes provide multiple methods with the same signature, the inheritance rules attempt to resolve the conflict. Two basic principles drive these rules:
-
-Class method declarations are preferred to interface defaults. This is true whether the class method is concrete or abstract. (Hence the default keyword: default methods are a fallback if the class hierarchy doesn't say anything.)
-
-Methods that are already overridden by other candidates are ignored. This circumstance can arise when supertypes share a common ancestor.
-
-As an example of how the second rule comes into play, say the Collection and List interfaces provided different defaults for removeAll, and Queue inherits the default method from Collection; in the following implements clause, the List declaration would have priority over the Collection declaration inherited by Queue:
-
-class LinkedList implements List, Queue { ... }
-In the event that two independently-defined defaults conflict, or a default method conflicts with an abstract method, it is a compilation error. In this case, the programmer must explicitly override the supertype methods. Often, this amounts to picking the preferred default, and declaring a body that invokes the preferred default. An enhanced syntax for super supports the invocation of a particular superinterface's default implementation:
-
-interface Robot implements Artist, Gun {
- default void draw() { Artist.super.draw(); }
-}
-The name preceding super must refer to a direct superinterface that defines or inherits a default for the invoked method. This form of method invocation is not restricted to simple disambiguation -- it can be used just like any other invocation, in both classes and interfaces.
-
-In no case does the order in which interfaces are declared in an inherits or extends clause, or which interface was implemented "first" or "more recently", affect inheritance.
-
-12. Putting it together
-The language and library features for Project Lambda were designed to work together. To illustrate, we'll consider the task of sorting a list of people by last name.
-
-Today we write:
-
-List people = ...
-Collections.sort(people, new Comparator() {
- public int compare(Person x, Person y) {
- return x.getLastName().compareTo(y.getLastName());
- }
-});
-This is a very verbose way to write "sort people by last name"!
-
-With lambda expressions, we can make this expression more concise:
-
-Collections.sort(people,
- (Person x, Person y) -> x.getLastName().compareTo(y.getLastName()));
-However, while more concise, it is not any more abstract; it still burdens the programmer with the need to do the actual comparison (which is even worse when the sort key is a primitive). Small changes to the libraries can help here, such the static comparing method added to Comparator:
-
-Collections.sort(people, Comparator.comparing((Person p) -> p.getLastName()));
-This can be shortened by allowing the compiler to infer the type of the lambda parameter, and importing the comparing method via a static import:
-
-Collections.sort(people, comparing(p -> p.getLastName()));
-The lambda in the above expression is simply a forwarder for the existing method getLastName. We can use method references to reuse the existing method in place of the lambda expression:
-
-Collections.sort(people, comparing(Person::getLastName));
-Finally, the use of an ancillary method like Collections.sort is undesirable for many reasons: it is more verbose; it can't be specialized for each data structure that implements List; and it undermines the value of the List interface since users can't easily discover the static sort method when inspecting the documentation for List.
-
-Default methods provide a more object-oriented solution for this problem, where we've added a sort() method to List:
-
-people.sort(comparing(Person::getLastName));
-Which also reads much more like to the problem statement in the first place: sort the people list by last name.
-
-If we add a default method reversed() to Comparator, which produces a Comparator that uses the same sort key but in reverse order, we can just as easily express a descending sort:
-
-people.sort(comparing(Person::getLastName).reversed());
-13. Summary
-Java SE 8 adds a relatively small number of new language features -- lambda expressions, method references, default and static methods in interfaces, and more widespread use of type inference. Taken together, though, they enable programmers to express their intent more clearly and concisely with less boilerplate, and enable the development of more powerful, parallel-friendly libraries.
\ No newline at end of file
diff --git a/3-0-java-core/3-6-3-crazy-regex/README.MD b/3-0-java-core/3-6-3-crazy-regex/README.MD
deleted file mode 100644
index 4d42bebf6..000000000
--- a/3-0-java-core/3-6-3-crazy-regex/README.MD
+++ /dev/null
@@ -1,66 +0,0 @@
-# Crazy Regex
-
-### Pre-conditions ❗
-You're supposed to know how to work regex and be able to build Patterns and Matchers
-
-### Objectives
-* **build Patterns to extract** necessary parts from text ✅
-* **manipulate** extracted text with **Matcher** object ✅
-
-### Regular expressions - sequence of characters that define a search pattern for text
-
----
-
-There 2 peace pf puzzle:
-* Literal characters - I want to match literally the character I specified (like 'a')
-* Meta characters - I want to match any character of this kind (more generic/abstract thing)
-
-Single char
-
-* \\d -> 0-9
-* \\D -> negate of \\d
-* \\w -> A-Za-z0-9
-* \\W -> negate of \\w
-* \\s -> whitespace, tab
-* \\S -> negate of \\s
-* . -> anything but newline
-* \\. -> literal dot
-
-
-Quantifiers - modify single characters how many of them you want match in a row
-* \* -> Occurs zero or more times
-* \+ -> 1 or more
-* ? -> zero or one
-* {min, max} -> some range
-* {n} -> precise quantity
-
-
-Position
-* ^ -> beginning
-* $ -> end
-* \\b -> word boundary
-
----
-
-Character class -> is the thing that appears in between []. For example [abc] -> match 'a' or 'b' or 'c'.
-Another example [-.] -> match dash or period. Here . is not meta character anymore and ^ are special characters inside []
-* [0-5] -> match all numbers from 0 to 5. [^0-5] -> match anything that NOT 0-5
-BUT it works like meta character only when it on first position, otherwise - its literal, [a^bc] - like this
-
----
-
-Capturing Groups - whenever u do regex search it matches whole result as a group 0.
-* \\d{3}-\\d{3}-\\d{4} -> 212-555-1234 = GROUP 0
-
-Parentheses can capture a subgroup:
-\\d{3}-(\\d{3})-(\\d{4}) where 212-555-1234 = GROUP 0, 555 = GROUP 1, 1234 = GROUP 2
-
-We can refer to this groups by $1 ($ when we want to replace) and \1 (within regex itself referring to capture group
-it's called back reference)
-
----
-
-#### 🆕 First time here? – [See Introduction](https://github.com/bobocode-projects/java-fundamentals-exercises/tree/main/0-0-intro#introduction)
-
-##
-
\ No newline at end of file
diff --git a/3-0-java-core/3-6-3-crazy-regex/pom.xml b/3-0-java-core/3-6-3-crazy-regex/pom.xml
deleted file mode 100644
index 891fe99f2..000000000
--- a/3-0-java-core/3-6-3-crazy-regex/pom.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- 3-0-java-core
- com.bobocode
- 1.0-SNAPSHOT
-
- 4.0.0
-
- 3-6-3-crazy-regex
-
-
-
\ No newline at end of file
diff --git a/3-0-java-core/3-6-3-crazy-regex/src/main/java/com/bobocode/se/CrazyRegex.java b/3-0-java-core/3-6-3-crazy-regex/src/main/java/com/bobocode/se/CrazyRegex.java
deleted file mode 100644
index e213d3f26..000000000
--- a/3-0-java-core/3-6-3-crazy-regex/src/main/java/com/bobocode/se/CrazyRegex.java
+++ /dev/null
@@ -1,255 +0,0 @@
-package com.bobocode.se;
-
-import com.bobocode.util.ExerciseNotCompletedException;
-
-import java.util.regex.Pattern;
-
-/**
- * {@link CrazyRegex} is an exercise class. Each method returns Pattern class which
- * should be created using regex expression. Every method that is not implemented yet
- * throws {@link ExerciseNotCompletedException}
- *
- * TODO: remove exception and implement each method of this class using {@link Pattern}
- *
- * @author Andriy Paliychuk
- */
-public class CrazyRegex {
-
- /**
- * A Pattern that that finds all words "Curiosity" in text
- *
- * @return a pattern that looks for the word "Curiosity"
- */
- public Pattern findSpecificWord() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds first word in text
- *
- * @return a pattern that looks for the first word in text
- */
- public Pattern findFirstWord() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds last word in text
- *
- * @return a pattern that looks for the last word in text
- */
- public Pattern findLastWord() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds all numbers in text. When we have "555-555", "(555)555" and "30th" in text
- * our pattern must grab all that numbers:
- * "555" - four times, and one "30"
- *
- * @return a pattern that looks for numbers
- */
- public Pattern findAllNumbers() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds all dates. For instance: "1971-11-23"
- *
- * @return a pattern that looks for dates
- */
- public Pattern findDates() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds different variations of word "color".
- * We are looking for: "color", "colour", "colors", "colours"
- *
- * @return a pattern that looks for different variations of word "color"
- */
- public Pattern findDifferentSpellingsOfColor() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds all zip codes in text.
- * Zip code is a 5-digit number without any characters or special symbols.
- * For example: 72300
- *
- * @return a pattern that looks for zip codes
- */
- public Pattern findZipCodes() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds different variations of word "link".
- * We are looking for: "lynk", "link", "l nk", "l(nk"
- *
- * @return a pattern that looks for different variations of word "link"
- */
- public Pattern findDifferentSpellingsOfLink() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds phone numbers.
- * For example: "555-555-5555"
- *
- * @return a pattern that looks for phone numbers
- */
- public Pattern findSimplePhoneNumber() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds numbers with following requirements:
- * - inside the number can be only digits from 0 to 5
- * - length 3
- *
- * @return a pattern that looks for numbers with length 3 and digits from 0 to 5 in the middle
- */
- public Pattern findNumbersFromZeroToFiveWithLengthThree() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds all words in text that have length 5
- *
- * @return a pattern that looks for the words that have length 5
- */
- public Pattern findAllWordsWithFiveLength() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds words and numbers with following constraints:
- * - not shorter than two symbols
- * - not longer than three symbols
- *
- * @return a pattern that looks for words and numbers that not shorter 2 and not longer 3
- */
- public Pattern findAllLettersAndDigitsWithLengthThree() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds all words that begin with capital letter
- *
- * @return a pattern that looks for the words that begin with capital letter
- */
- public Pattern findAllWordsWhichBeginWithCapitalLetter() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds only the following abbreviation:
- * - AK, AL, AR, AZ, CA, CO, CT, PR, PA, PD
- *
- * @return a pattern that looks for the abbreviations above
- */
- public Pattern findAbbreviation() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds all open braces
- *
- * @return a pattern that looks for all open braces
- */
- public Pattern findAllOpenBraces() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds everything inside []
- *
- * @return a pattern that looks for everything inside []
- */
- public Pattern findOnlyResources() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds all https links in note.txt
- *
- * @return a pattern that looks for all https links in note.txt
- */
- public Pattern findOnlyLinksInNote() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds all http links in nasa.json
- *
- * @return a pattern that looks for all http links in nasa.json
- */
- public Pattern findOnlyLinksInJson() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds all .com, .net and .edu emails
- *
- * @return a pattern that looks for all .com, .net and .edu emails
- */
- public Pattern findAllEmails() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds the following examples of phone numbers:
- * - 555-555-5555
- * - 555.555.5555
- * - (555)555-5555
- *
- * @return a pattern that looks for phone numbers patterns above
- */
- public Pattern findAllPatternsForPhoneNumbers() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * A Pattern that finds only duplicates
- *
- * @return a pattern that looks for duplicates
- */
- public Pattern findOnlyDuplicates() {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * You have a text where all names recorded as first name, last name.
- * Create matcher and use method replaceAll to record that names as:
- * - last name first name
- *
- * @return String where all names recorded as last name first name
- */
- public String replaceFirstAndLastNames(String names) {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * You have a text with phone numbers.
- * Create matcher and use method replaceAll to replace last digits:
- * - 555-XXX-XXXX
- *
- * @return String where in all phone numbers last 7 digits replaced to X
- */
- public String replaceLastSevenDigitsOfPhoneNumberToX(String phones) {
- throw new ExerciseNotCompletedException();
- }
-
- /**
- * You have a text with resources and links to those resources:
- * - [Bobocode](https://www.bobocode.com)
- * Create matcher and use method replaceAll to get the following result:
- * - Bobocode
- *
- * @return String where all resources embraced in href
- */
- public String insertLinksAndResourcesIntoHref(String links) {
- throw new ExerciseNotCompletedException();
- }
-}
diff --git a/3-0-java-core/3-6-3-crazy-regex/src/test/java/com/bobocode/se/CrazyRegexTest.java b/3-0-java-core/3-6-3-crazy-regex/src/test/java/com/bobocode/se/CrazyRegexTest.java
deleted file mode 100644
index e0d2d50fb..000000000
--- a/3-0-java-core/3-6-3-crazy-regex/src/test/java/com/bobocode/se/CrazyRegexTest.java
+++ /dev/null
@@ -1,246 +0,0 @@
-package com.bobocode.se;
-
-import lombok.SneakyThrows;
-import org.junit.jupiter.api.MethodOrderer;
-import org.junit.jupiter.api.Order;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestMethodOrder;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Stream;
-
-import static java.util.stream.Collectors.joining;
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-
-/**
- * A test class for {@link CrazyRegex}.
- *
- * @author Andriy Paliychuk
- */
-@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-public class CrazyRegexTest {
-
- private final CrazyRegex crazyRegex = new CrazyRegex();
-
- private final String text;
- private final String json;
-
- public CrazyRegexTest() {
- this.text = readWholeFile("note.txt");
- this.json = readWholeFile("nasa.json");
- }
-
- @Test
- @Order(1)
- void findSpecificWord() {
- String result = regexChecker(crazyRegex.findSpecificWord(), json);
- assertThat(result).isEqualTo("\nCuriosity\nCuriosity\nCuriosity");
- }
-
- @Test
- @Order(2)
- void findFirstWord() {
- String result = regexChecker(crazyRegex.findFirstWord(), text);
- assertThat(result).isEqualTo("\nThe");
- }
-
- @Test
- @Order(3)
- void findLastWord() {
- String result = regexChecker(crazyRegex.findLastWord(), text);
- assertThat(result).isEqualTo("\nfish");
- }
-
- @Test
- @Order(4)
- void findAllNumbers() {
- String result = regexChecker(crazyRegex.findAllNumbers(), text);
- assertThat(result).isEqualTo("\n01001\n03148\n02132\n412\n555\n1212\n412\n555" +
- "\n1234\n412\n555\n1234\n646\n555\n1234\n1");
- }
-
- @Test
- @Order(5)
- void findDates() {
- String result = regexChecker(crazyRegex.findDates(), json);
- assertThat(result).isEqualTo("\n2015-05-30\n2012-08-06\n2011-11-26\n2015-05-30\n2012-08-06\n" +
- "2011-11-26\n2015-05-30\n2012-08-06\n2011-11-26");
- }
-
- @Test
- @Order(6)
- void findDifferentSpellingsOfColor() {
- String result = regexChecker(crazyRegex.findDifferentSpellingsOfColor(), text);
- assertThat(result).isEqualTo("\ncolors\ncolours\ncolour");
- }
-
- @Test
- @Order(7)
- void findZipCodes() {
- String result = regexChecker(crazyRegex.findZipCodes(), text);
- assertThat(result).isEqualTo("\n 01001 \n 03148 \n 02132 ");
- }
-
- @Test
- @Order(8)
- void findDifferentSpellingsOfLink() {
- String result = regexChecker(crazyRegex.findDifferentSpellingsOfLink(), text);
- assertThat(result).isEqualTo("\nlynk\nlink\nl nk\nl(nk");
- }
-
- @Test
- @Order(9)
- void findSimplePhoneNumber() {
- String result = regexChecker(crazyRegex.findSimplePhoneNumber(), text);
- assertThat(result).isEqualTo("\n412-555-1234");
- }
-
- @Test
- @Order(10)
- void findNumbersFromZeroToFiveWithLengthThree() {
- String result = regexChecker(crazyRegex.findNumbersFromZeroToFiveWithLengthThree(), text);
- assertThat(result).isEqualTo("\n010\n031\n021\n412\n555\n121\n412" +
- "\n555\n123\n412\n555\n123\n555\n123");
- }
-
- @Test
- @Order(11)
- void findAllWordsWithFiveLength() {
- String result = regexChecker(crazyRegex.findAllWordsWithFiveLength(), json);
- assertThat(result).isEqualTo("\nFront\nrover\nFront\nrover\nrover");
- }
-
- @Test
- @Order(12)
- void findAllLettersAndDigitsWithLengthThree() {
- String result = regexChecker(crazyRegex.findAllLettersAndDigitsWithLengthThree(), text);
- assertThat(result).isEqualTo("\nThe\nof\nthe\nand\nthe\nnot\nThe\nis\ndon\nyou\nnk\nnk\nThe\nCA\nAK\nPA\n412" +
- "\n555\ncom\n412\n555\n412\n555\n646\n555\nof\ncom\nnet\nor\nnyu\nedu\n1Z\naaa\nOf\nwww\ncom\ncom\nwww\ncom" +
- "\nis\nis\nam\nnot\nnot\nwhy\nwhy\nam\nok\ncat\ncat\ndog\ndog");
- }
-
- @Test
- @Order(13)
- void findAllWordsWhichBeginWithCapitalLetter() {
- String result = regexChecker(crazyRegex.findAllWordsWhichBeginWithCapitalLetter(), json);
- assertThat(result).isEqualTo("\nFront\nHazard\nAvoidance\nCamera" +
- "\nCuriosity\nFront\nHazard\nAvoidance\nCamera\nCuriosity\nRear\nHazard\nAvoidance\nCamera\nCuriosity");
- }
-
- @Test
- @Order(14)
- void findAbbreviation() {
- String result = regexChecker(crazyRegex.findAbbreviation(), text);
- assertThat(result).isEqualTo("\nCA\nAK\nPA");
- }
-
- @Test
- @Order(15)
- void findAllOpenBraces() {
- String result = regexChecker(crazyRegex.findAllOpenBraces(), text);
- assertThat(result).isEqualTo("\n{{{\n{{\n{");
- }
-
- @Test
- @Order(16)
- void findOnlyResources() {
- String result = regexChecker(crazyRegex.findOnlyResources(), text);
- assertThat(result).isEqualTo("\nGoogle\nStackOverflow\nYoutube");
- }
-
- @Test
- @Order(17)
- void findOnlyLinksInNote() {
- String result = regexChecker(crazyRegex.findOnlyLinksInNote(), text);
- assertThat(result).isEqualTo("\nhttps://www.google.com\nhttps://stackoverflow.com\nhttps://www.youtube.com");
- }
-
- @Test
- @Order(18)
- void findOnlyLinksInJson() {
- String result = regexChecker(crazyRegex.findOnlyLinksInJson(), json);
- assertThat(result).isEqualTo(
- "\nhttp://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/01000/opgs/edr/fcam/FLB_486265257EDR_F0481570FHAZ00323M_.JPG\n" +
- "http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/01000/opgs/edr/fcam/FRB_486265257EDR_F0481570FHAZ00323M_.JPG\n" +
- "http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/01000/opgs/edr/rcam/RLB_486265291EDR_F0481570RHAZ00323M_.JPG"
- );
- }
-
- @Test
- @Order(19)
- void findAllEmails() {
- String result = regexChecker(crazyRegex.findAllEmails(), text);
- assertThat(result).isEqualTo("\njohnsmith@yahoo.com\nterek.koval@gmail.com\nterek@koval.net" +
- "\nterek.koval@nyu.edu");
- }
-
- @Test
- @Order(20)
- void findAllPatternsForPhoneNumbers() {
- String result = regexChecker(crazyRegex.findAllPatternsForPhoneNumbers(), text);
- assertThat(result).isEqualTo("\n(412)555-1212\n412-555-1234\n646.555.1234");
- }
-
- @Test
- @Order(21)
- void findOnlyDuplicates() {
- String result = regexChecker(crazyRegex.findOnlyDuplicates(), text);
- assertThat(result).isEqualTo("\nis is\ntext text\ndouble double\nI I\nnot not\nwhy why" +
- "\ncat cat\ndog\ndog\nfish fish");
- }
-
- @Test
- @Order(22)
- void replaceFirstAndLastNames() {
- String names = "Tarasenko, Nazar ... Petrashyk, Petro ... Zlepko, Andrii";
- String result = crazyRegex.replaceFirstAndLastNames(names);
- assertThat(result).isEqualTo("Nazar Tarasenko ... Petro Petrashyk ... Andrii Zlepko");
- }
-
- @Test
- @Order(23)
- void replaceLastSevenDigitsOfPhoneNumberToX() {
- String phones = "(948)333-5656 1235-889-7897 111.747.6236";
- String result = crazyRegex.replaceLastSevenDigitsOfPhoneNumberToX(phones);
- assertThat(result).isEqualTo("948-XXX-XXXX 1235-XXX-XXXX 111-XXX-XXXX");
- }
-
- @Test
- @Order(24)
- void insertLinksAndResourcesIntoHref() {
- String links = "[Bobocode](https://www.bobocode.com)" +
- "\n[LinkedIn](https://www.linkedin.com)" +
- "\n[Netflix](https://www.netflix.com)";
- String result = crazyRegex.insertLinksAndResourcesIntoHref(links);
- assertThat(result).isEqualTo(
- "Bobocode \n" +
- "LinkedIn \n" +
- "Netflix "
- );
- }
-
- private String regexChecker(Pattern pattern, String str2WorkWith) {
- Matcher matcher = pattern.matcher(str2WorkWith);
- StringBuilder stringBuilder = new StringBuilder();
- while (matcher.find()) {
- if (matcher.group().length() != 0) {
- stringBuilder.append("\n").append(matcher.group());
- }
- }
- return stringBuilder.toString();
- }
-
- @SneakyThrows
- private String readWholeFile(String fileName) {
- Path filePath = Paths.get(CrazyRegex.class.getClassLoader()
- .getResource(fileName)
- .toURI());
- try (Stream fileLinesStream = Files.lines(filePath)) {
- return fileLinesStream.collect(joining("\n"));
- }
- }
-}
\ No newline at end of file
diff --git a/3-0-java-core/3-6-3-crazy-regex/src/test/resources/nasa.json b/3-0-java-core/3-6-3-crazy-regex/src/test/resources/nasa.json
deleted file mode 100644
index e21232795..000000000
--- a/3-0-java-core/3-6-3-crazy-regex/src/test/resources/nasa.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{"photos":[
- {"id":102693,
- "sol":1000,
- "camera":{"id":20,"name":"FHAZ","rover_id":5,"full_name":"Front Hazard Avoidance Camera"},
- "img_src":"http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/01000/opgs/edr/fcam/FLB_486265257EDR_F0481570FHAZ00323M_.JPG",
- "earth_date":"2015-05-30",
- "rover":{"id":5,"name":"Curiosity","landing_date":"2012-08-06","launch_date":"2011-11-26","status":"active"}
- },
- {"id":102694,
- "sol":1000,
- "camera":{"id":20,"name":"FHAZ","rover_id":5,"full_name":"Front Hazard Avoidance Camera"},
- "img_src":"http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/01000/opgs/edr/fcam/FRB_486265257EDR_F0481570FHAZ00323M_.JPG",
- "earth_date":"2015-05-30",
- "rover":{"id":5,"name":"Curiosity","landing_date":"2012-08-06","launch_date":"2011-11-26","status":"active"}
- },
- {"id":102850,
- "sol":1000,
- "camera":{"id":21,"name":"RHAZ","rover_id":5,"full_name":"Rear Hazard Avoidance Camera"},
- "img_src":"http://mars.jpl.nasa.gov/msl-raw-images/proj/msl/redops/ods/surface/sol/01000/opgs/edr/rcam/RLB_486265291EDR_F0481570RHAZ00323M_.JPG",
- "earth_date":"2015-05-30",
- "rover":{"id":5,"name":"Curiosity","landing_date":"2012-08-06","launch_date":"2011-11-26","status":"active"}
- }
-]}
\ No newline at end of file
diff --git a/3-0-java-core/3-6-3-crazy-regex/src/test/resources/note.txt b/3-0-java-core/3-6-3-crazy-regex/src/test/resources/note.txt
deleted file mode 100644
index 2ab940b50..000000000
--- a/3-0-java-core/3-6-3-crazy-regex/src/test/resources/note.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-The colors of the rainbow have many colours and the rainbow does not have a single colour
-The lynk is quite a link don't you think? l nk l(nk
-The Collin Richardson CA 01001 AK 03148 PA 02132 (412)555-1212 johnsmith@yahoo.com 412-555-1234 412 555-1234 646.555.1234
-I know email addresses of fascinating people like terek.koval@gmail.com terek@koval.net or
-terek.koval@nyu.edu
- 1Z aaa **** *** {{{ {{ { Of
-[Google](https://www.google.com)[StackOverflow](https://stackoverflow.com)[Youtube](https://www.youtube.com)
-This is is some text text with double double words some where I I I am not not sure why why I am typing ok? cat cat dog
-dog fish fish
\ No newline at end of file
diff --git a/3-0-java-core/3-6-4-random-field-comparator/src/main/java/com/bobocode/se/RandomFieldComparator.java b/3-0-java-core/3-6-4-random-field-comparator/src/main/java/com/bobocode/se/RandomFieldComparator.java
index 760989875..be1acd01f 100644
--- a/3-0-java-core/3-6-4-random-field-comparator/src/main/java/com/bobocode/se/RandomFieldComparator.java
+++ b/3-0-java-core/3-6-4-random-field-comparator/src/main/java/com/bobocode/se/RandomFieldComparator.java
@@ -1,7 +1,7 @@
package com.bobocode.se;
-import com.bobocode.util.ExerciseNotCompletedException;
-import java.util.Comparator;
+import java.lang.reflect.Field;
+import java.util.*;
/**
* A generic comparator that is comparing a random field of the given class. The field is either primitive or
@@ -17,11 +17,23 @@
* @author Stanislav Zabramnyi
*/
public class RandomFieldComparator implements Comparator {
+ private final Field chosenField;
public RandomFieldComparator(Class targetType) {
- throw new ExerciseNotCompletedException(); // todo: implement this constructor;
+ Field[] fields = targetType.getDeclaredFields();
+
+ List candidates = Arrays.stream(fields)
+ .filter(field -> field.getType().isPrimitive() || Comparable.class.isAssignableFrom(field.getType()))
+ .toList();
+
+ if (candidates.isEmpty()) {
+ throw new IllegalArgumentException("No comparable field found");
+ }
+
+ chosenField = candidates.get(new Random().nextInt(candidates.size()));
}
+
/**
* Compares two objects of the class T by the value of the field that was randomly chosen. It allows null values
* for the fields, and it treats null value greater than a non-null value.
@@ -34,14 +46,31 @@ public RandomFieldComparator(Class targetType) {
*/
@Override
public int compare(T o1, T o2) {
- throw new ExerciseNotCompletedException(); // todo: implement this method;
+ try {
+ chosenField.setAccessible(true);
+ Object value1 = chosenField.get(o1);
+ Object value2 = chosenField.get(o2);
+
+
+ //nulls are considered greater, so they go last
+ if (value1 == null && value2 == null) return 0;
+ if (value1 == null) return 1;
+ if (value2 == null) return -1;
+
+ @SuppressWarnings("unchecked")
+ Comparable comp1 = (Comparable