├── .gitignore ├── README.md ├── account-analytics ├── README.MD ├── pom.xml └── src │ ├── main │ └── java │ │ └── com.bobocode │ │ ├── AccountAnalytics.java │ │ └── exception │ │ └── EntityNotFoundException.java │ └── test │ └── java │ └── com │ └── bobocode │ └── AccountAnalyticsTest.java ├── account-data ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── bobocode │ ├── data │ └── Accounts.java │ └── model │ ├── Account.java │ └── Sex.java ├── crazy-lambdas ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── bobocode │ │ └── CrazyLambdas.java │ └── test │ └── java │ └── com │ └── bobocode │ └── CrazyLambdasTest.java ├── math-functions ├── README.MD ├── pom.xml └── src │ ├── main │ └── java │ │ └── com.bobocode │ │ ├── FunctionMap.java │ │ ├── Functions.java │ │ └── InvalidFunctionNameException.java │ └── test │ └── java │ └── com │ └── bobocode │ └── FunctionsTest.java ├── pom.xml └── sum-of-squares ├── README.MD ├── pom.xml └── src ├── main └── java │ └── com │ └── bobocode │ ├── SumOfSquares.java │ └── exception │ └── InvalidRangeException.java └── test └── java └── com └── bobocode └── SumOfSquareTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | **/*.iml 3 | **/target 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This repo is DEPRECATED. Please use [java-fundamentals-course](https://github.com/bobocode-projects/java-fundamentals-course) 2 | # Java 8 exercises 3 | The list of exercises dedicated to training your Java 8 and functional programming skills 4 | 5 | ### No pain, No gain :heavy_exclamation_mark: 6 | 7 | > Skill is only developed by hours and hours and hours of beating on your craft 8 | 9 | Working on real problems, you're focused on finding a solution. Learning new things, you're trying to understand how it works. 10 | It is important to have a different type of activities, which purpose is improving your skill 11 | 12 | ***An exercise** is a predefined task that you continuously implement to improve a certain skill* :muscle: 13 | ## 14 | * [Math functions](https://github.com/bobocode-projects/java-8-exercises/tree/master/math-functions) 15 | * [Account analytics](https://github.com/bobocode-projects/java-functional-features-exercises/tree/master/account-analytics) 16 | * [Sum of squares](https://github.com/bobocode-projects/java-functional-features-exercises/tree/master/sum-of-squares) 17 | * [Crazy lambdas](https://github.com/bobocode-projects/java-functional-features-exercises/tree/master/crazy-lambdas) 18 | -------------------------------------------------------------------------------- /account-analytics/README.MD: -------------------------------------------------------------------------------- 1 | # Account analytics exercise :muscle: 2 | Improve your Stream API skills 3 | ### Task 4 | `AccountAnalytics` provides an API with a couple statistic methods for a list of accounts. Your job is to implement the *todo* section of that class using **Stream API**. 5 | To verify your implementation, run `AccountAnalyticsTest.java` 6 | 7 | ### Pre-conditions :heavy_exclamation_mark: 8 | You're supposed to be familiar with Java 8 9 | 10 | ### How to start :question: 11 | * Just clone the repository and start implementing the **todo** section, verify your changes by running tests 12 | * If you don't have enough knowledge about this domain, check out the [links below](#related-materials-information_source) 13 | * Don't worry if you got stuck, checkout the **exercise/completed** branch and see the final implementation 14 | 15 | ### Related materials :information_source: 16 | * [Stream API tutorial](https://github.com/bobocode-projects/java-functional-features-tutorial/blob/master/stream-api/README.MD) 17 | * [State of lambda (JSR 335)](http://htmlpreview.github.io/?https://github.com/bobocode-projects/resources/blob/master/java8/lambda/sotl.html) 18 | 19 | -------------------------------------------------------------------------------- /account-analytics/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | java-functional-features-exercises 7 | com.bobocode 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | account-analytics 13 | 14 | 15 | 16 | com.bobocode 17 | account-data 18 | 1.0-SNAPSHOT 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /account-analytics/src/main/java/com.bobocode/AccountAnalytics.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | import com.bobocode.exception.EntityNotFoundException; 4 | import com.bobocode.model.Account; 5 | 6 | import java.math.BigDecimal; 7 | import java.time.Month; 8 | import java.util.*; 9 | 10 | import static java.util.stream.Collectors.mapping; 11 | import static java.util.stream.Collectors.toMap; 12 | 13 | /** 14 | * Implement methods using Stream API 15 | */ 16 | public class AccountAnalytics { 17 | private Collection accounts; 18 | 19 | public static AccountAnalytics of(Collection accounts) { 20 | return new AccountAnalytics(accounts); 21 | } 22 | 23 | private AccountAnalytics(Collection accounts) { 24 | this.accounts = accounts; 25 | } 26 | 27 | /** 28 | * Returns {@link Optional} that contains an {@link Account} with the max value of balance 29 | * 30 | * @return account with max balance wrapped with optional 31 | */ 32 | public Optional findRichestPerson() { 33 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 34 | } 35 | 36 | /** 37 | * Returns a {@link List} of {@link Account} that have a birthday month equal to provided. 38 | * 39 | * @param birthdayMonth a month of birth 40 | * @return a list of accounts 41 | */ 42 | public List findAccountsByBirthdayMonth(Month birthdayMonth) { 43 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 44 | } 45 | 46 | /** 47 | * Returns a map that separates all accounts into two lists - male and female. Map has two keys {@code true} indicates 48 | * male list, and {@code false} indicates female list. 49 | * 50 | * @return a map where key is true or false, and value is list of male, and female accounts 51 | */ 52 | public Map> partitionMaleAccounts() { 53 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 54 | } 55 | 56 | /** 57 | * Returns a {@link Map} that stores accounts grouped by its email domain. A map key is {@link String} which is an 58 | * email domain like "gmail.com". And the value is a {@link List} of {@link Account} objects with a specific email domain. 59 | * 60 | * @return a map where key is an email domain and value is a list of all account with such email 61 | */ 62 | public Map> groupAccountsByEmailDomain() { 63 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 64 | } 65 | 66 | /** 67 | * Returns a number of letters in all first and last names. 68 | * 69 | * @return total number of letters of first and last names of all accounts 70 | */ 71 | public int getNumOfLettersInFirstAndLastNames() { 72 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 73 | } 74 | 75 | /** 76 | * Returns a total balance of all accounts. 77 | * 78 | * @return total balance of all accounts 79 | */ 80 | public BigDecimal calculateTotalBalance() { 81 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 82 | } 83 | 84 | /** 85 | * Returns a {@link List} of {@link Account} objects sorted by first and last names. 86 | * 87 | * @return list of accounts sorted by first and last names 88 | */ 89 | public List sortByFirstAndLastNames() { 90 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 91 | } 92 | 93 | /** 94 | * Checks if there is at least one account with provided email domain. 95 | * 96 | * @param emailDomain 97 | * @return true if there is an account that has an email with provided domain 98 | */ 99 | public boolean containsAccountWithEmailDomain(String emailDomain) { 100 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 101 | } 102 | 103 | /** 104 | * Returns account balance by its email. Throws {@link EntityNotFoundException} with message 105 | * "Cannot find Account by email={email}" if account is not found. 106 | * 107 | * @param email account email 108 | * @return account balance 109 | */ 110 | public BigDecimal getBalanceByEmail(String email) { 111 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 112 | } 113 | 114 | /** 115 | * Collects all existing accounts into a {@link Map} where a key is account id, and the value is {@link Account} instance 116 | * 117 | * @return map of accounts by its ids 118 | */ 119 | public Map collectAccountsById() { 120 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 121 | } 122 | 123 | /** 124 | * Filters accounts by the year when an account was created. Collects account balances by its emails into a {@link Map}. 125 | * The key is {@link Account#email} and the value is {@link Account#balance} 126 | * 127 | * @param year the year of account creation 128 | * @return map of account by its ids the were created in a particular year 129 | */ 130 | public Map collectBalancesByIdForAccountsCreatedOn(int year) { 131 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 132 | } 133 | 134 | /** 135 | * Returns a {@link Map} where key is {@link Account#lastName} and values is a {@link Set} that contains first names 136 | * of all accounts with a specific last name. 137 | * 138 | * @return a map where key is a last name and value is a set of first names 139 | */ 140 | public Map> groupFirstNamesByLastNames() { 141 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 142 | } 143 | 144 | /** 145 | * Returns a {@link Map} where key is a birthday month, and value is a {@link String} that stores comma and space 146 | * -separated first names (e.g. "Polly, Dylan, Clark"), of all accounts that have the same birthday month. 147 | * 148 | * @return a map where a key is a birthday month and value is comma-separated first names 149 | */ 150 | public Map groupCommaSeparatedFirstNamesByBirthdayMonth() { 151 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 152 | } 153 | 154 | /** 155 | * Returns a {@link Map} where key is a {@link Month} of {@link Account#creationDate}, and value is total balance 156 | * of all accounts that have the same value creation month. 157 | * 158 | * @return a map where key is a creation month and value is total balance of all accounts created in that month 159 | */ 160 | public Map groupTotalBalanceByCreationMonth() { 161 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 162 | } 163 | 164 | /** 165 | * Returns a {@link Map} where key is a letter {@link Character}, and value is a number of its occurrences in 166 | * {@link Account#firstName}. 167 | * 168 | * @return a map where key is a letter and value is its count in all first names 169 | */ 170 | public Map getCharacterFrequencyInFirstNames() { 171 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 172 | } 173 | 174 | /** 175 | * Returns a {@link Map} where key is a letter {@link Character}, and value is a number of its occurrences ignoring 176 | * case, in all {@link Account#firstName} and {@link Account#lastName}. All letters should stored in lower case. 177 | * 178 | * @return a map where key is a letter and value is its count ignoring case in all first and last names 179 | */ 180 | public Map getCharacterFrequencyIgnoreCaseInFirstAndLastNames() { 181 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 182 | } 183 | 184 | } 185 | 186 | -------------------------------------------------------------------------------- /account-analytics/src/main/java/com.bobocode/exception/EntityNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.bobocode.exception; 2 | 3 | public class EntityNotFoundException extends RuntimeException { 4 | public EntityNotFoundException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /account-analytics/src/test/java/com/bobocode/AccountAnalyticsTest.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | import com.bobocode.exception.EntityNotFoundException; 4 | import com.bobocode.model.Account; 5 | import com.bobocode.model.Sex; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.junit.runners.JUnit4; 10 | 11 | import java.math.BigDecimal; 12 | import java.time.LocalDate; 13 | import java.time.Month; 14 | import java.util.*; 15 | 16 | import static org.junit.Assert.*; 17 | 18 | /** 19 | * The helper method of this test class do not use Stream API intentionally. You should try to find a stream-based 20 | * solutions for {@link AccountAnalytics} by yourself. 21 | */ 22 | @RunWith(JUnit4.class) 23 | public class AccountAnalyticsTest { 24 | 25 | private AccountAnalytics analytics; 26 | private List accounts; 27 | 28 | @Before 29 | public void setUp() { 30 | accounts = Arrays.asList( 31 | new Account(1L, "Justin", "Butler", "justin.butler@gmail.com", 32 | LocalDate.parse("2003-04-17"), Sex.MALE, LocalDate.parse("2016-06-13"), BigDecimal.valueOf(172966)), 33 | new Account(2L, "Olivia", "Cardenas", "cardenas@mail.com", 34 | LocalDate.parse("1930-01-19"), Sex.FEMALE, LocalDate.parse("2014-06-21"), BigDecimal.valueOf(38029)), 35 | new Account(3L, "Nolan", "Donovan", "nolandonovan@gmail.com", 36 | LocalDate.parse("1925-04-19"), Sex.MALE, LocalDate.parse("2011-03-10"), BigDecimal.valueOf(13889)), 37 | new Account(4L, "Lucas", "Lynn", "lucas.lynn@yahoo.com", 38 | LocalDate.parse("1987-05-25"), Sex.MALE, LocalDate.parse("2009-03-05"), BigDecimal.valueOf(16980)) 39 | ); 40 | analytics = AccountAnalytics.of(accounts); 41 | } 42 | 43 | @Test 44 | public void testFindRichestPerson() { 45 | Optional expectedPerson = Optional.of(accounts.get(0)); 46 | Optional actualRichestPerson = analytics.findRichestPerson(); 47 | 48 | assertEquals(expectedPerson, actualRichestPerson); 49 | } 50 | 51 | @Test 52 | public void testSeparateMaleAccounts() { 53 | Map> expectedAccountMap = getExpectedMaleMap(); 54 | Map> maleToAccountsMap = analytics.partitionMaleAccounts(); 55 | 56 | assertEquals(expectedAccountMap, maleToAccountsMap); 57 | } 58 | 59 | private Map> getExpectedMaleMap() { 60 | Map> expectedMap = new HashMap<>(2); 61 | expectedMap.put(Boolean.TRUE, Arrays.asList(accounts.get(0), accounts.get(2), accounts.get(3))); 62 | expectedMap.put(Boolean.FALSE, Arrays.asList(accounts.get(1))); 63 | return expectedMap; 64 | } 65 | 66 | @Test 67 | public void testFindAccountsByBirthdayMonth() { 68 | List expectedList = getExpectedList(); 69 | List aprilAccounts = analytics.findAccountsByBirthdayMonth(Month.APRIL); 70 | 71 | assertEquals(expectedList, aprilAccounts); 72 | } 73 | 74 | private List getExpectedList() { 75 | return Arrays.asList(accounts.get(0), accounts.get(2)); 76 | } 77 | 78 | @Test 79 | public void testGroupAccountsByEmailDomain() { 80 | Map> expectedEmailMap = getExpectedEmailMap(); 81 | Map> emailDomainToAccountsMap = analytics.groupAccountsByEmailDomain(); 82 | 83 | assertEquals(expectedEmailMap, emailDomainToAccountsMap); 84 | } 85 | 86 | private Map> getExpectedEmailMap() { 87 | Map> expectedEmailMap = new HashMap<>(); 88 | expectedEmailMap.put("gmail.com", Arrays.asList(accounts.get(0), accounts.get(2))); 89 | expectedEmailMap.put("mail.com", Arrays.asList(accounts.get(1))); 90 | expectedEmailMap.put("yahoo.com", Arrays.asList(accounts.get(3))); 91 | 92 | return expectedEmailMap; 93 | } 94 | 95 | @Test 96 | public void testGetNumOfLettersInFirstAndLastNames() { 97 | int numOfLettersInFirstAndLastNames = analytics.getNumOfLettersInFirstAndLastNames(); 98 | 99 | assertEquals(47, numOfLettersInFirstAndLastNames); 100 | } 101 | 102 | @Test 103 | public void testCalculateTotalBalance() { 104 | BigDecimal totalBalance = analytics.calculateTotalBalance(); 105 | 106 | assertEquals(BigDecimal.valueOf(241864), totalBalance); 107 | } 108 | 109 | 110 | @Test 111 | public void testSortByFirstAndLastNames() { 112 | List sortedList = analytics.sortByFirstAndLastNames(); 113 | 114 | assertEquals(1L, sortedList.get(0).getId().longValue()); 115 | assertEquals(4L, sortedList.get(1).getId().longValue()); 116 | assertEquals(3L, sortedList.get(2).getId().longValue()); 117 | assertEquals(2L, sortedList.get(3).getId().longValue()); 118 | 119 | } 120 | 121 | @Test 122 | public void testContainsAccountWithEmailDomain() { 123 | assertTrue(analytics.containsAccountWithEmailDomain("gmail.com")); 124 | assertTrue(analytics.containsAccountWithEmailDomain("yahoo.com")); 125 | assertFalse(analytics.containsAccountWithEmailDomain("ukr.net")); 126 | } 127 | 128 | @Test 129 | public void testGetBalanceByEmail() { 130 | Account account = accounts.get(1); 131 | BigDecimal balance = analytics.getBalanceByEmail(account.getEmail()); 132 | 133 | assertEquals(account.getBalance(), balance); 134 | } 135 | 136 | @Test 137 | public void testGetBalanceByEmailThrowsException() { 138 | String fakeEmail = "fake@mail.com"; 139 | try { 140 | analytics.getBalanceByEmail(fakeEmail); 141 | fail("Should throw exception"); 142 | } catch (Exception e) { 143 | assertTrue(e instanceof EntityNotFoundException); 144 | assertEquals(String.format("Cannot find Account by email=%s", fakeEmail), e.getMessage()); 145 | } 146 | } 147 | 148 | @Test 149 | public void testCollectAccountsById() { 150 | Map idToAccountMap = analytics.collectAccountsById(); 151 | 152 | assertEquals(accounts.get(0), idToAccountMap.get(1L)); 153 | assertEquals(accounts.get(1), idToAccountMap.get(2L)); 154 | assertEquals(accounts.get(2), idToAccountMap.get(3L)); 155 | assertEquals(accounts.get(3), idToAccountMap.get(4L)); 156 | } 157 | 158 | @Test 159 | public void testCollectBalancesByIdForAccountsCreatedOn() { 160 | Account account = accounts.get(3); 161 | 162 | Map emailToBalanceMap = analytics.collectBalancesByIdForAccountsCreatedOn(account.getCreationDate().getYear()); 163 | 164 | assertEquals(Map.of(account.getEmail(), account.getBalance()), emailToBalanceMap); 165 | } 166 | 167 | @Test 168 | public void testGroupFirstNamesByLastNames() { 169 | Map> lastToFirstNamesMap = analytics.groupFirstNamesByLastNames(); 170 | 171 | assertEquals(4, lastToFirstNamesMap.size()); 172 | assertEquals(Set.of("Justin"), lastToFirstNamesMap.get("Butler")); 173 | assertEquals(Set.of("Olivia"), lastToFirstNamesMap.get("Cardenas")); 174 | assertEquals(Set.of("Nolan"), lastToFirstNamesMap.get("Donovan")); 175 | assertEquals(Set.of("Lucas"), lastToFirstNamesMap.get("Lynn")); 176 | } 177 | 178 | @Test 179 | public void testGroupCommaSeparatedFirstNamesByBirthdayMonth() { 180 | Map birthdayMonthToFirstNamesMap = analytics.groupCommaSeparatedFirstNamesByBirthdayMonth(); 181 | 182 | assertEquals(3, birthdayMonthToFirstNamesMap.size()); 183 | assertEquals("Olivia", birthdayMonthToFirstNamesMap.get(Month.JANUARY)); 184 | assertEquals("Justin, Nolan", birthdayMonthToFirstNamesMap.get(Month.APRIL)); 185 | assertEquals("Lucas", birthdayMonthToFirstNamesMap.get(Month.MAY)); 186 | } 187 | 188 | @Test 189 | public void testGroupTotalBalanceByCreationMonth() { 190 | Map totalBalanceByAccountCreationMonth = analytics.groupTotalBalanceByCreationMonth(); 191 | 192 | assertEquals(2, totalBalanceByAccountCreationMonth.size()); 193 | assertEquals(BigDecimal.valueOf(210995), totalBalanceByAccountCreationMonth.get(Month.JUNE)); 194 | assertEquals(BigDecimal.valueOf(30869), totalBalanceByAccountCreationMonth.get(Month.MARCH)); 195 | } 196 | 197 | @Test 198 | public void testGetCharacterFrequencyInFirstNames() { 199 | Map characterFrequencyInFirstAndLastNames = analytics.getCharacterFrequencyInFirstNames(); 200 | 201 | assertEquals(3, characterFrequencyInFirstAndLastNames.get('a').longValue()); 202 | assertEquals(1, characterFrequencyInFirstAndLastNames.get('c').longValue()); 203 | assertEquals(3, characterFrequencyInFirstAndLastNames.get('i').longValue()); 204 | assertEquals(1, characterFrequencyInFirstAndLastNames.get('J').longValue()); 205 | assertEquals(1, characterFrequencyInFirstAndLastNames.get('L').longValue()); 206 | assertEquals(2, characterFrequencyInFirstAndLastNames.get('l').longValue()); 207 | assertEquals(2, characterFrequencyInFirstAndLastNames.get('u').longValue()); 208 | } 209 | 210 | @Test 211 | public void testGetCharacterFrequencyIgnoreCaseInFirstAndLastNames() { 212 | Map characterFrequencyInFirstAndLastNames = analytics.getCharacterFrequencyIgnoreCaseInFirstAndLastNames(); 213 | 214 | assertEquals(6, characterFrequencyInFirstAndLastNames.get('a').longValue()); 215 | assertEquals(1, characterFrequencyInFirstAndLastNames.get('b').longValue()); 216 | assertEquals(2, characterFrequencyInFirstAndLastNames.get('c').longValue()); 217 | assertEquals(5, characterFrequencyInFirstAndLastNames.get('l').longValue()); 218 | assertEquals(8, characterFrequencyInFirstAndLastNames.get('n').longValue()); 219 | assertEquals(3, characterFrequencyInFirstAndLastNames.get('u').longValue()); 220 | assertEquals(1, characterFrequencyInFirstAndLastNames.get('y').longValue()); 221 | } 222 | } 223 | 224 | 225 | -------------------------------------------------------------------------------- /account-data/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | java-functional-features-exercises 7 | com.bobocode 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | account-data 13 | 14 | 15 | 16 | io.codearte.jfairy 17 | jfairy 18 | 0.5.7 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /account-data/src/main/java/com/bobocode/data/Accounts.java: -------------------------------------------------------------------------------- 1 | package com.bobocode.data; 2 | 3 | import com.bobocode.model.Account; 4 | import com.bobocode.model.Sex; 5 | import io.codearte.jfairy.Fairy; 6 | import io.codearte.jfairy.producer.person.Person; 7 | 8 | import java.math.BigDecimal; 9 | import java.time.LocalDate; 10 | import java.util.List; 11 | import java.util.Random; 12 | 13 | import static java.util.stream.Collectors.toList; 14 | import static java.util.stream.IntStream.range; 15 | 16 | public interface Accounts { 17 | static Account getAccount(){ 18 | Fairy fairy = Fairy.create(); 19 | Person person = fairy.person(); 20 | Random random = new Random(); 21 | 22 | 23 | Account fakeAccount = new Account(); 24 | fakeAccount.setFirstName(person.getFirstName()); 25 | fakeAccount.setLastName(person.getLastName()); 26 | fakeAccount.setEmail(person.getEmail()); 27 | fakeAccount.setBirthday(LocalDate.of( 28 | person.getDateOfBirth().getYear(), 29 | person.getDateOfBirth().getMonthOfYear(), 30 | person.getDateOfBirth().getDayOfMonth())); 31 | fakeAccount.setSex(Sex.valueOf(person.getSex().name())); 32 | fakeAccount.setBalance(BigDecimal.valueOf(random.nextInt(200_000))); 33 | fakeAccount.setCreationDate(LocalDate.now()); 34 | 35 | return fakeAccount; 36 | } 37 | 38 | static List getAccountList(int size){ 39 | return range(0, size) 40 | .mapToObj(i -> getAccount()) 41 | .collect(toList()); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /account-data/src/main/java/com/bobocode/model/Account.java: -------------------------------------------------------------------------------- 1 | package com.bobocode.model; 2 | 3 | import lombok.*; 4 | 5 | import java.math.BigDecimal; 6 | import java.time.LocalDate; 7 | import java.time.LocalDateTime; 8 | 9 | @NoArgsConstructor 10 | @AllArgsConstructor(access = AccessLevel.PUBLIC) 11 | @Getter 12 | @Setter 13 | @ToString 14 | @EqualsAndHashCode(of = "email") 15 | public class Account { 16 | private Long id; 17 | private String firstName; 18 | private String lastName; 19 | private String email; 20 | private LocalDate birthday; 21 | private Sex sex; 22 | private LocalDate creationDate; 23 | private BigDecimal balance = BigDecimal.ZERO; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /account-data/src/main/java/com/bobocode/model/Sex.java: -------------------------------------------------------------------------------- 1 | package com.bobocode.model; 2 | 3 | public enum Sex { 4 | MALE, 5 | FEMALE 6 | } 7 | -------------------------------------------------------------------------------- /crazy-lambdas/README.md: -------------------------------------------------------------------------------- 1 | # Crazy lambda exercise :muscle: 2 | Improve your lambda skills 3 | ### Task 4 | `CrazyLambdas` class consists of static methods that return various functions, operations and predicates. 5 | Your job is to implement the *todo* section of that class using **Lambda expressions** and **method reference**. 6 | To verify your implementation, run `CrazyLambdasTest.java` 7 | 8 | ### Pre-conditions :heavy_exclamation_mark: 9 | You're supposed to be familiar with Java 8 10 | 11 | ### How to start :question: 12 | * Just clone the repository and start implementing the **todo** section, verify your changes by running tests 13 | * If you don't have enough knowledge about this domain, check out the [links below](#related-materials-information_source) 14 | * Don't worry if you got stuck, checkout the **exercise/completed** branch and see the final implementation 15 | 16 | ### Related materials :information_source: 17 | * [Lambda tutorial](https://github.com/bobocode-projects/java-8-tutorial/tree/master/lambdas) 18 | * [State of lambda (JSR 335)](http://htmlpreview.github.io/?https://github.com/bobocode-projects/resources/blob/master/java8/lambda/sotl.html) 19 | 20 | -------------------------------------------------------------------------------- /crazy-lambdas/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | java-functional-features-exercises 7 | com.bobocode 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | crazy-lambdas 13 | 14 | 15 | -------------------------------------------------------------------------------- /crazy-lambdas/src/main/java/com/bobocode/CrazyLambdas.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Map; 5 | import java.util.TreeMap; 6 | import java.util.function.*; 7 | 8 | public class CrazyLambdas { 9 | 10 | /** 11 | * Returns {@link Supplier} that always supply "Hello" 12 | * 13 | * @return a string supplier 14 | */ 15 | public static Supplier helloSupplier() { 16 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 17 | } 18 | 19 | /** 20 | * Returns a {@link Predicate} of string that checks if string is empty 21 | * 22 | * @return a string predicate 23 | */ 24 | public static Predicate isEmptyPredicate() { 25 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 26 | } 27 | 28 | /** 29 | * Return a {@link Function} that accepts {@link String} and returns that string repeated n time, where n is passed 30 | * as function argument 31 | * 32 | * @return function that repeats Strings 33 | */ 34 | public static BiFunction stringMultiplier() { 35 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 36 | } 37 | 38 | /** 39 | * Returns a {@link Function} that converts a {@link BigDecimal} number into a {@link String} that start with 40 | * a dollar sign and then gets a value 41 | * 42 | * @return function that converts adds dollar sign 43 | */ 44 | public static Function toDollarStringFunction() { 45 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 46 | } 47 | 48 | /** 49 | * Receives two parameter that represent a range and returns a {@link Predicate} that verifies if string 50 | * length is in the specified range. E.g. min <= length < max 51 | * 52 | * @param min min length 53 | * @param max max length 54 | * @return a string predicate 55 | */ 56 | public static Predicate lengthInRangePredicate(int min, int max) { 57 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 58 | } 59 | 60 | /** 61 | * Returns a {@link Supplier} of random integers 62 | * 63 | * @return int supplier 64 | */ 65 | public static IntSupplier randomIntSupplier() { 66 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 67 | } 68 | 69 | 70 | /** 71 | * Returns an {@link IntUnaryOperator} that receives an int as a bound parameter, and returns a random int 72 | * 73 | * @return int operation 74 | */ 75 | public static IntUnaryOperator boundedRandomIntSupplier() { 76 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 77 | } 78 | 79 | /** 80 | * Returns {@link IntUnaryOperator} that calculates an integer square 81 | * 82 | * @return square operation 83 | */ 84 | public static IntUnaryOperator intSquareOperation() { 85 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 86 | } 87 | 88 | /** 89 | * Returns a {@link LongBinaryOperator} sum operation. 90 | * 91 | * @return binary sum operation 92 | */ 93 | public static LongBinaryOperator longSumOperation() { 94 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 95 | } 96 | 97 | /** 98 | * Returns a {@link ToIntFunction} that converts string to integer. 99 | * 100 | * @return string to int converter 101 | */ 102 | public static ToIntFunction stringToIntConverter() { 103 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 104 | } 105 | 106 | /** 107 | * Receives int parameter n, and returns a {@link Supplier} that supplies {@link IntUnaryOperator} 108 | * that is a function f(x) = n * x 109 | * 110 | * @param n a multiplier 111 | * @return a function supplier 112 | */ 113 | public static Supplier nMultiplyFunctionSupplier(int n) { 114 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 115 | } 116 | 117 | /** 118 | * Returns a {@link UnaryOperator} that accepts str to str function and returns the same function composed with trim 119 | * 120 | * @return function that composes functions with trim() function 121 | */ 122 | public static UnaryOperator> composeWithTrimFunction() { 123 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 124 | } 125 | 126 | /** 127 | * Receives a {@link Runnable} parameter, and returns a {@link Supplier}. The thread will be started only 128 | * when you call supplier method {@link Supplier#get()} 129 | * 130 | * @param runnable the code you want to tun in new thread 131 | * @return a thread supplier 132 | */ 133 | public static Supplier runningThreadSupplier(Runnable runnable) { 134 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 135 | } 136 | 137 | /** 138 | * Returns a {@link Consumer} that accepts {@link Runnable} as a parameter and runs in in a new thread. 139 | * 140 | * @return a runnable consumer 141 | */ 142 | public static Consumer newThreadRunnableConsumer() { 143 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 144 | } 145 | 146 | /** 147 | * Returns a {@link Function} that accepts an instance of {@link Runnable} and returns a {@link Supplier} of a 148 | * started {@link Thread} that is created from a given {@link Runnable} 149 | * 150 | * @return a function that transforms runnable into a thread supplier 151 | */ 152 | public static Function> runnableToThreadSupplierFunction() { 153 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 154 | } 155 | 156 | /** 157 | * Returns a {@link BiFunction} that has two parameters. First is {@link IntUnaryOperator} which is some integer function. 158 | * Second is {@link IntPredicate} which is some integer condition. And the third is {@link IntUnaryOperator} which is 159 | * a new composed function that uses provided predicate (second parameter of binary function) to verify its input 160 | * parameter. If predicate returns {@code true} it applies a provided integer function 161 | * (first parameter of binary function) and returns a result value, otherwise it returns an element itself. 162 | * 163 | * @return a binary function that receiver predicate and function and compose them to create a new function 164 | */ 165 | public static BiFunction functionToConditionalFunction() { 166 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 167 | } 168 | 169 | /** 170 | * Returns a {@link BiFunction} which first parameter is a {@link Map} where key is a function name, and value is some 171 | * {@link IntUnaryOperator}, and second parameter is a {@link String} which is a function name. If the map contains a 172 | * function by a given name then it is returned by high order function otherwise an identity() is returned. 173 | * 174 | * @return a high-order function that fetches a function from a function map by a given name or returns identity() 175 | */ 176 | public static BiFunction, String, IntUnaryOperator> functionLoader() { 177 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 178 | } 179 | 180 | /** 181 | * Returns {@link Supplier} of {@link Supplier} of {@link Supplier} of {@link String} "WELL DONE". 182 | * 183 | * @return a supplier instance 184 | */ 185 | public static Supplier>> trickyWellDoneSupplier() { 186 | throw new UnsupportedOperationException("It's your job to implement this method"); // todo 187 | } 188 | } 189 | 190 | -------------------------------------------------------------------------------- /crazy-lambdas/src/test/java/com/bobocode/CrazyLambdasTest.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.junit.runners.JUnit4; 6 | 7 | import java.math.BigDecimal; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Queue; 13 | import java.util.concurrent.ConcurrentLinkedQueue; 14 | import java.util.function.*; 15 | 16 | import static org.junit.Assert.*; 17 | 18 | @RunWith(JUnit4.class) 19 | public class CrazyLambdasTest { 20 | 21 | @Test 22 | public void testHelloSupplier() { 23 | Supplier helloSupplier = CrazyLambdas.helloSupplier(); 24 | 25 | assertEquals("Hello", helloSupplier.get()); 26 | } 27 | 28 | 29 | @Test 30 | public void testIsEmptyPredicate() { 31 | Predicate isEmptyPredicate = CrazyLambdas.isEmptyPredicate(); 32 | 33 | boolean nonEmptyStringResult = isEmptyPredicate.test("fasdfa"); 34 | boolean emptyStringResult = isEmptyPredicate.test(""); 35 | 36 | assertFalse(nonEmptyStringResult); 37 | assertTrue(emptyStringResult); 38 | } 39 | 40 | @Test 41 | public void testStringMultiplier() { 42 | BiFunction stringMultiplier = CrazyLambdas.stringMultiplier(); 43 | 44 | String threeTimesHi = stringMultiplier.apply("Hi", 3); 45 | String twoTimesHello = stringMultiplier.apply("Hello", 2); 46 | 47 | assertEquals("HiHiHi", threeTimesHi); 48 | assertEquals("HelloHello", twoTimesHello); 49 | } 50 | 51 | @Test 52 | public void testToDollarStringFunction() { 53 | Function toDollarStringFunction = CrazyLambdas.toDollarStringFunction(); 54 | String tenDollarStr = toDollarStringFunction.apply(BigDecimal.TEN.setScale(2)); 55 | 56 | assertEquals("$10.00", tenDollarStr); 57 | } 58 | 59 | @Test 60 | public void testLengthInRangePredicate() { 61 | Predicate lengthInRangePredicate = CrazyLambdas.lengthInRangePredicate(4, 10); 62 | 63 | boolean twoLetterStringResult = lengthInRangePredicate.test("Hi"); 64 | boolean fourLetterStringResult = lengthInRangePredicate.test("Hola"); 65 | boolean fiveLetterStringResult = lengthInRangePredicate.test("Amigo"); 66 | boolean eightLetterStringResult = lengthInRangePredicate.test("Lalaland"); 67 | boolean thirteenLetterStringResult = lengthInRangePredicate.test("Lambda rocks!"); 68 | 69 | assertFalse(twoLetterStringResult); 70 | assertTrue(fourLetterStringResult); 71 | assertTrue(fiveLetterStringResult); 72 | assertTrue(eightLetterStringResult); 73 | assertFalse(thirteenLetterStringResult); 74 | } 75 | 76 | @Test 77 | public void testRandomIntSupplier() { 78 | IntSupplier randomIntSupplier = CrazyLambdas.randomIntSupplier(); 79 | 80 | int firstValue = randomIntSupplier.getAsInt(); 81 | int secondValue = randomIntSupplier.getAsInt(); 82 | 83 | assertNotEquals(firstValue, secondValue); 84 | } 85 | 86 | @Test 87 | public void testBoundedRandomIntSupplier() { 88 | IntUnaryOperator boundedRandomIntSupplier = CrazyLambdas.boundedRandomIntSupplier(); 89 | 90 | int randomIntLessThan10 = boundedRandomIntSupplier.applyAsInt(10); 91 | int randomIntLessThan100 = boundedRandomIntSupplier.applyAsInt(100); 92 | int randomIntLessThan1000 = boundedRandomIntSupplier.applyAsInt(1000); 93 | int randomIntLessThan10000 = boundedRandomIntSupplier.applyAsInt(1000); 94 | 95 | assertTrue(randomIntLessThan10 < 10); 96 | assertTrue(randomIntLessThan100 < 100); 97 | assertTrue(randomIntLessThan1000 < 1000); 98 | assertTrue(randomIntLessThan10000 < 10000); 99 | } 100 | 101 | @Test 102 | public void testIntSquareOperation() { 103 | IntUnaryOperator squareOperation = CrazyLambdas.intSquareOperation(); 104 | 105 | int squareOfFour = squareOperation.applyAsInt(4); 106 | int squareOfZero = squareOperation.applyAsInt(0); 107 | 108 | assertEquals(16, squareOfFour); 109 | assertEquals(0, squareOfZero); 110 | } 111 | 112 | @Test 113 | public void testLongSumOperation() { 114 | LongBinaryOperator sumOperation = CrazyLambdas.longSumOperation(); 115 | 116 | 117 | long sumOfSevenAndEight = sumOperation.applyAsLong(7, 8); 118 | long sumOfTenAndZero = sumOperation.applyAsLong(10, 0); 119 | long sumOfFiveAndMinusTen = sumOperation.applyAsLong(5, -10); 120 | 121 | assertEquals(15, sumOfSevenAndEight); 122 | assertEquals(10, sumOfTenAndZero); 123 | assertEquals(-5, sumOfFiveAndMinusTen); 124 | } 125 | 126 | @Test 127 | public void testStringToIntConverter() { 128 | ToIntFunction stringToIntConverter = CrazyLambdas.stringToIntConverter(); 129 | 130 | int num = stringToIntConverter.applyAsInt("234"); 131 | int negativeNum = stringToIntConverter.applyAsInt("-122"); 132 | 133 | assertEquals(234, num); 134 | assertEquals(-122, negativeNum); 135 | } 136 | 137 | @Test 138 | public void testNMultiplyFunctionSupplier() { 139 | Supplier fiveMultiplyFunctionSupplier = CrazyLambdas.nMultiplyFunctionSupplier(5); 140 | 141 | IntUnaryOperator multiplyByFiveOperation = fiveMultiplyFunctionSupplier.get(); 142 | int result = multiplyByFiveOperation.applyAsInt(11); // 11 * 5 = 55 143 | 144 | assertEquals(55, result); 145 | } 146 | 147 | @Test 148 | public void testComposeWithTrimFunction() { 149 | UnaryOperator> composeWithTrimFunction = CrazyLambdas.composeWithTrimFunction(); 150 | Function toLowerWithTrim = composeWithTrimFunction.apply(String::toLowerCase); 151 | Function threeTimesRepeatWithTrim = composeWithTrimFunction.apply(s -> s.repeat(3)); 152 | 153 | String hey = toLowerWithTrim.apply(" Hey "); 154 | String threeTimesHi = threeTimesRepeatWithTrim.apply(" Hi "); 155 | 156 | assertEquals("hey", hey); 157 | assertEquals("HiHiHi", threeTimesHi); 158 | } 159 | 160 | @Test 161 | public void testRunningThreadSupplier() throws InterruptedException { 162 | Queue concurrentLinkedQueue = new ConcurrentLinkedQueue<>(); 163 | Supplier runningThreadSupplier = CrazyLambdas.runningThreadSupplier(() -> concurrentLinkedQueue.add(25)); 164 | 165 | // supplier does not create and start a thread before you call get() 166 | assertEquals(0, concurrentLinkedQueue.size()); 167 | 168 | Thread runningThread = runningThreadSupplier.get(); // new thread has been started 169 | runningThread.join(); 170 | 171 | assertEquals(1, concurrentLinkedQueue.size()); 172 | assertEquals(25, concurrentLinkedQueue.element().intValue()); 173 | } 174 | 175 | @Test 176 | public void testNewThreadRunnableConsumer() throws InterruptedException { 177 | Consumer newThreadRunnableConsumer = CrazyLambdas.newThreadRunnableConsumer(); 178 | 179 | Queue concurrentLinkedQueue = new ConcurrentLinkedQueue<>(); 180 | newThreadRunnableConsumer.accept(() -> concurrentLinkedQueue.add(50)); 181 | 182 | Thread.sleep(500); // don't do that in real code 183 | 184 | assertEquals(1, concurrentLinkedQueue.size()); 185 | assertEquals(50, concurrentLinkedQueue.element().intValue()); 186 | } 187 | 188 | @Test 189 | public void testRunnableToThreadSupplierFunction() throws InterruptedException { 190 | Function> runnableSupplierFunction = CrazyLambdas.runnableToThreadSupplierFunction(); 191 | Queue concurrentLinkedQueue = new ConcurrentLinkedQueue<>(); 192 | 193 | Supplier threadSupplier = runnableSupplierFunction.apply(() -> concurrentLinkedQueue.add(200)); 194 | 195 | assertEquals(0, concurrentLinkedQueue.size()); // supplier does not create and start a thread before you call get() 196 | 197 | Thread thread = threadSupplier.get();// new thread has been started 198 | thread.join(); 199 | 200 | assertEquals(1, concurrentLinkedQueue.size()); 201 | assertEquals(200, concurrentLinkedQueue.element().intValue()); 202 | } 203 | 204 | @Test 205 | public void testFunctionToConditionalFunction() { 206 | BiFunction intFunctionToConditionalIntFunction 207 | = CrazyLambdas.functionToConditionalFunction(); 208 | 209 | IntUnaryOperator abs = intFunctionToConditionalIntFunction.apply(a -> -a, a -> a < 0); 210 | 211 | assertEquals(5, abs.applyAsInt(-5)); 212 | assertEquals(0, abs.applyAsInt(0)); 213 | assertEquals(5, abs.applyAsInt(5)); 214 | } 215 | 216 | @Test 217 | public void testFunctionLoader() { 218 | BiFunction, String, IntUnaryOperator> functionLoader = CrazyLambdas.functionLoader(); 219 | Map functionMap = new HashMap<>(); 220 | functionMap.put("increment", x -> x + 1); 221 | functionMap.put("square", x -> x * x); 222 | 223 | IntUnaryOperator incrementFunction = functionLoader.apply(functionMap, "increment"); 224 | IntUnaryOperator squareFunction = functionLoader.apply(functionMap, "square"); 225 | IntUnaryOperator identityFunction = functionLoader.apply(functionMap, "none"); 226 | 227 | assertEquals(5, incrementFunction.applyAsInt(4)); 228 | assertEquals(9, squareFunction.applyAsInt(3)); 229 | assertEquals(10, identityFunction.applyAsInt(10)); 230 | } 231 | 232 | 233 | @Test 234 | public void testTrickyWellDoneSupplier() { 235 | Supplier>> wellDoneSupplier = CrazyLambdas.trickyWellDoneSupplier(); 236 | 237 | String wellDoneStr = wellDoneSupplier.get().get().get(); 238 | 239 | assertEquals("WELL DONE!", wellDoneStr); 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /math-functions/README.MD: -------------------------------------------------------------------------------- 1 | # Math functions exercise :muscle: 2 | Improve your lambda and method reference skills 3 | ### Task 4 | **FunctionMap** is an API that allows you to store and retrieve math functions by string name. Your job is to implement the *todo* section of `Functions.java` class using **Lambda expressions and method reference**, so all tests in `FunctionsTest.java` should pass 5 | 6 | ### Pre-conditions :heavy_exclamation_mark: 7 | You're supposed to be familiar with Java 8 8 | 9 | ### How to start :question: 10 | * Just clone the repository and start implementing the **todo** section, verify your changes by running tests 11 | * If you don't have enough knowledge about this domain, check out the [links below](#related-materials-information_source) 12 | * Don't worry if you got stuck, checkout the [exercise/completed](https://github.com/bobocode-projects/tdd-exercises/tree/exercise/completed/binary-search-tree) branch and see the final implementation 13 | 14 | ### Related materials :information_source: 15 | * [Lambda tutorial](https://github.com/bobocode-projects/java-8-tutorial/tree/master/lambdas) 16 | * [State of lambda (JSR 335)](http://htmlpreview.github.io/?https://github.com/bobocode-projects/resources/blob/master/java8/lambda/sotl.html) 17 | 18 | -------------------------------------------------------------------------------- /math-functions/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | java-functional-features-exercises 7 | com.bobocode 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | math-functions 13 | 14 | -------------------------------------------------------------------------------- /math-functions/src/main/java/com.bobocode/FunctionMap.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | 7 | /** 8 | * FunctionMap is an API that allows you to store and retrieve functions by string name. FunctionMap are stored in a 9 | * HashMap, where the key is a function name, and the value is a Function instance 10 | */ 11 | public class FunctionMap { 12 | private Map> functionMap; 13 | 14 | FunctionMap() { 15 | functionMap = new HashMap<>(); 16 | } 17 | 18 | public void addFunction(String name, Function function) { 19 | functionMap.put(name, function); 20 | } 21 | 22 | public Function getFunction(String name) { 23 | if (functionMap.containsKey(name)) { 24 | return functionMap.get(name); 25 | } else { 26 | throw new InvalidFunctionNameException(name); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /math-functions/src/main/java/com.bobocode/Functions.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | public class Functions { 4 | /** 5 | * A static factory method that creates an integer function map with basic functions: 6 | * - abs (absolute value) 7 | * - sgn (signum function) 8 | * - increment 9 | * - decrement 10 | * - square 11 | * 12 | * @return an instance of {@link FunctionMap} that contains all listed functions 13 | */ 14 | public static FunctionMap intFunctionMap() { 15 | FunctionMap intFunctionMap = new FunctionMap<>(); 16 | 17 | // todo: add simple functions to the function map (abs, sng, increment, decrement, square) 18 | 19 | return intFunctionMap; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /math-functions/src/main/java/com.bobocode/InvalidFunctionNameException.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | public class InvalidFunctionNameException extends RuntimeException { 4 | public InvalidFunctionNameException(String functionName) { 5 | super("Function " + functionName + " doesn't exist."); 6 | } 7 | } -------------------------------------------------------------------------------- /math-functions/src/test/java/com/bobocode/FunctionsTest.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | import org.junit.Before; 4 | import org.junit.Test; 5 | 6 | import java.util.function.Function; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | public class FunctionsTest { 11 | private FunctionMap integerFunctionMap; 12 | 13 | @Before 14 | public void init(){ 15 | integerFunctionMap = Functions.intFunctionMap(); 16 | } 17 | 18 | @Test 19 | public void testSquareFunction() { 20 | Function squareFunction = integerFunctionMap.getFunction("square"); 21 | 22 | int actualResult = squareFunction.apply(5); 23 | 24 | assertEquals(25, actualResult); 25 | } 26 | 27 | @Test 28 | public void testAbsFunction(){ 29 | Function absFunction = integerFunctionMap.getFunction("abs"); 30 | 31 | int actualResult = absFunction.apply(-192); 32 | 33 | assertEquals(192, actualResult); 34 | } 35 | 36 | @Test 37 | public void testIncrementFunction(){ 38 | Function incrementFunction = integerFunctionMap.getFunction("increment"); 39 | 40 | int actualResult = incrementFunction.apply(399); 41 | 42 | assertEquals(400, actualResult); 43 | } 44 | 45 | @Test 46 | public void testDecrementFunction(){ 47 | Function decrementFunction = integerFunctionMap.getFunction("decrement"); 48 | 49 | int actualResult = decrementFunction.apply(800); 50 | 51 | assertEquals(799, actualResult); 52 | } 53 | 54 | @Test 55 | public void testSignFunctionOnNegativeValue(){ 56 | Function signFunction = integerFunctionMap.getFunction("sgn"); 57 | 58 | int actualResult = signFunction.apply(-123); 59 | 60 | assertEquals(-1, actualResult); 61 | } 62 | 63 | @Test 64 | public void testSignFunctionOnPositiveValue(){ 65 | Function signFunction = integerFunctionMap.getFunction("sgn"); 66 | 67 | int actualResult = signFunction.apply(23); 68 | 69 | assertEquals(1, actualResult); 70 | } 71 | 72 | @Test 73 | public void testSignFunctionOnZero(){ 74 | Function signFunction = integerFunctionMap.getFunction("sgn"); 75 | 76 | int actualResult = signFunction.apply(0); 77 | 78 | assertEquals(0, actualResult); 79 | } 80 | 81 | @Test(expected = InvalidFunctionNameException.class) 82 | public void testGetUnknownFunction(){ 83 | integerFunctionMap.getFunction("sqrt"); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.bobocode 8 | java-functional-features-exercises 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | math-functions 13 | account-analytics 14 | account-data 15 | sum-of-squares 16 | crazy-lambdas 17 | 18 | 19 | 20 | 11 21 | 11 22 | 23 | 24 | 25 | 26 | junit 27 | junit 28 | 4.12 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | 1.18.0 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /sum-of-squares/README.MD: -------------------------------------------------------------------------------- 1 | # Sum of squares exercise :muscle: 2 | Improve your functional programming skills 3 | ### Task 4 | `SumOfSquares` is a class that allows you to calculate a sum of squares in a provided range. It is implemented using 5 | OO approach. Your job is to **refactor the todo section using functional approach.** So the **implementation will not use 6 | mutable variables**, and all test will pass. 7 | 8 | ### Pre-conditions :heavy_exclamation_mark: 9 | You're supposed to be familiar with Java 8 10 | 11 | ### How to start :question: 12 | * Just clone the repository and start working on the **todo** section, verify your changes by running tests 13 | * If you don't have enough knowledge about this domain, check out the [links below](#related-materials-information_source) 14 | * Don't worry if you got stuck, checkout the branch **exercise/completed** and see the final implementation 15 | 16 | ### Related materials :information_source: 17 | * [Functional programming tutorial](https://github.com/bobocode-projects/java-functional-features-tutorial/tree/master/functional-programming-basics) 18 | 19 | -------------------------------------------------------------------------------- /sum-of-squares/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | java-functional-features-exercises 7 | com.bobocode 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | sum-of-squares 13 | 14 | 15 | -------------------------------------------------------------------------------- /sum-of-squares/src/main/java/com/bobocode/SumOfSquares.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | 4 | import com.bobocode.exception.InvalidRangeException; 5 | 6 | 7 | /** 8 | * This class allow to calculate a sum of squares of integer number in a certain range. It was implemented using 9 | * OO approach. Your job is to refactor it using functional approach. E.g. avoid using mutable variables 10 | */ 11 | public class SumOfSquares { 12 | public static void main(String[] args) { 13 | System.out.println("Sum of squares from 5 to 10 is " + calculateSumOfSquaresInRange(5, 10)); 14 | } 15 | 16 | /** 17 | * This method calculates the sum of squares of integer in the range 18 | * 19 | * @param startInclusive first element in range 20 | * @param endInclusive last element in range 21 | * @return the sum of squares of each element in the range 22 | */ 23 | static int calculateSumOfSquaresInRange(int startInclusive, int endInclusive) { 24 | if (endInclusive < startInclusive) { 25 | throw new InvalidRangeException(); 26 | } 27 | 28 | // todo: refactor using functional approach 29 | int sumOfSquares = 0; 30 | for (int i = startInclusive; i <= endInclusive; i++) { 31 | sumOfSquares += i * i; 32 | } 33 | return sumOfSquares; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /sum-of-squares/src/main/java/com/bobocode/exception/InvalidRangeException.java: -------------------------------------------------------------------------------- 1 | package com.bobocode.exception; 2 | 3 | public class InvalidRangeException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /sum-of-squares/src/test/java/com/bobocode/SumOfSquareTest.java: -------------------------------------------------------------------------------- 1 | package com.bobocode; 2 | 3 | import com.bobocode.exception.InvalidRangeException; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.JUnit4; 7 | 8 | import static org.junit.Assert.assertEquals; 9 | 10 | @RunWith(JUnit4.class) 11 | public class SumOfSquareTest { 12 | 13 | @Test 14 | public void testCalculateSumOfSquaresOfZero() { 15 | int sumOfSquares = SumOfSquares.calculateSumOfSquaresInRange(0, 0); 16 | 17 | assertEquals(0, sumOfSquares); 18 | } 19 | 20 | @Test 21 | public void testCalculateSumOfSquaresOfOne() { 22 | int sumOfSquares = SumOfSquares.calculateSumOfSquaresInRange(0, 1); 23 | 24 | assertEquals(1, sumOfSquares); 25 | } 26 | 27 | @Test 28 | public void testCalculateSumOfSquares() { 29 | int sumOfSquares = SumOfSquares.calculateSumOfSquaresInRange(1, 5); // 1*1 + 2*2 + 3*3 + 4*4 + 5*5 = 55 30 | 31 | assertEquals(55, sumOfSquares); 32 | } 33 | 34 | @Test 35 | public void testCalculateSumOfSquaresOnNegative() { 36 | int sumOfSquares = SumOfSquares.calculateSumOfSquaresInRange(-4, -2); // -4*(-4) + -3*(-3) + -2*(-2) = 29 37 | 38 | assertEquals(29, sumOfSquares); 39 | } 40 | 41 | @Test(expected = InvalidRangeException.class) 42 | public void testWithInvalidRange() { 43 | SumOfSquares.calculateSumOfSquaresInRange(4, 1); 44 | } 45 | 46 | } 47 | --------------------------------------------------------------------------------