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
index 35d925636..102e94732 100644
--- a/0-0-intro/src/main/java/com/bobocode/intro/ExerciseIntroduction.java
+++ b/0-0-intro/src/main/java/com/bobocode/intro/ExerciseIntroduction.java
@@ -1,6 +1,6 @@
package com.bobocode.intro;
-import com.bobocode.util.ExerciseNotCompletedException;
+import java.util.Base64;
/**
* Welcome! This is an introduction exercise that will show you a simple example of Bobocode exercises.
@@ -23,8 +23,7 @@ public class ExerciseIntroduction {
* @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();
+ return "The key to efficient learning is practice!";
}
/**
@@ -39,7 +38,6 @@ public String getWelcomeMessage() {
* @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();
+ return Base64.getEncoder().encodeToString(message.getBytes());
}
}
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..da2997c74 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,13 +9,12 @@
*/
public class BoxDemoApp {
public static void main(String[] args) {
- Box intBox = new Box(123);
- Box intBox2 = new Box(321);
- System.out.println((int) intBox.getValue() + (int) intBox2.getValue());
+ Box intBox = new Box<>(123);
+ Box intBox2 = new Box<>(321);
+ System.out.println((int) intBox.getValue() + intBox2.getValue());
intBox.setValue(222);
- 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());
+// intBox.setValue("abc"); // this should not be allowed
+ System.out.println((int) intBox.getValue() + 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..5c63d64a6 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,12 @@
package com.bobocode.basics;
import com.bobocode.basics.util.BaseEntity;
-import com.bobocode.util.ExerciseNotCompletedException;
import lombok.Data;
+import lombok.val;
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 +31,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 {
+ private T value;
private String source;
}
@@ -45,11 +43,10 @@ public static class Sourced { // todo: refactor class to introduce type paramete
* @param – actual, min and max type
*/
@Data
- 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;
+ public static class Limited {
+ private final T actual;
+ private final T min;
+ private final T max;
}
/**
@@ -59,8 +56,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 {
+ R convert(T obj);
}
/**
@@ -70,10 +67,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 +79,13 @@ 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) {
+ if (val.compareTo(max) > 0) {
+ max = val;
+ }
}
- public Object getMax() {
+ public T getMax() {
return max;
}
}
@@ -97,8 +96,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 +107,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 +119,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,12 +132,14 @@ 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
+ interface ComparableCollection extends Collection, Comparable> {
+
+ @Override
+ default int compareTo(Collection> o) {
+ return Integer.compare(this.size(), o.size());
+ }
}
- /**
- * {@link CollectionUtil} is an util class that provides various generic helper methods.
- */
static class CollectionUtil {
static final Comparator CREATED_ON_COMPARATOR = Comparator.comparing(BaseEntity::getCreatedOn);
@@ -147,8 +148,7 @@ 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
+ public static void print(List> list) {
list.forEach(element -> System.out.println(" – " + element));
}
@@ -160,8 +160,9 @@ 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) {
+ return entities.stream()
+ .anyMatch(e -> e.getUuid() == null);
}
/**
@@ -173,8 +174,10 @@ 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) {
+ return entities.stream()
+ .allMatch(validationPredicate);
}
/**
@@ -187,8 +190,10 @@ 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) {
+ return entities.stream()
+ .filter(e -> e.getUuid().equals(targetEntity.getUuid()))
+ .count() > 1;
}
/**
@@ -200,7 +205,20 @@ public static boolean hasDuplicates() {
* @param type of elements
* @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) {
+ var iterator = elements.iterator();
+ if (!iterator.hasNext()) {
+ return Optional.empty();
+ }
+ var max = iterator.next();
+ while (iterator.hasNext()) {
+ var element = iterator.next();
+ if (comparator.compare(element, max) > 0) {
+ max = element;
+ }
+ }
+ return Optional.of(max);
+ }
/**
* findMostRecentlyCreatedEntity is a generic util method that accepts a collection of entities and returns the
@@ -214,7 +232,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();
+ }
/**
* An util method that allows to swap two elements of any list. It changes the list so the element with the index
@@ -228,8 +249,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 elements, int i, int j) {
+ T temp = elements.get(i);
+ elements.set(i, elements.get(j));
+ elements.set(j, temp);
+ }
}
}
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..6afbec0e7 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,7 +1,11 @@
package com.bobocode.basics;
+import java.util.Comparator;
+import java.util.HashMap;
import java.util.Map;
+import static java.util.Objects.requireNonNull;
+
/**
* {@link HeterogeneousMaxHolder} is a multi-type container that holds maximum values per each type. It's kind of a
* key/value map, where the key is a type and the value is the maximum among all values of this type that were put.
@@ -15,9 +19,10 @@
* @author Taras Boychuk
*/
public class HeterogeneousMaxHolder {
+ private Map, Object> typeToMaxValueMap = 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
+ * Stores a provided value by its type, if the value is greater than the current maximum. In other words, the logic
* of this method makes sure that only max value is stored and everything else is ignored.
*
* If the current max value is less than a provided one, or if it's null, then a provided value gets stored and the old
@@ -30,7 +35,9 @@ public class HeterogeneousMaxHolder {
* @param value type parameter
* @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) {
+ return put(key, value, Comparator.naturalOrder());
+ }
/**
* An overloaded method put implements the same logic using a custom comparator. A given comparator is wrapped with
@@ -44,14 +51,27 @@ public class HeterogeneousMaxHolder {
* @param value type parameter
* @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) {
+ var currentMax = getMax(requireNonNull(key));
+ var nullSafeComparator = Comparator.nullsFirst(requireNonNull(comparator));
+ requireNonNull(value);
+ if (nullSafeComparator.compare(value, currentMax) > 0) {
+ typeToMaxValueMap.put(key, value);
+ return currentMax;
+ }
+ 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.
+ * Returns a max value by the given type. If no value is stored by this type, then it returns null.
*
* @param key a provided value type
* @param value type parameter
* @return current max value or null
*/
- // todo: implement a method according to javadoc
+ public T getMax(Class key) {
+ requireNonNull(key);
+ var currentMax = typeToMaxValueMap.get(key);
+ return key.cast(currentMax);
+ }
}
diff --git a/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Exercise.java b/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Exercise.java
new file mode 100644
index 000000000..70066cbff
--- /dev/null
+++ b/1-0-java-basics/1-5-0-hello-annotations/src/main/java/com/bobocode/basics/Exercise.java
@@ -0,0 +1,14 @@
+package com.bobocode.basics;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Exercise {
+ String value();
+
+ Level complexityLevel() default Level.BASIC;
+}
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
index 4dc8c4b22..268ee071d 100644
--- 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
@@ -13,5 +13,6 @@
*
* @author Taras Boychuk
*/
+@Exercise("hello-annotation-basic")
public class HelloAnnotationsExercise { // todo: mark class with the annotation according to the javadoc
}
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
index b01a4acfb..97c0c5a82 100644
--- 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
@@ -9,5 +9,10 @@
* @author Taras Boychuk
*/
public class Node {
- // todo:
+ T element;
+ Node next;
+
+ public Node(T element) {
+ this.element = element;
+ }
}
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
index 5321aa53a..cfe213778 100644
--- 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
@@ -1,7 +1,5 @@
package com.bobobode.cs;
-import com.bobocode.util.ExerciseNotCompletedException;
-
/**
* A class that consists of static methods only and provides util methods for {@link Node}.
*
@@ -22,7 +20,7 @@ private Nodes() {
* @return a new instance of {@link Node}
*/
public static Node create(T element) {
- throw new ExerciseNotCompletedException(); // todo:
+ return new Node<>(element);
}
/**
@@ -33,7 +31,7 @@ public static Node create(T element) {
* @param a genetic type
*/
public static void link(Node first, Node second) {
- throw new ExerciseNotCompletedException(); // todo:
+ first.next = second;
}
/**
@@ -46,7 +44,9 @@ public static void link(Node first, Node second) {
* @return a reference to a first node created based on firstElement
*/
public static Node pairOf(T firstElement, T secondElement) {
- throw new ExerciseNotCompletedException(); // todo:
+ Node firstNode = new Node<>(firstElement);
+ firstNode.next = new Node<>(secondElement);
+ return firstNode;
}
/**
@@ -60,7 +60,11 @@ public static Node pairOf(T firstElement, T secondElement) {
* @return a reference to the first node
*/
public static Node closedPairOf(T firstElement, T secondElement) {
- throw new ExerciseNotCompletedException(); // todo:
+ Node firstNode = new Node<>(firstElement);
+ Node secondNode = new Node<>(secondElement);
+ firstNode.next = secondNode;
+ secondNode.next = firstNode;
+ return firstNode;
}
/**
@@ -72,7 +76,13 @@ public static Node closedPairOf(T firstElement, T secondElement) {
* @return a reference to the first element of the chain
*/
public static Node chainOf(T... elements) {
- throw new ExerciseNotCompletedException(); // todo:
+ Node firstNode = new Node<>(elements[0]);
+ Node current = firstNode;
+ for (int i = 1; i < elements.length; i++) {
+ current.next = new Node<>(elements[i]);
+ current = current.next;
+ }
+ return firstNode;
}
/**
@@ -85,6 +95,13 @@ public static Node chainOf(T... elements) {
* @return a reference to the first element of the chain
*/
public static Node circleOf(T... elements) {
- throw new ExerciseNotCompletedException(); // todo:
+ Node firstNode = new Node<>(elements[0]);
+ Node current = firstNode;
+ for (int i = 1; i < elements.length; i++) {
+ current.next = new Node<>(elements[i]);
+ current = current.next;
+ }
+ current.next = firstNode;
+ return firstNode;
}
}
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
index 05b0c724d..4a15e0814 100644
--- 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
@@ -1,7 +1,8 @@
package com.bobocode.cs;
import com.bobocode.cs.exception.EmptyStackException;
-import com.bobocode.util.ExerciseNotCompletedException;
+import java.util.Objects;
+import java.util.stream.Stream;
/**
* {@link LinkedStack} is a stack implementation that is based on singly linked generic nodes.
@@ -15,6 +16,21 @@
* @author Serhii Hryhus
*/
public class LinkedStack implements Stack {
+ private static class Node {
+ T element;
+ Node next;
+
+ public static Node valueOf(T element) {
+ return new Node<>(element);
+ }
+
+ private Node(T element) {
+ this.element = element;
+ }
+ }
+
+ private Node head;
+ private int size = 0;
/**
* This method creates a stack of provided elements
@@ -24,7 +40,9 @@ public class LinkedStack implements Stack {
* @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
+ LinkedStack linkedStack = new LinkedStack<>();
+ Stream.of(elements).forEach(linkedStack::push);
+ return linkedStack;
}
/**
@@ -35,7 +53,13 @@ public static LinkedStack of(T... elements) {
*/
@Override
public void push(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ Objects.requireNonNull(element);
+ Node newNode = Node.valueOf(element);
+ if (head != null) {
+ newNode.next = head;
+ }
+ head = newNode;
+ size++;
}
/**
@@ -47,7 +71,18 @@ public void push(T element) {
*/
@Override
public T pop() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ if (head != null) {
+ size--;
+ return retrieveHead();
+ } else {
+ throw new EmptyStackException();
+ }
+ }
+
+ private T retrieveHead() {
+ T element = head.element;
+ this.head = head.next;
+ return element;
}
/**
@@ -57,7 +92,7 @@ public T pop() {
*/
@Override
public int size() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ return size;
}
/**
@@ -67,7 +102,7 @@ public int size() {
*/
@Override
public boolean isEmpty() {
- throw new ExerciseNotCompletedException(); // todo: implement this method;
+ return head == null;
}
}
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
index 7b4a79667..ce9bd4911 100644
--- 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
@@ -1,7 +1,5 @@
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()}
@@ -15,6 +13,22 @@
* @author Ivan Virchenko
*/
public class LinkedQueue implements Queue {
+ static final class Node {
+ private T element;
+ private Node next;
+
+ static Node valueOf(T element) {
+ return new Node<>(element);
+ }
+
+ private Node(T element) {
+ this.element = element;
+ }
+ }
+
+ private Node head;
+ private Node tail;
+ private int size;
/**
* Adds an element to the end of the queue.
@@ -22,7 +36,14 @@ public class LinkedQueue implements Queue {
* @param element the element to add
*/
public void add(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ Node newNode = Node.valueOf(element);
+ if (head == null) {
+ head = tail = newNode;
+ } else {
+ tail.next = newNode;
+ tail = newNode;
+ }
+ size++;
}
/**
@@ -31,7 +52,17 @@ public void add(T element) {
* @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
+ if (head != null) {
+ T element = head.element;
+ head = head.next;
+ if (head == null) {
+ tail = null;
+ }
+ size--;
+ return element;
+ } else {
+ return null;
+ }
}
/**
@@ -40,7 +71,7 @@ public T poll() {
* @return an integer value that is a size of queue
*/
public int size() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ return size;
}
/**
@@ -49,6 +80,6 @@ public int size() {
* @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
+ return head == null;
}
}
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
index 502fefbdf..0c8f5f15e 100644
--- 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
@@ -1,7 +1,8 @@
package com.bobocode.cs;
-
-import com.bobocode.util.ExerciseNotCompletedException;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.stream.Stream;
/**
* {@link LinkedList} is a list implementation that is based on singly linked generic nodes. A node is implemented as
@@ -15,6 +16,9 @@
* @author Serhii Hryhus
*/
public class LinkedList implements List {
+ private Node first;
+ private Node last;
+ private int size;
/**
* This method creates a list of provided elements
@@ -24,7 +28,9 @@ public class LinkedList implements List {
* @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
+ LinkedList linkedList = new LinkedList<>();
+ Stream.of(elements).forEach(linkedList::add);
+ return linkedList;
}
/**
@@ -34,7 +40,14 @@ public static LinkedList of(T... elements) {
*/
@Override
public void add(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ Node newNode = new Node<>(element);
+ if (size == 0) {
+ first = last = newNode;
+ } else {
+ last.next = newNode;
+ last = newNode;
+ }
+ size++;
}
/**
@@ -46,7 +59,51 @@ public void add(T element) {
*/
@Override
public void add(int index, T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ Node newNode = Node.valueOf(element);
+ if (index == 0) {
+ addAsHead(newNode);
+ } else if (index == size) {
+ addAsTail(newNode);
+ } else {
+ add(index, newNode);
+ }
+ size++;
+ }
+
+ private void addAsHead(Node newNode) {
+ newNode.next = first;
+ first = newNode;
+ if (first.next == null) {
+ last = first;
+ }
+ }
+
+ private void addAsTail(Node newNode) {
+ last.next = newNode;
+ last = newNode;
+ }
+
+ private void add(int index, Node newNode) {
+ Node node = findNodeByIndex(index - 1);
+ newNode.next = node.next;
+ node.next = newNode;
+ }
+
+ private Node findNodeByIndex(int index) {
+ Objects.checkIndex(index, size);
+ if (index == size - 1) {
+ return last;
+ } else {
+ return nodeAt(index);
+ }
+ }
+
+ private Node nodeAt(int index) {
+ Node currentNode = first;
+ for (int i = 0; i < index; i++) {
+ currentNode = currentNode.next;
+ }
+ return currentNode;
}
/**
@@ -58,7 +115,8 @@ public void add(int index, T element) {
*/
@Override
public void set(int index, T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ Node node = findNodeByIndex(index);
+ node.value = element;
}
/**
@@ -70,7 +128,8 @@ public void set(int index, T element) {
*/
@Override
public T get(int index) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ Node node = findNodeByIndex(index);
+ return node.value;
}
/**
@@ -81,7 +140,8 @@ public T get(int index) {
*/
@Override
public T getFirst() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ checkElementsExist();
+ return first.value;
}
/**
@@ -92,7 +152,14 @@ public T getFirst() {
*/
@Override
public T getLast() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ checkElementsExist();
+ return last.value;
+ }
+
+ private void checkElementsExist() {
+ if (first == null) {
+ throw new NoSuchElementException();
+ }
}
/**
@@ -104,9 +171,28 @@ public T getLast() {
*/
@Override
public T remove(int index) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ T deletedElement;
+ if (index == 0 && !isEmpty()) {
+ deletedElement = first.value;
+ removeHead();
+ } else {
+ Node previousNode = findNodeByIndex(index - 1);
+ deletedElement = previousNode.next.value;
+ previousNode.next = previousNode.next.next;
+ if (index == size - 1) {
+ last = previousNode;
+ }
+ }
+ size--;
+ return deletedElement;
}
+ private void removeHead() {
+ first = first.next;
+ if (first == null) {
+ last = null;
+ }
+ }
/**
* Checks if a specific exists in he list
@@ -115,7 +201,14 @@ public T remove(int index) {
*/
@Override
public boolean contains(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ Node currentNode = first;
+ while (currentNode != null) {
+ if (currentNode.value.equals(element)) {
+ return true;
+ }
+ currentNode = currentNode.next;
+ }
+ return false;
}
/**
@@ -125,7 +218,7 @@ public boolean contains(T element) {
*/
@Override
public boolean isEmpty() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ return first == null;
}
/**
@@ -135,7 +228,7 @@ public boolean isEmpty() {
*/
@Override
public int size() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ return size;
}
/**
@@ -143,6 +236,20 @@ public int size() {
*/
@Override
public void clear() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ first = last = null;
+ size = 0;
+ }
+
+ static class Node {
+ private T value;
+ private Node next;
+
+ private Node(T value) {
+ this.value = value;
+ }
+
+ public static Node valueOf(T value) {
+ return new Node<>(value);
+ }
}
}
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
index 384ca81e5..10be12b87 100644
--- 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
@@ -1,6 +1,8 @@
package com.bobocode.cs;
-import com.bobocode.util.ExerciseNotCompletedException;
+import java.util.Arrays;
+import java.util.NoSuchElementException;
+import java.util.Objects;
/**
* {@link ArrayList} is an implementation of {@link List} interface. This resizable data structure
@@ -12,6 +14,9 @@
* @author Serhii Hryhus
*/
public class ArrayList implements List {
+ private static final int DEFAULT_CAPACITY = 5;
+ private Object[] elementData;
+ private int size;
/**
* This constructor creates an instance of {@link ArrayList} with a specific capacity of an array inside.
@@ -20,7 +25,10 @@ public class ArrayList implements List {
* @throws IllegalArgumentException – if the specified initial capacity is negative or 0.
*/
public ArrayList(int initCapacity) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ if (initCapacity <= 0) {
+ throw new IllegalArgumentException();
+ }
+ elementData = new Object[initCapacity];
}
/**
@@ -28,7 +36,7 @@ public ArrayList(int initCapacity) {
* A default size of inner array is 5;
*/
public ArrayList() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ this(DEFAULT_CAPACITY);
}
/**
@@ -38,7 +46,10 @@ public ArrayList() {
* @return new instance
*/
public static List of(T... elements) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ ArrayList list = new ArrayList<>(elements.length);
+ list.elementData = Arrays.copyOf(elements, elements.length);
+ list.size = elements.length;
+ return list;
}
/**
@@ -48,7 +59,15 @@ public static List of(T... elements) {
*/
@Override
public void add(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ increaseDataArrayIfFull();
+ elementData[size] = element;
+ size++;
+ }
+
+ private void increaseDataArrayIfFull() {
+ if (elementData.length == size) {
+ elementData = Arrays.copyOf(elementData, size * 2);
+ }
}
/**
@@ -59,7 +78,10 @@ public void add(T element) {
*/
@Override
public void add(int index, T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ increaseDataArrayIfFull();
+ System.arraycopy(elementData, index, elementData, index + 1, size - index);
+ elementData[index] = element;
+ size++;
}
/**
@@ -70,8 +92,10 @@ public void add(int index, T element) {
* @return en element
*/
@Override
+ @SuppressWarnings("unchecked")
public T get(int index) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ Objects.checkIndex(index, size);
+ return (T) elementData[index];
}
/**
@@ -81,8 +105,12 @@ public T get(int index) {
* @throws java.util.NoSuchElementException if list is empty
*/
@Override
+ @SuppressWarnings("unchecked")
public T getFirst() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ if (isEmpty()) {
+ throw new NoSuchElementException();
+ }
+ return (T) elementData[0];
}
/**
@@ -92,8 +120,12 @@ public T getFirst() {
* @throws java.util.NoSuchElementException if list is empty
*/
@Override
+ @SuppressWarnings("unchecked")
public T getLast() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ if (isEmpty()) {
+ throw new NoSuchElementException();
+ }
+ return (T) elementData[size - 1];
}
/**
@@ -105,7 +137,8 @@ public T getLast() {
*/
@Override
public void set(int index, T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ Objects.checkIndex(index, size);
+ elementData[index] = element;
}
/**
@@ -116,8 +149,16 @@ public void set(int index, T element) {
* @return deleted element
*/
@Override
- public T remove(int index) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ @SuppressWarnings("unchecked")
+ public T remove(int index) {// 4,5,3,6,7,7 -> remove(3)
+ Objects.checkIndex(index, size);
+ T deletedElement = (T) elementData[index];
+ if (index < size - 1) {
+ System.arraycopy(elementData, index + 1, elementData, index, size - index - 1);
+ }
+ elementData[size - 1] = null;
+ size--;
+ return deletedElement;
}
/**
@@ -128,7 +169,12 @@ public T remove(int index) {
*/
@Override
public boolean contains(T element) {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ for (int i = 0; i < size; i++) {
+ if (elementData[i].equals(element)) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -138,7 +184,7 @@ public boolean contains(T element) {
*/
@Override
public boolean isEmpty() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ return size == 0;
}
/**
@@ -146,7 +192,7 @@ public boolean isEmpty() {
*/
@Override
public int size() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ return size;
}
/**
@@ -154,6 +200,7 @@ public int size() {
*/
@Override
public void clear() {
- throw new ExerciseNotCompletedException(); // todo: implement this method
+ elementData = new Object[DEFAULT_CAPACITY];
+ size = 0;
}
}
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
index a4e394b0b..9b821d1da 100644
--- 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
@@ -1,8 +1,8 @@
package com.bobocode.cs;
-import com.bobocode.util.ExerciseNotCompletedException;
-
+import java.util.Objects;
import java.util.function.Consumer;
+import java.util.stream.Stream;
/**
* {@link RecursiveBinarySearchTree} is an implementation of a {@link BinarySearchTree} that is based on a linked nodes
@@ -17,33 +17,123 @@
* @author Maksym Stasiuk
*/
public class RecursiveBinarySearchTree> implements BinarySearchTree {
+ private static class Node {
+ T element;
+ Node left;
+ Node right;
+
+ private Node(T element) {
+ this.element = element;
+ }
+
+ public static Node valueOf(T element) {
+ return new Node<>(element);
+ }
+ }
+
+ private Node root;
+ private int size = 0;
public static > RecursiveBinarySearchTree of(T... elements) {
- throw new ExerciseNotCompletedException();
+ RecursiveBinarySearchTree bst = new RecursiveBinarySearchTree<>();
+ Stream.of(elements).forEach(bst::insert);
+ return bst;
}
@Override
public boolean insert(T element) {
- throw new ExerciseNotCompletedException();
+ Objects.requireNonNull(element);
+ boolean isInserted = insertElement(element);
+ if (isInserted) {
+ size++;
+ }
+ return isInserted;
+ }
+
+ boolean insertElement(T element) {
+ if (root == null) {
+ root = Node.valueOf(element);
+ return true;
+ } else {
+ return insertIntoSubTree(root, element);
+ }
+ }
+
+ private boolean insertIntoSubTree(Node subTreeRoot, T element) {
+ if (subTreeRoot.element.compareTo(element) > 0) {
+ return insertIntoLeftSubtree(subTreeRoot, element);
+ } else if (subTreeRoot.element.compareTo(element) < 0) {
+ return insertIntoRightSubtree(subTreeRoot, element);
+ } else {
+ return false;
+ }
+ }
+
+ private boolean insertIntoLeftSubtree(Node node, T element) {
+ if (node.left != null) {
+ return insertIntoSubTree(node.left, element);
+ } else {
+ node.left = Node.valueOf(element);
+ return true;
+ }
+ }
+
+ private boolean insertIntoRightSubtree(Node node, T element) {
+ if (node.right != null) {
+ return insertIntoSubTree(node.right, element);
+ } else {
+ node.right = Node.valueOf(element);
+ return true;
+ }
}
+
@Override
public boolean contains(T element) {
- throw new ExerciseNotCompletedException();
+ Objects.requireNonNull(element);
+ return findChildNodeByElement(root, element) != null;
+ }
+
+ private Node findChildNodeByElement(Node node, T element) {
+ if (node == null) {
+ return null;
+ } else if (node.element.compareTo(element) > 0) {
+ return findChildNodeByElement(node.left, element);
+ } else if (node.element.compareTo(element) < 0) {
+ return findChildNodeByElement(node.right, element);
+ } else {
+ return node;
+ }
}
@Override
public int size() {
- throw new ExerciseNotCompletedException();
+ return size;
}
@Override
public int depth() {
- throw new ExerciseNotCompletedException();
+ return root != null ? depth(root) - 1 : 0;
+ }
+
+ private int depth(Node node) {
+ if (node == null) {
+ return 0;
+ } else {
+ return 1 + Math.max(depth(node.left), depth(node.right));
+ }
}
@Override
public void inOrderTraversal(Consumer consumer) {
- throw new ExerciseNotCompletedException();
+ inOrderTraversal(root, consumer);
+ }
+
+ private void inOrderTraversal(Node node, Consumer consumer) {
+ if (node != null) {
+ inOrderTraversal(node.left, consumer);
+ consumer.accept(node.element);
+ inOrderTraversal(node.right, consumer);
+ }
}
}
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
index ade9cea4d..31a2d9dfb 100644
--- 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
@@ -1,6 +1,8 @@
package com.bobocode.cs;
-import com.bobocode.util.ExerciseNotCompletedException;
+import lombok.ToString;
+
+import static java.util.Objects.requireNonNull;
/**
* {@link HashTable} is a simple Hashtable-based implementation of {@link Map} interface with some additional methods.
@@ -27,6 +29,20 @@
* @author Taras Boychuk
*/
public class HashTable implements Map {
+ private static final int DEFAULT_CAPACITY = 8;
+ private static final float RESIZE_THRESHOLD = 1.0f;
+ private Node[] table;
+ private int size;
+
+ @SuppressWarnings("unchecked")
+ public HashTable(int initialCapacity) {
+ verifyCapacity(initialCapacity);
+ this.table = new Node[initialCapacity];
+ }
+
+ public HashTable() {
+ this(DEFAULT_CAPACITY);
+ }
/**
* This method is a critical part of the hast table. The main idea is that having a key, you can calculate its index
@@ -43,7 +59,8 @@ public class HashTable implements Map {
* @return array index of the given key
*/
public static int calculateIndex(Object key, int tableCapacity) {
- throw new ExerciseNotCompletedException(); // todo:
+ var hash = key.hashCode() ^ (key.hashCode() >> 16);
+ return hash & (tableCapacity - 1);
}
/**
@@ -59,7 +76,40 @@ public static int calculateIndex(Object key, int tableCapacity) {
*/
@Override
public V put(K key, V value) {
- throw new ExerciseNotCompletedException(); // todo:
+ resizeIfNeeded();
+ return putOnTable(table, key, value);
+ }
+
+ private void resizeIfNeeded() {
+ if (size / (float) table.length > RESIZE_THRESHOLD) {
+ resizeTable(2 * table.length);
+ }
+ }
+
+ private V putOnTable(Node[] table, K key, V value) {
+ var newNode = new Node<>(requireNonNull(key), requireNonNull(value));
+ var index = calculateIndex(key, table.length);
+ if (table[index] == null) { // add new head key
+ table[index] = newNode;
+ } else {
+ var current = table[index];
+ while (current.next != null) { // iterate linked list to new key
+ if (current.key.equals(key)) {
+ var prevValue = current.value;
+ current.value = value;
+ return prevValue;
+ }
+ current = current.next;
+ }
+ if (current.key.equals(key)) {
+ var prevValue = current.value;
+ current.value = value;
+ return prevValue;
+ }
+ current.next = newNode; // attach new key to the end of the list
+ }
+ size++;
+ return null;
}
/**
@@ -71,7 +121,15 @@ public V put(K key, V value) {
*/
@Override
public V get(K key) {
- throw new ExerciseNotCompletedException(); // todo:
+ var index = calculateIndex(requireNonNull(key), table.length);
+ var current = table[index];
+ while (current != null) {
+ if (current.key.equals(key)) {
+ return current.value;
+ }
+ current = current.next;
+ }
+ return null;
}
/**
@@ -82,7 +140,7 @@ public V get(K key) {
*/
@Override
public boolean containsKey(K key) {
- throw new ExerciseNotCompletedException(); // todo:
+ return get(key) != null;
}
/**
@@ -93,9 +151,19 @@ public boolean containsKey(K key) {
*/
@Override
public boolean containsValue(V value) {
- throw new ExerciseNotCompletedException(); // todo:
+ for (var head : table) {
+ var current = head;
+ while (current != null) {
+ if (current.value.equals(value)) {
+ return true;
+ }
+ current = current.next;
+ }
+ }
+ return false;
}
+
/**
* Return a number of elements in the table.
*
@@ -103,7 +171,7 @@ public boolean containsValue(V value) {
*/
@Override
public int size() {
- throw new ExerciseNotCompletedException(); // todo:
+ return size;
}
/**
@@ -113,7 +181,7 @@ public int size() {
*/
@Override
public boolean isEmpty() {
- throw new ExerciseNotCompletedException(); // todo:
+ return size == 0;
}
/**
@@ -124,7 +192,26 @@ public boolean isEmpty() {
*/
@Override
public V remove(K key) {
- throw new ExerciseNotCompletedException(); // todo:
+ var index = calculateIndex(requireNonNull(key), table.length);
+ var current = table[index];
+ if (current != null) {
+ if (current.key.equals(key)) {
+ var value = current.value;
+ table[index] = current.next;
+ size--;
+ return value;
+ }
+ while (current.next != null) {
+ if (current.next.key.equals(key)) {
+ var value = current.next.value;
+ current.next = current.next.next;
+ size--;
+ return value;
+ }
+ current = current.next;
+ }
+ }
+ return null;
}
/**
@@ -150,7 +237,22 @@ public V remove(K key) {
*/
@Override
public String toString() {
- throw new ExerciseNotCompletedException(); // todo:
+ var stringBuilder = new StringBuilder();
+ var n = table.length;
+ for (int i = 0; i < n; i++) { // iterate array
+ stringBuilder.append(i).append(": ");
+ var current = table[i];
+ if (current != null) {
+ while (current.next != null) { // iterate each linked list
+ stringBuilder.append(current.key).append("=").append(current.value).append(" -> ");
+ current = current.next;
+ }
+ stringBuilder.append(current.key).append("=").append(current.value).append("\n");
+ } else {
+ stringBuilder.append("\n");
+ }
+ }
+ return stringBuilder.toString();
}
/**
@@ -160,13 +262,42 @@ public String toString() {
* (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.
+ * PLEASE NOTE that such method should be a part of the implementation details, 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:
+ verifyCapacity(newCapacity);
+ @SuppressWarnings("unchecked") Node[] newTable = new Node[newCapacity];
+ size = 0;
+ for (var head : table) {
+ var current = head;
+ while (current != null) {
+ putOnTable(newTable, current.key, current.value);
+ current = current.next;
+ }
+ }
+ table = newTable;
+ }
+
+ private void verifyCapacity(int capacity) {
+ if (capacity <= 0) {
+ throw new IllegalArgumentException("Capacity (table array size) must be positive");
+ }
}
+
+ @ToString(exclude = "next")
+ public static class Node {
+ T key;
+ V value;
+ Node next;
+
+ public Node(T key, V value) {
+ this.key = key;
+ this.value = value;
+ }
+ }
+
}
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
index b7355496c..1a3565c20 100644
--- 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
@@ -503,10 +503,10 @@ class HashTableHelperMethodsTest {
@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.put("madmax", 833);
+ hashTable.put("altea", 553);
+ hashTable.put("AaAa", 123);
+ hashTable.put("BBBB", 456);
hashTable.resizeTable(16);
@@ -518,6 +518,20 @@ void resizeTable() {
}
@Test
+ @Order(2)
+ @DisplayName("resizeTable does not change the size")
+ void resizeTableDoesNotChangeSize() {
+ hashTable.put("madmax", 833);
+ hashTable.put("altea", 553);
+ hashTable.put("AaAa", 123);
+
+ hashTable.resizeTable(32);
+
+ assertThat(hashTable.size()).isEqualTo(3);
+ }
+
+ @Test
+ @Order(3)
@DisplayName("toString returns a string that represents an underlying table")
void toStringTest() {
addToTable("madmax", 833);
diff --git a/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaderException.java b/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaderException.java
new file mode 100644
index 000000000..19ed36ef6
--- /dev/null
+++ b/3-0-java-core/3-6-1-file-reader/src/main/java/com/bobocode/se/FileReaderException.java
@@ -0,0 +1,7 @@
+package com.bobocode.se;
+
+public class FileReaderException extends RuntimeException {
+ public FileReaderException(String message, Exception e) {
+ super(message, e);
+ }
+}
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
index 6370a3638..1c2f8a54f 100644
--- 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
@@ -1,6 +1,15 @@
package com.bobocode.se;
-import com.bobocode.util.ExerciseNotCompletedException;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.joining;
/**
* {@link FileReaders} provides an API that allow to read whole file into a {@link String} by file name.
@@ -14,6 +23,27 @@ public class FileReaders {
* @return string that holds whole file content
*/
public static String readWholeFile(String fileName) {
- throw new ExerciseNotCompletedException(); //todo
+ Path filePath = createPathFromFileName(fileName);
+ try (Stream fileLinesStream = openFileLinesStream(filePath)) {
+ return fileLinesStream.collect(joining("\n"));
+ }
+ }
+
+ private static Path createPathFromFileName(String fileName) {
+ Objects.requireNonNull(fileName);
+ URL fileUrl = FileReaders.class.getClassLoader().getResource(fileName);
+ try {
+ return Paths.get(fileUrl.toURI());
+ } catch (URISyntaxException e) {
+ throw new FileReaderException("Invalid file URL", e);
+ }
+ }
+
+ private static Stream openFileLinesStream(Path filePath) {
+ try {
+ return Files.lines(filePath);
+ } catch (IOException e) {
+ throw new FileReaderException("Cannot create stream of file lines!", e);
+ }
}
}
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
index 56b4aa596..88dd6a7b6 100644
--- 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
@@ -1,12 +1,28 @@
package com.bobocode.se;
-import com.bobocode.util.ExerciseNotCompletedException;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.counting;
+import static java.util.stream.Collectors.groupingBy;
/**
* {@link FileStats} provides an API that allow to get character statistic based on text file. All whitespace characters
* are ignored.
*/
public class FileStats {
+ private final Map characterCountMap;
+ private final char mostPopularCharacter;
+
/**
* Creates a new immutable {@link FileStats} objects using data from text file received as a parameter.
*
@@ -14,7 +30,47 @@ public class FileStats {
* @return new FileStats object created from text file
*/
public static FileStats from(String fileName) {
- throw new ExerciseNotCompletedException(); //todo
+ return new FileStats(fileName);
+ }
+
+ private FileStats(String fileName) {
+ Path filePath = getFilePath(fileName);
+ characterCountMap = computeCharacterMap(filePath);
+ mostPopularCharacter = findMostPopularCharacter(characterCountMap);
+ }
+
+ private Path getFilePath(String fileName) {
+ Objects.requireNonNull(fileName);
+ URL fileUrl = getFileUrl(fileName);
+ try {
+ return Paths.get(fileUrl.toURI());
+ } catch (URISyntaxException e) {
+ throw new FileStatsException("Wrong file path", e);
+ }
+ }
+
+ private URL getFileUrl(String fileName) {
+ URL fileUrl = getClass().getClassLoader().getResource(fileName);
+ if (fileUrl == null) {
+ throw new FileStatsException("Wrong file path");
+ }
+ return fileUrl;
+ }
+
+ private Map computeCharacterMap(Path filePath) {
+ try (Stream lines = Files.lines(filePath)) {
+ return collectCharactersToCountMap(lines);
+ } catch (IOException e) {
+ throw new FileStatsException("Cannot read the file", e);
+ }
+ }
+
+ private Map collectCharactersToCountMap(Stream linesStream) {
+ return linesStream
+ .flatMapToInt(String::chars)
+ .filter(a -> a != 32) // filter whitespace
+ .mapToObj(c -> (char) c)
+ .collect(groupingBy(identity(), counting()));
}
/**
@@ -24,7 +80,7 @@ public static FileStats from(String fileName) {
* @return a number that shows how many times this character appeared in a text file
*/
public int getCharCount(char character) {
- throw new ExerciseNotCompletedException(); //todo
+ return characterCountMap.get(character).intValue();
}
/**
@@ -33,7 +89,15 @@ public int getCharCount(char character) {
* @return the most frequently appeared character
*/
public char getMostPopularCharacter() {
- throw new ExerciseNotCompletedException(); //todo
+ return mostPopularCharacter;
+ }
+
+ private char findMostPopularCharacter(Map characterCountMap) {
+ return characterCountMap.entrySet()
+ .stream()
+ .max(Comparator.comparing(Map.Entry::getValue))
+ .get()
+ .getKey();
}
/**
@@ -43,6 +107,6 @@ public char getMostPopularCharacter() {
* @return {@code true} if this character has appeared in the text, and {@code false} otherwise
*/
public boolean containsCharacter(char character) {
- throw new ExerciseNotCompletedException(); //todo
+ return characterCountMap.containsKey(character);
}
-}
+}
\ 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
index e213d3f26..b6e1793c6 100644
--- 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
@@ -2,6 +2,7 @@
import com.bobocode.util.ExerciseNotCompletedException;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -21,7 +22,7 @@ public class CrazyRegex {
* @return a pattern that looks for the word "Curiosity"
*/
public Pattern findSpecificWord() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("Curiosity");
}
/**
@@ -30,7 +31,7 @@ public Pattern findSpecificWord() {
* @return a pattern that looks for the first word in text
*/
public Pattern findFirstWord() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("^\\w+");
}
/**
@@ -39,7 +40,7 @@ public Pattern findFirstWord() {
* @return a pattern that looks for the last word in text
*/
public Pattern findLastWord() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\w+$");
}
/**
@@ -50,7 +51,7 @@ public Pattern findLastWord() {
* @return a pattern that looks for numbers
*/
public Pattern findAllNumbers() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\d+");
}
/**
@@ -59,7 +60,7 @@ public Pattern findAllNumbers() {
* @return a pattern that looks for dates
*/
public Pattern findDates() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
}
/**
@@ -69,7 +70,7 @@ public Pattern findDates() {
* @return a pattern that looks for different variations of word "color"
*/
public Pattern findDifferentSpellingsOfColor() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("colou?rs?");
}
/**
@@ -80,7 +81,7 @@ public Pattern findDifferentSpellingsOfColor() {
* @return a pattern that looks for zip codes
*/
public Pattern findZipCodes() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\s\\d{5}\\s");
}
/**
@@ -90,7 +91,7 @@ public Pattern findZipCodes() {
* @return a pattern that looks for different variations of word "link"
*/
public Pattern findDifferentSpellingsOfLink() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("l[yi (]nk");
}
/**
@@ -100,7 +101,7 @@ public Pattern findDifferentSpellingsOfLink() {
* @return a pattern that looks for phone numbers
*/
public Pattern findSimplePhoneNumber() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\d\\d\\d-\\d\\d\\d-\\d\\d\\d\\d");
}
/**
@@ -111,7 +112,7 @@ public Pattern findSimplePhoneNumber() {
* @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();
+ return Pattern.compile("[0-5]{3}");
}
/**
@@ -120,7 +121,7 @@ public Pattern findNumbersFromZeroToFiveWithLengthThree() {
* @return a pattern that looks for the words that have length 5
*/
public Pattern findAllWordsWithFiveLength() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\b[A-Za-z]{5}\\b");
}
/**
@@ -131,7 +132,7 @@ public Pattern findAllWordsWithFiveLength() {
* @return a pattern that looks for words and numbers that not shorter 2 and not longer 3
*/
public Pattern findAllLettersAndDigitsWithLengthThree() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\b\\w{2,3}\\b");
}
/**
@@ -140,7 +141,7 @@ public Pattern findAllLettersAndDigitsWithLengthThree() {
* @return a pattern that looks for the words that begin with capital letter
*/
public Pattern findAllWordsWhichBeginWithCapitalLetter() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\b[A-Z][a-z]*\\b");
}
/**
@@ -150,7 +151,7 @@ public Pattern findAllWordsWhichBeginWithCapitalLetter() {
* @return a pattern that looks for the abbreviations above
*/
public Pattern findAbbreviation() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("A[KLRZ]|C[AOT]|P[RAD]");
}
/**
@@ -159,7 +160,7 @@ public Pattern findAbbreviation() {
* @return a pattern that looks for all open braces
*/
public Pattern findAllOpenBraces() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("(\\{+)");
}
/**
@@ -168,7 +169,7 @@ public Pattern findAllOpenBraces() {
* @return a pattern that looks for everything inside []
*/
public Pattern findOnlyResources() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("(?<=\\[).+?(?=\\])");
}
/**
@@ -177,7 +178,7 @@ public Pattern findOnlyResources() {
* @return a pattern that looks for all https links in note.txt
*/
public Pattern findOnlyLinksInNote() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("https://((www.)?+[\\w]+(.))com");
}
/**
@@ -186,7 +187,7 @@ public Pattern findOnlyLinksInNote() {
* @return a pattern that looks for all http links in nasa.json
*/
public Pattern findOnlyLinksInJson() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("http://(.*)JPG");
}
/**
@@ -195,7 +196,7 @@ public Pattern findOnlyLinksInJson() {
* @return a pattern that looks for all .com, .net and .edu emails
*/
public Pattern findAllEmails() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("[\\w.]+@[\\w]+\\.(net|com|edu)");
}
/**
@@ -207,7 +208,7 @@ public Pattern findAllEmails() {
* @return a pattern that looks for phone numbers patterns above
*/
public Pattern findAllPatternsForPhoneNumbers() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\(?\\d{3}[-.)]\\d{3}[-.]\\d{4}");
}
/**
@@ -216,7 +217,7 @@ public Pattern findAllPatternsForPhoneNumbers() {
* @return a pattern that looks for duplicates
*/
public Pattern findOnlyDuplicates() {
- throw new ExerciseNotCompletedException();
+ return Pattern.compile("\\b(\\w+)\\s\\1\\b");
}
/**
@@ -227,7 +228,8 @@ public Pattern findOnlyDuplicates() {
* @return String where all names recorded as last name first name
*/
public String replaceFirstAndLastNames(String names) {
- throw new ExerciseNotCompletedException();
+ Matcher matcher = Pattern.compile("(\\w+),\\s+(\\w+)").matcher(names);
+ return matcher.replaceAll("$2 $1");
}
/**
@@ -238,7 +240,8 @@ public String replaceFirstAndLastNames(String names) {
* @return String where in all phone numbers last 7 digits replaced to X
*/
public String replaceLastSevenDigitsOfPhoneNumberToX(String phones) {
- throw new ExerciseNotCompletedException();
+ Matcher matcher = Pattern.compile("\\(?(\\d{3})[-.)]\\d{3}[-.]\\d{4}").matcher(phones);
+ return matcher.replaceAll("$1-XXX-XXXX");
}
/**
@@ -250,6 +253,7 @@ public String replaceLastSevenDigitsOfPhoneNumberToX(String phones) {
* @return String where all resources embraced in href
*/
public String insertLinksAndResourcesIntoHref(String links) {
- throw new ExerciseNotCompletedException();
+ Matcher matcher = Pattern.compile("\\[(.*?)]\\((http.*?)\\)").matcher(links);
+ return matcher.replaceAll("$1 ");
}
}
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..630b21c67 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,12 @@
package com.bobocode.se;
-import com.bobocode.util.ExerciseNotCompletedException;
+import static java.util.Objects.requireNonNull;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
import java.util.Comparator;
+import java.util.Objects;
+import lombok.SneakyThrows;
/**
* A generic comparator that is comparing a random field of the given class. The field is either primitive or
@@ -18,13 +23,17 @@
*/
public class RandomFieldComparator implements Comparator {
+ private final Class targetType;
+ private final Field fieldToCompare;
+
public RandomFieldComparator(Class targetType) {
- throw new ExerciseNotCompletedException(); // todo: implement this constructor;
+ this.targetType = requireNonNull(targetType);
+ this.fieldToCompare = chooseFieldToCompare(targetType);
}
/**
* 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.
+ * for the fields, and it treats null value grater than a non-null value.
*
* @param o1
* @param o2
@@ -34,14 +43,16 @@ public RandomFieldComparator(Class targetType) {
*/
@Override
public int compare(T o1, T o2) {
- throw new ExerciseNotCompletedException(); // todo: implement this method;
+ Objects.requireNonNull(o1);
+ Objects.requireNonNull(o2);
+ return compareFieldValues(o1, o2);
}
/**
* Returns the name of the randomly-chosen comparing field.
*/
public String getComparingFieldName() {
- throw new ExerciseNotCompletedException(); // todo: implement this method;
+ return fieldToCompare.getName();
}
/**
@@ -52,6 +63,23 @@ public String getComparingFieldName() {
*/
@Override
public String toString() {
- throw new ExerciseNotCompletedException(); // todo: implement this method;
+ return String.format("Random field comparator of class '%s' is comparing '%s'", targetType.getSimpleName(),
+ getComparingFieldName());
+ }
+
+ private Field chooseFieldToCompare(Class targetType) {
+ return Arrays.stream(targetType.getDeclaredFields())
+ .filter(f -> Comparable.class.isAssignableFrom(f.getType()) || f.getType().isPrimitive())
+ .findAny().orElseThrow(() -> new IllegalArgumentException("There are no fields available to compare"));
+ }
+
+ @SneakyThrows
+ @SuppressWarnings("unchecked")
+ private > int compareFieldValues(T o1, T o2) {
+ fieldToCompare.setAccessible(true);
+ var value1 = (U) fieldToCompare.get(o1);
+ var value2 = (U) fieldToCompare.get(o2);
+ Comparator comparator = Comparator.nullsLast(Comparator.naturalOrder());
+ return comparator.compare(value1, value2);
}
}
diff --git a/3-0-java-core/3-6-4-random-field-comparator/src/test/java/com/bobocode/se/RandomFieldComparatorTest.java b/3-0-java-core/3-6-4-random-field-comparator/src/test/java/com/bobocode/se/RandomFieldComparatorTest.java
index 469f30cd8..1733568e5 100644
--- a/3-0-java-core/3-6-4-random-field-comparator/src/test/java/com/bobocode/se/RandomFieldComparatorTest.java
+++ b/3-0-java-core/3-6-4-random-field-comparator/src/test/java/com/bobocode/se/RandomFieldComparatorTest.java
@@ -82,7 +82,7 @@ void compareWhenFieldValuesOfSecondObjectIsNull() {
@Order(7)
@SneakyThrows
@DisplayName("Method 'compare' returns positive int when the first value is greater")
- void compareWhenFieldValueOfFirstObjectIsGreater() {
+ void compareWhenFieldValueOfFirstObjectIsGrater() {
var fieldToCompareName = "firstName";
Account account1 = new Account();
Account account2 = new Account();
@@ -102,7 +102,7 @@ void compareWhenFieldValueOfFirstObjectIsGreater() {
@Order(8)
@SneakyThrows
@DisplayName("Method 'compare' returns negative int when the first value is smaller")
- void compareWhenFieldValueOfSecondObjectIsGreater() {
+ void compareWhenFieldValueOfSecondObjectIsGrater() {
var fieldToCompareName = "firstName";
Account account1 = new Account();
Account account2 = new Account();
@@ -142,7 +142,7 @@ void compareWhenFieldValuesOfObjectsAreEqual() {
@Order(10)
@SneakyThrows
@DisplayName("Method 'compare' returns positive int when the first primitive value is greater")
- void comparePrimitivesWhenFieldValueOfFirstObjectIsGreater() {
+ void comparePrimitivesWhenFieldValueOfFirstObjectIsGrater() {
var fieldToCompareName = "age";
Account account1 = new Account();
Account account2 = new Account();
@@ -182,7 +182,7 @@ void comparePrimitivesWhenFieldValuesOfObjectsAreEqual() {
@Order(12)
@SneakyThrows
@DisplayName("Method 'compare' returns negative int when the first primitive value is smaller")
- void comparePrimitivesWhenFieldValueOfSecondObjectIsGreater() {
+ void comparePrimitivesWhenFieldValueOfSecondObjectIsGrater() {
var fieldToCompareName = "age";
Account account1 = new Account();
Account account2 = new Account();
diff --git a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/FlightDao.java b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/FlightDao.java
index 3e58c3b33..6865612f7 100644
--- a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/FlightDao.java
+++ b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/data/FlightDao.java
@@ -1,6 +1,6 @@
package com.bobocode.oop.data;
-import com.bobocode.util.ExerciseNotCompletedException;
+import com.bobocode.oop.service.Flights;
import java.util.HashSet;
import java.util.Set;
@@ -12,7 +12,7 @@
* todo: 1. Implement a method {@link FlightDao#register(String)} that store new flight number into the set
* todo: 2. Implement a method {@link FlightDao#findAll()} that returns a set of all flight numbers
*/
-public class FlightDao {
+public class FlightDao implements Flights {
private Set flights = new HashSet<>();
/**
@@ -22,7 +22,7 @@ public class FlightDao {
* @return {@code true} if a flight number was stored, {@code false} otherwise
*/
public boolean register(String flightNumber) {
- throw new ExerciseNotCompletedException();// todo: implement this method
+ return flights.add(flightNumber);
}
/**
@@ -31,7 +31,6 @@ public boolean register(String flightNumber) {
* @return a set of flight numbers
*/
public Set findAll() {
- throw new ExerciseNotCompletedException();// todo: implement this method
+ return flights;
}
-
}
diff --git a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/factory/FlightServiceFactory.java b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/factory/FlightServiceFactory.java
index 8cd2ed673..f7568b934 100644
--- a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/factory/FlightServiceFactory.java
+++ b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/factory/FlightServiceFactory.java
@@ -1,7 +1,7 @@
package com.bobocode.oop.factory;
+import com.bobocode.oop.data.FlightDao;
import com.bobocode.oop.service.FlightService;
-import com.bobocode.util.ExerciseNotCompletedException;
/**
* {@link FlightServiceFactory} is used to create an instance of {@link FlightService}
@@ -16,6 +16,6 @@ public class FlightServiceFactory {
* @return FlightService
*/
public FlightService creteFlightService() {
- throw new ExerciseNotCompletedException();
+ return new FlightService(new FlightDao());
}
}
diff --git a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/FlightService.java b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/FlightService.java
index b31cd8f07..9b420412a 100644
--- a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/FlightService.java
+++ b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/FlightService.java
@@ -1,9 +1,9 @@
package com.bobocode.oop.service;
-import com.bobocode.util.ExerciseNotCompletedException;
-
import java.util.List;
+import static java.util.stream.Collectors.toList;
+
/**
* {@link FlightService} provides an API that allows to manage flight numbers
*
@@ -12,6 +12,12 @@
*/
public class FlightService {
+ private Flights flights;
+
+ public FlightService(Flights flights) {
+ this.flights = flights;
+ }
+
/**
* Adds a new flight number
*
@@ -19,7 +25,7 @@ public class FlightService {
* @return {@code true} if a flight number was added, {@code false} otherwise
*/
public boolean registerFlight(String flightNumber) {
- throw new ExerciseNotCompletedException();
+ return flights.register(flightNumber);
}
/**
@@ -29,6 +35,8 @@ public boolean registerFlight(String flightNumber) {
* @return a list of found flight numbers
*/
public List searchFlights(String query) {
- throw new ExerciseNotCompletedException();
+ return flights.findAll().stream()
+ .filter(flightNum -> flightNum.toUpperCase().contains(query.toUpperCase()))
+ .collect(toList());
}
}
diff --git a/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/Flights.java b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/Flights.java
new file mode 100644
index 000000000..be6793a19
--- /dev/null
+++ b/4-0-object-oriented-programming/4-3-1-flight-search/src/main/java/com/bobocode/oop/service/Flights.java
@@ -0,0 +1,9 @@
+package com.bobocode.oop.service;
+
+import java.util.Set;
+
+public interface Flights {
+ boolean register(String flightNumber);
+
+ Set findAll();
+}
diff --git a/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/FunctionMap.java b/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/FunctionMap.java
index 446b9d27e..680a7d956 100644
--- a/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/FunctionMap.java
+++ b/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/FunctionMap.java
@@ -1,7 +1,6 @@
package com.bobocode.fp;
import com.bobocode.fp.exception.InvalidFunctionNameException;
-
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
diff --git a/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/Functions.java b/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/Functions.java
index a1eed08d4..a07723fc2 100644
--- a/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/Functions.java
+++ b/5-0-functional-programming/5-0-1-lambda-functions-map/src/main/java/com/bobocode/fp/Functions.java
@@ -1,5 +1,7 @@
package com.bobocode.fp;
+import static java.lang.Math.abs;
+
/**
* An util class that provides a factory method for creating an instance of a {@link FunctionMap} filled with a list
* of functions.
@@ -28,7 +30,11 @@ private Functions() {
public static FunctionMap intFunctionMap() {
FunctionMap intFunctionMap = new FunctionMap<>();
- // todo: according to the javadoc add functions using lambda expression
+ intFunctionMap.addFunction("square", n -> n * n);
+ intFunctionMap.addFunction("abs", Math::abs);
+ intFunctionMap.addFunction("increment", n -> n + 1);
+ intFunctionMap.addFunction("decrement", n -> n - 1);
+ intFunctionMap.addFunction("sgn", n -> (n != 0) ? n / abs(n) : 0);
return intFunctionMap;
}
diff --git a/5-0-functional-programming/5-0-2-stream-sum-of-squares/src/main/java/com/bobocode/fp/SumOfSquares.java b/5-0-functional-programming/5-0-2-stream-sum-of-squares/src/main/java/com/bobocode/fp/SumOfSquares.java
index b043454d1..06f8e214b 100644
--- a/5-0-functional-programming/5-0-2-stream-sum-of-squares/src/main/java/com/bobocode/fp/SumOfSquares.java
+++ b/5-0-functional-programming/5-0-2-stream-sum-of-squares/src/main/java/com/bobocode/fp/SumOfSquares.java
@@ -2,6 +2,8 @@
import com.bobocode.fp.exception.InvalidRangeException;
+import java.util.stream.IntStream;
+
/**
* This class allow to calculate a sum of squares of integer number in a certain range. It was implemented using
* OO approach. Your job is to refactor it using functional approach. E.g. avoid using mutable variables
@@ -25,11 +27,8 @@ static int calculateSumOfSquaresInRange(int startInclusive, int endInclusive) {
throw new InvalidRangeException();
}
- // todo: refactor using functional approach – instead of using for loop, use IntStream.rangeClose()
- int sumOfSquares = 0;
- for (int i = startInclusive; i <= endInclusive; i++) {
- sumOfSquares += i * i;
- }
- return sumOfSquares;
+ return IntStream.rangeClosed(startInclusive, endInclusive)
+ .map(a -> a * a)
+ .sum();
}
}
diff --git a/5-0-functional-programming/5-1-1-crazy-lambdas/src/main/java/com/bobocode/fp/CrazyLambdas.java b/5-0-functional-programming/5-1-1-crazy-lambdas/src/main/java/com/bobocode/fp/CrazyLambdas.java
index 78feebde2..4f9810273 100644
--- a/5-0-functional-programming/5-1-1-crazy-lambdas/src/main/java/com/bobocode/fp/CrazyLambdas.java
+++ b/5-0-functional-programming/5-1-1-crazy-lambdas/src/main/java/com/bobocode/fp/CrazyLambdas.java
@@ -5,6 +5,7 @@
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Map;
+import java.util.concurrent.ThreadLocalRandom;
import java.util.function.*;
/**
@@ -27,7 +28,8 @@ public class CrazyLambdas {
* @return a string supplier
*/
public static Supplier helloSupplier() {
- throw new ExerciseNotCompletedException();
+ // because supplier method has NO PARAMETERS, a lambda starts with empty brackets
+ return () -> "Hello";
}
/**
@@ -36,7 +38,9 @@ public static Supplier helloSupplier() {
* @return a string predicate
*/
public static Predicate isEmptyPredicate() {
- throw new ExerciseNotCompletedException();
+ // have a string parameter we can call isEmpty() and return result, e.g `str -> str.isEmpty()`
+ // so if we only call a method, it's better to provide a reference to that method instead of lambda expression
+ return String::isEmpty;
}
/**
@@ -46,7 +50,11 @@ public static Predicate isEmptyPredicate() {
* @return function that repeats Strings
*/
public static BiFunction stringMultiplier() {
- throw new ExerciseNotCompletedException();
+ // Bi means two parameters (str, n), and we can implement this method using a lambda with two params
+ // e.g. `(str, n) -> str.repeat(n)`, however in this case it's also better to provide a reference instead.
+ // BiFunction method `apply` has two params, and String method `repeat` has only one, but when you use a static
+ // method reference to a non-static method it's first parameter becomes `this`
+ return String::repeat;
}
/**
@@ -56,7 +64,8 @@ public static BiFunction stringMultiplier() {
* @return function that converts adds dollar sign
*/
public static Function toDollarStringFunction() {
- throw new ExerciseNotCompletedException();
+ // Function is a classic lambda, where parameter and return types are different
+ return val -> "$" + val;
}
/**
@@ -68,7 +77,11 @@ public static Function toDollarStringFunction() {
* @return a string predicate
*/
public static Predicate lengthInRangePredicate(int min, int max) {
- throw new ExerciseNotCompletedException();
+ // A lambda has one string parameter and we need to compare its length with provided min and max values.
+ // Please note, that `min` and `max` must be "effectively final" if we want to use them in lambda expression.
+ // Try to uncomment the line below
+ // min = 1;
+ return str -> str.length() >= min && str.length() < max;
}
/**
@@ -77,7 +90,8 @@ public static Predicate lengthInRangePredicate(int min, int max) {
* @return int supplier
*/
public static IntSupplier randomIntSupplier() {
- throw new ExerciseNotCompletedException();
+ // This is a special Supplier for int primitive. Its method has no arguments and supplies an int value.
+ return () -> ThreadLocalRandom.current().nextInt();
}
@@ -87,7 +101,9 @@ public static IntSupplier randomIntSupplier() {
* @return int operation
*/
public static IntUnaryOperator boundedRandomIntSupplier() {
- throw new ExerciseNotCompletedException();
+ // IntUnaryOperator is just an UnaryOperator for int primitives. Its method accepts int and returns int.
+ // So a parameter is a bound that should be used when generating a random integer
+ return bound -> ThreadLocalRandom.current().nextInt(bound);
}
/**
@@ -96,7 +112,8 @@ public static IntUnaryOperator boundedRandomIntSupplier() {
* @return square operation
*/
public static IntUnaryOperator intSquareOperation() {
- throw new ExerciseNotCompletedException();
+ // a classical example of lambda, we use parameter and return its square
+ return x -> x * x;
}
/**
@@ -105,7 +122,9 @@ public static IntUnaryOperator intSquareOperation() {
* @return binary sum operation
*/
public static LongBinaryOperator longSumOperation() {
- throw new ExerciseNotCompletedException();
+ // LongBinaryOperator is a binary operator for long primitive.
+ // It can be done using lambda with two params like `(a, b) -> a + b` but it's better to use method reference
+ return Long::sum;
}
/**
@@ -114,7 +133,9 @@ public static LongBinaryOperator longSumOperation() {
* @return string to int converter
*/
public static ToIntFunction stringToIntConverter() {
- throw new ExerciseNotCompletedException();
+ // ToIntFunction is a special form of Function that returns an int primitive. In this case we also use a simple
+ // method reference instead of a longer lambda `str -> Integer.parseInt(str)`
+ return Integer::parseInt;
}
/**
@@ -125,7 +146,11 @@ public static ToIntFunction stringToIntConverter() {
* @return a function supplier
*/
public static Supplier nMultiplyFunctionSupplier(int n) {
- throw new ExerciseNotCompletedException();
+ // As you can see we have Supplier that supplies IntUnaryOperator, which means we'll need a nested lambda.
+ // If it looks complex, you can start by implementing an inner lambda which is `x -> n * x`. Then on top of that
+ // you just need to implement a supplier that supplies that lambda above.
+ // Or you can start by implementing a supplier like `() -> ...` and then add inner lambda instead of three dots.
+ return () -> x -> n * x;
}
/**
@@ -134,7 +159,13 @@ public static Supplier nMultiplyFunctionSupplier(int n) {
* @return function that composes functions with trim() function
*/
public static UnaryOperator> composeWithTrimFunction() {
- throw new ExerciseNotCompletedException();
+ // UnaryOperator has the same parameter and return type. In our case it's a function. So our job is to use
+ // that function and compose it with another function called `trim`
+ // As you can see Function provides some additional default methods, and one of them is `compose`.
+ // So we have one parameter and we'll call compose, like `strFunction -> strFunction.compose(...)` then
+ // instead of three dots, we need to pass another function(lambda) trim, you can pass `s -> s.trim()`, or just
+ // use a method reference to `trim`
+ return strFunction -> strFunction.compose(String::trim);
}
/**
@@ -145,7 +176,16 @@ public static UnaryOperator> composeWithTrimFunction()
* @return a thread supplier
*/
public static Supplier runningThreadSupplier(Runnable runnable) {
- throw new ExerciseNotCompletedException();
+ // Having a runnable you can create and start a thread. And in this case you need to implement a supplier that
+ // will supply this running thread. The main point is that THREAD WON'T BE CREATED AND STARTED until
+ // method `get` of the supplier is called.
+ // In this case you need to do multiple operations like create thread, call start and return it, so we need to
+ // use lambda body with curly brackets and return statement
+ return () -> {
+ Thread t = new Thread(runnable);
+ t.start();
+ return t;
+ };
}
/**
@@ -154,7 +194,10 @@ public static Supplier runningThreadSupplier(Runnable runnable) {
* @return a runnable consumer
*/
public static Consumer newThreadRunnableConsumer() {
- throw new ExerciseNotCompletedException();
+ // In this case runnable is a parameter of a Consumer method. We use that parameter to create Thread
+ // and start it. Since consumer does not return any value (void), we call method `start` right within
+ // lambda expression. (Method `start` also returns `void`)
+ return runnable -> new Thread(runnable).start();
}
/**
@@ -164,7 +207,13 @@ public static Consumer newThreadRunnableConsumer() {
* @return a function that transforms runnable into a thread supplier
*/
public static Function> runnableToThreadSupplierFunction() {
- throw new ExerciseNotCompletedException();
+ // This method is very similar to `runningThreadSupplier`. But in this case we should implement a function
+ // that accepts a runnable and then does exactly what we did before in `runningThreadSupplier`.
+ return runnable -> () -> {
+ Thread t = new Thread(runnable);
+ t.start();
+ return t;
+ };
}
/**
@@ -177,7 +226,13 @@ public static Function> runnableToThreadSupplierFunct
* @return a binary function that receiver predicate and function and compose them to create a new function
*/
public static BiFunction functionToConditionalFunction() {
- throw new ExerciseNotCompletedException();
+ // BiFunction accepts two parameters, so you can start from implementing this part
+ // `(intFunction, condition) -> ...` then the return type is `IntUnaryOperator`, and in order to implement
+ // this result `IntUnaryOperator` we need a lambda with parameter e.g. `x`, so we can add it like
+ // `(intFunction, condition) -> x -> ...`. Now we should check the condition for `x`
+ // `(intFunction, condition) -> x -> condition.test(x) ? ...` if it's true, we call provided `intFunction`
+ // and return result, otherwise we just return `x`
+ return (intFunction, condition) -> x -> condition.test(x) ? intFunction.applyAsInt(x) : x;
}
/**
@@ -188,7 +243,11 @@ public static BiFunction funct
* @return a high-order function that fetches a function from a function map by a given name or returns identity()
*/
public static BiFunction, String, IntUnaryOperator> functionLoader() {
- throw new ExerciseNotCompletedException();
+ // This BiFunction accepts a map of functions and a function name, so we start form this
+ // `(functionMap, functionName) -> ...` then using a name we need to extract a function from map and return it
+ // or return `IntUnaryOperator.identity()` if no function was found. For this use case there is a default method
+ // of a class `Map` called `getOrDefault`
+ return (functionMap, functionName) -> functionMap.getOrDefault(functionName, IntUnaryOperator.identity());
}
/**
@@ -206,7 +265,7 @@ public static BiFunction, String, IntUnaryOperator
* @return a comparator instance
*/
public static > Comparator comparing(Function super T, ? extends U> mapper) {
- throw new ExerciseNotCompletedException();
+ return (o1, o2) -> mapper.apply(o1).compareTo(mapper.apply(o2));
}
/**
@@ -226,7 +285,13 @@ public static > Comparator comparing(Funct
*/
public static > Comparator thenComparing(
Comparator super T> comparator, Function super T, ? extends U> mapper) {
- throw new ExerciseNotCompletedException();
+ return (o1, o2) -> {
+ var initialResult = comparator.compare(o1, o2);
+ if (initialResult != 0) {
+ return initialResult;
+ }
+ return mapper.apply(o1).compareTo(mapper.apply(o2));
+ };
}
/**
@@ -235,7 +300,8 @@ public static > Comparator thenComparing(
* @return a supplier instance
*/
public static Supplier>> trickyWellDoneSupplier() {
- throw new ExerciseNotCompletedException();
+ // You just need to create a couple of nested lambdas like `() -> () -> ...`
+ return () -> () -> () -> "WELL DONE!";
}
}
diff --git a/5-0-functional-programming/5-2-1-crazy-streams/src/main/java/com/bobocode/fp/CrazyStreams.java b/5-0-functional-programming/5-2-1-crazy-streams/src/main/java/com/bobocode/fp/CrazyStreams.java
index 40ffc170f..4b60c0c13 100644
--- a/5-0-functional-programming/5-2-1-crazy-streams/src/main/java/com/bobocode/fp/CrazyStreams.java
+++ b/5-0-functional-programming/5-2-1-crazy-streams/src/main/java/com/bobocode/fp/CrazyStreams.java
@@ -1,12 +1,18 @@
package com.bobocode.fp;
import com.bobocode.model.Account;
-import com.bobocode.util.ExerciseNotCompletedException;
+import com.bobocode.model.Sex;
+import com.bobocode.fp.exception.EntityNotFoundException;
import lombok.AllArgsConstructor;
import java.math.BigDecimal;
import java.time.Month;
import java.util.*;
+import java.util.stream.Stream;
+
+import static java.util.Comparator.comparing;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.*;
/**
* {@link CrazyStreams} is an exercise class. Each method represent some operation with a collection of accounts that
@@ -30,7 +36,8 @@ public class CrazyStreams {
* @return account with max balance wrapped with optional
*/
public Optional findRichestPerson() {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .max(comparing(Account::getBalance));
}
/**
@@ -40,7 +47,9 @@ public Optional findRichestPerson() {
* @return a list of accounts
*/
public List findAccountsByBirthdayMonth(Month birthdayMonth) {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .filter(a -> a.getBirthday().getMonth().equals(birthdayMonth))
+ .collect(toList());
}
/**
@@ -50,7 +59,8 @@ public List findAccountsByBirthdayMonth(Month birthdayMonth) {
* @return a map where key is true or false, and value is list of male, and female accounts
*/
public Map> partitionMaleAccounts() {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .collect(partitioningBy(a -> a.getSex().equals(Sex.MALE)));
}
/**
@@ -60,7 +70,8 @@ public Map> partitionMaleAccounts() {
* @return a map where key is an email domain and value is a list of all account with such email
*/
public Map> groupAccountsByEmailDomain() {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .collect(groupingBy(a -> a.getEmail().split("@")[1]));
}
/**
@@ -69,7 +80,9 @@ public Map> groupAccountsByEmailDomain() {
* @return total number of letters of first and last names of all accounts
*/
public int getNumOfLettersInFirstAndLastNames() {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .mapToInt(a -> a.getFirstName().length() + a.getLastName().length())
+ .sum();
}
/**
@@ -78,7 +91,9 @@ public int getNumOfLettersInFirstAndLastNames() {
* @return total balance of all accounts
*/
public BigDecimal calculateTotalBalance() {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .map(Account::getBalance)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
}
/**
@@ -87,7 +102,10 @@ public BigDecimal calculateTotalBalance() {
* @return list of accounts sorted by first and last names
*/
public List sortByFirstAndLastNames() {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .sorted(comparing(Account::getFirstName)
+ .thenComparing(Account::getLastName))
+ .collect(toList());
}
/**
@@ -97,7 +115,9 @@ public List sortByFirstAndLastNames() {
* @return true if there is an account that has an email with provided domain
*/
public boolean containsAccountWithEmailDomain(String emailDomain) {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .map(Account::getEmail)
+ .anyMatch(email -> email.split("@")[1].equals(emailDomain));
}
/**
@@ -108,7 +128,11 @@ public boolean containsAccountWithEmailDomain(String emailDomain) {
* @return account balance
*/
public BigDecimal getBalanceByEmail(String email) {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .filter(account -> account.getEmail().equals(email))
+ .findFirst()
+ .map(Account::getBalance)
+ .orElseThrow(() -> new EntityNotFoundException(String.format("Cannot find Account by email=%s", email)));
}
/**
@@ -117,7 +141,8 @@ public BigDecimal getBalanceByEmail(String email) {
* @return map of accounts by its ids
*/
public Map collectAccountsById() {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .collect(toMap(Account::getId, identity()));
}
/**
@@ -128,17 +153,20 @@ public Map collectAccountsById() {
* @return map of account by its ids the were created in a particular year
*/
public Map collectBalancesByEmailForAccountsCreatedOn(int year) {
- throw new ExerciseNotCompletedException();
+ return accounts.stream()
+ .filter(account -> account.getCreationDate().getYear() == year)
+ .collect(toMap(Account::getEmail, Account::getBalance));
}
/**
* Returns a {@link Map} where key is {@link Account#lastName} and values is a {@link Set} that contains first names
* of all accounts with a specific last name.
*
- * @return a map where key is a last name and value is a set of first names
+ * @return a map where key is a first name and value is a set of first names
*/
public Map