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..9bcbab4d4 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 @@ -2,44 +2,14 @@ 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(); + return "The key to efficient learning is practice!"; } - /** - * 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 index 093909fe9..69b19ea6d 100644 --- a/0-0-intro/src/test/java/com/bobocode/intro/ExerciseIntroductionTest.java +++ b/0-0-intro/src/test/java/com/bobocode/intro/ExerciseIntroductionTest.java @@ -1,51 +1,2 @@ -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"); - } +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 . * 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..ac490bb61 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 @@ -1,24 +1,18 @@ package com.bobocode.basics; -/** - * {@link Box} is a container class that can store a value of any given type. Using Object as a field type - * is flexible, because we can store anything we want there. But it is not safe, because it requires runtime casting - * and there is no guarantee that we know the type of the stored value. - *

- * 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..8f10455fa 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 @@ -1,21 +1,15 @@ package com.bobocode.basics; -/** - * This demo demonstrates why using Object is not safe. It's not safe because runtime casting can cause runtime - * exceptions. We should always fail as soon as possible. So in this code we should not allow setting String - * value at compile time, if we expect to work with integers. - *

- * todo: refactor class {@link Box} to make type parameterization safe and make this demo fail at compile time - */ 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(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"); // ❌ Тепер так не можна + + System.out.println(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..d67c04b8c 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,235 +1,181 @@ 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 - * using generics. - *

- * TODO: go step by step from top to bottom. Read the java doc, write code and run CrazyGenericsTest to verify your impl - *

- * Hint: in some cases you will need to refactor the code, like replace {@link Object} with a generic type. In order - * cases you will need to add new fields, create new classes, or add new methods. Always try to read java doc and update - * the code according to it. - *

- * TODO: to get the most out of your learning, visit our website - *

- * - * @author Taras Boychuk + * {@link CrazyGenerics} is an exercise class with generics refactoring. */ + public class CrazyGenerics { + /** - * {@link Sourced} is a container class that allows storing any object along with the source of that data. - * The value type can be specified by a type parameter "T". - * - * @param – value type + * Sourced: container for any value with its source. */ - @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; + + public Sourced(T value, String source) { + this.value = value; + this.source = source; + } + + public T getValue() { + return value; + } + + public void setValue(T value) { + this.value = value; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } } /** - * {@link Limited} is a container class that allows storing an actual value along with possible min and max values. - * It is special form of triple. All three values have a generic type that should be a subclass of {@link Number}. - * - * @param – actual, min and max type + * Limited: container for a number with min/max values. */ - @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; + + public Limited(T actual, T min, T max) { + this.actual = actual; + this.min = min; + this.max = max; + } + + public T getActual() { + return actual; + } + + public T getMin() { + return min; + } + + public T getMax() { + return max; + } } /** - * {@link Converter} interface declares a typical contract of a converter. It works with two independent generic types. - * It defines a convert method which accepts one parameter of one type and returns a converted result of another type. - * - * @param – source object type - * @param - converted result type + * Converter: convert from T to R. */ - public interface Converter { // todo: introduce type parameters - // todo: add convert method + public interface Converter { + R convert(T source); } /** - * {@link MaxHolder} is a container class that keeps track of the maximum value only. It works with comparable objects - * and allows you to put new values. Every time you put a value, it is stored only if the new value is greater - * than the current max. - * - * @param – value type + * MaxHolder: keeps track of maximum Comparable value. */ - public static class MaxHolder { // todo: refactor class to make it generic - private Object max; + public static class MaxHolder> { + private T max; - public MaxHolder(Object max) { + public MaxHolder(T max) { this.max = max; } - /** - * Puts a new value to the holder. A new value is stored to the max, only if it is greater than current max value. - * - * @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 (max == null || val.compareTo(max) > 0) { + max = val; + } } - public Object getMax() { + public T getMax() { return max; } } /** - * {@link StrictProcessor} defines a contract of a processor that can process only objects that are {@link Serializable} - * and {@link Comparable}. - * - * @param – the type of objects that can be processed + * StrictProcessor: processes only Serializable & Comparable objects. */ - interface StrictProcessor { // todo: make it generic - void process(Object obj); + interface StrictProcessor> { + void process(T obj); } /** - * {@link CollectionRepository} defines a contract of a runtime store for entities based on any {@link Collection}. - * It has methods that allow to save new entity, and get whole collection. - * - * @param – a type of the entity that should be a subclass of {@link BaseEntity} - * @param – a type of any collection + * CollectionRepository: store entities in any collection. */ - interface CollectionRepository { // todo: update interface according to the javadoc - void save(Object entity); + interface CollectionRepository> { + void save(T entity); - Collection getEntityCollection(); + C getEntityCollection(); } /** - * {@link ListRepository} extends {@link CollectionRepository} but specifies the underlying collection as - * {@link java.util.List}. - * - * @param – a type of the entity that should be a subclass of {@link BaseEntity} + * ListRepository: repository specialized for List. */ - interface ListRepository { // todo: update interface according to the javadoc + interface ListRepository extends CollectionRepository> { } /** - * {@link ComparableCollection} is a {@link Collection} that can be compared by size. It extends a {@link Collection} - * interface and {@link Comparable} interface, and provides a default implementation of a compareTo method that - * compares collections sizes. - *

- * Please note that size does not depend on the elements type, so it is allowed to compare collections of different - * element types. - * - * @param a type of collection elements + * ComparableCollection: compares by size. */ - 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. + * CollectionUtil: utility methods for collections. */ static class CollectionUtil { - static final Comparator CREATED_ON_COMPARATOR = Comparator.comparing(BaseEntity::getCreatedOn); - - /** - * An util method that allows to print a dashed list of elements - * - * @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)); - } - - /** - * Util method that check if provided collection has new entities. An entity is any object - * that extends {@link BaseEntity}. A new entity is an entity that does not have an id assigned. - * (In other word, which id value equals null). - * - * @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 - } - - /** - * Util method that checks if a provided collection of entities is valid. An entity is any subclass of - * a {@link BaseEntity} A validation criteria can be different for different cases, so it is passed - * as second parameter. - * - * @param entities provided collection of 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 - } - - /** - * hasDuplicates is a generic util method checks if a list of entities contains target entity more than once. - * In other words, it checks if target entity has duplicates in the provided list. A duplicate is an entity that - * has the same UUID. - * - * @param entities given list of entities - * @param targetEntity a target entity - * @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 - } - - /** - * findMax is a generic util method that accepts an {@link Iterable} and {@link Comparator} and returns an - * optional object, that has maximum "value" based on the given comparator. - * - * @param elements provided iterable of elements - * @param comparator an object that will be used to compare elements - * @param type of elements - * @return optional max value - */ - // todo: create a method and implement its logic manually without using util method from JDK - - /** - * findMostRecentlyCreatedEntity is a generic util method that accepts a collection of entities and returns the - * one that is the most recently created. If collection is empty, - * it throws {@link java.util.NoSuchElementException}. - *

- * This method reuses findMax method and passes entities along with prepare comparator instance, - * that is stored as constant CREATED_ON_COMPARATOR. - * - * @param entities provided collection of entities - * @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 - - /** - * An util method that allows to swap two elements of any list. It changes the list so the element with the index - * i will be located on index j, and the element with index j, will be located on the index i. - * Please note that in order to make it convenient and simple, it DOES NOT declare any type parameter. - * - * @param elements a list of any given type - * @param i index of the element to swap - * @param j index of the other element to swap - */ - public static void swap(List elements, int i, int j) { + + static final Comparator CREATED_ON_COMPARATOR = + Comparator.comparing(BaseEntity::getCreatedOn); + + public static void print(List list) { + list.forEach(e -> System.out.println(" – " + e)); + } + + public static boolean hasNewEntities(Collection entities) { + return entities.stream().anyMatch(e -> e.getId() == null); + } + + public static boolean isValidCollection(Collection entities, Predicate validationPredicate) { + return entities.stream().allMatch(validationPredicate); + } + + public static boolean hasDuplicates(List entities, T targetEntity) { + return entities.stream().filter(e -> e.getUuid().equals(targetEntity.getUuid())).count() > 1; + } + + public static Optional findMax(Iterable elements, Comparator comparator) { + Iterator it = elements.iterator(); + if (!it.hasNext()) return Optional.empty(); + T max = it.next(); + while (it.hasNext()) { + T current = it.next(); + if (comparator.compare(current, max) > 0) { + max = current; + } + } + return Optional.of(max); + } + + public static T findMostRecentlyCreatedEntity(Collection entities) { + return findMax(entities, CREATED_ON_COMPARATOR) + .orElseThrow(NoSuchElementException::new); + } + + 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 + T tmp = elements.get(i); + elements.set(i, elements.get(j)); + elements.set(j, tmp); } - } }