diff --git a/crazy-lambdas/src/main/java/com/bobocode/CrazyLambdas.java b/crazy-lambdas/src/main/java/com/bobocode/CrazyLambdas.java index d5398ab..6a329f1 100644 --- a/crazy-lambdas/src/main/java/com/bobocode/CrazyLambdas.java +++ b/crazy-lambdas/src/main/java/com/bobocode/CrazyLambdas.java @@ -1,6 +1,7 @@ package com.bobocode; import java.math.BigDecimal; +import java.util.concurrent.ThreadLocalRandom; import java.util.Map; import java.util.function.*; @@ -12,7 +13,7 @@ public class CrazyLambdas { * @return a string supplier */ public static Supplier helloSupplier() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return () -> "Hello"; } /** @@ -21,7 +22,7 @@ public static Supplier helloSupplier() { * @return a string predicate */ public static Predicate isEmptyPredicate() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return String::isEmpty; } /** @@ -31,7 +32,7 @@ public static Predicate isEmptyPredicate() { * @return function that repeats Strings */ public static BiFunction stringMultiplier() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return String::repeat; } /** @@ -41,7 +42,7 @@ public static BiFunction stringMultiplier() { * @return function that converts adds dollar sign */ public static Function toDollarStringFunction() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return bigDecimal -> "$" + bigDecimal; } /** @@ -53,7 +54,7 @@ public static Function toDollarStringFunction() { * @return a string predicate */ public static Predicate lengthInRangePredicate(int min, int max) { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return str -> str.length() >= min && str.length() < max; } /** @@ -62,7 +63,7 @@ public static Predicate lengthInRangePredicate(int min, int max) { * @return int supplier */ public static IntSupplier randomIntSupplier() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return () -> ThreadLocalRandom.current().nextInt(); } @@ -72,7 +73,7 @@ public static IntSupplier randomIntSupplier() { * @return int operation */ public static IntUnaryOperator boundedRandomIntSupplier() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return bound -> ThreadLocalRandom.current().nextInt(bound); } /** @@ -81,7 +82,7 @@ public static IntUnaryOperator boundedRandomIntSupplier() { * @return square operation */ public static IntUnaryOperator intSquareOperation() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return a -> a * a; } /** @@ -90,7 +91,7 @@ public static IntUnaryOperator intSquareOperation() { * @return binary sum operation */ public static LongBinaryOperator longSumOperation() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return (a, b) -> a + b; } /** @@ -99,7 +100,7 @@ public static LongBinaryOperator longSumOperation() { * @return string to int converter */ public static ToIntFunction stringToIntConverter() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return Integer::parseInt; } /** @@ -110,7 +111,7 @@ public static ToIntFunction stringToIntConverter() { * @return a function supplier */ public static Supplier nMultiplyFunctionSupplier(int n) { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return () -> a -> n * a; } /** @@ -119,7 +120,7 @@ public static Supplier nMultiplyFunctionSupplier(int n) { * @return function that composes functions with trim() function */ public static UnaryOperator> composeWithTrimFunction() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return stringFunction -> stringFunction.compose(String::trim); } /** @@ -130,7 +131,11 @@ public static UnaryOperator> composeWithTrimFunction() * @return a thread supplier */ public static Supplier runningThreadSupplier(Runnable runnable) { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return () -> { + Thread thread = new Thread(runnable); + thread.start(); + return thread; + }; } /** @@ -139,7 +144,7 @@ public static Supplier runningThreadSupplier(Runnable runnable) { * @return a runnable consumer */ public static Consumer newThreadRunnableConsumer() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return runnable -> new Thread(runnable).start(); } /** @@ -149,7 +154,11 @@ public static Consumer newThreadRunnableConsumer() { * @return a function that transforms runnable into a thread supplier */ public static Function> runnableToThreadSupplierFunction() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return runnable -> () -> { + Thread thread = new Thread(runnable); + thread.start(); + return thread; + }; } /** @@ -162,7 +171,7 @@ 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 UnsupportedOperationException("It's your job to implement this method"); // todo + return (intOperation, intPredicate) -> a -> intPredicate.test(a) ? intOperation.applyAsInt(a) : a; } /** @@ -173,7 +182,7 @@ 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 UnsupportedOperationException("It's your job to implement this method"); // todo + return (functionMap, functionName) -> functionMap.getOrDefault(functionName, IntUnaryOperator.identity()); } /** @@ -182,7 +191,8 @@ public static BiFunction, String, IntUnaryOperator * @return a supplier instance */ public static Supplier>> trickyWellDoneSupplier() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return () -> () -> () -> "WELL DONE!"; } } + diff --git a/crazy-optionals/src/main/java/com/bobocode/CrazyOptionals.java b/crazy-optionals/src/main/java/com/bobocode/CrazyOptionals.java index d81fe02..eb1734e 100644 --- a/crazy-optionals/src/main/java/com/bobocode/CrazyOptionals.java +++ b/crazy-optionals/src/main/java/com/bobocode/CrazyOptionals.java @@ -15,6 +15,8 @@ import java.util.Optional; import java.util.OptionalDouble; +import static java.util.Comparator.comparing; + public class CrazyOptionals { /** @@ -24,7 +26,7 @@ public class CrazyOptionals { * @return optional object that holds text */ public static Optional optionalOfString(@Nullable String text) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return Optional.ofNullable(text); // Optional.ofNullable() will use Optional.empty() if text is null } /** @@ -34,7 +36,10 @@ public static Optional optionalOfString(@Nullable String text) { * @param amount money to deposit */ public static void deposit(AccountProvider accountProvider, BigDecimal amount) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + accountProvider.getAccount() + .ifPresent(account -> account.setBalance(account.getBalance().add(amount))); // instead of using if operator + // you can pass Consumer object that will be used in case Optional is not empty + // this approach is called declarative and is usually more precise } /** @@ -44,7 +49,7 @@ public static void deposit(AccountProvider accountProvider, BigDecimal amount) { * @return optional object that holds account */ public static Optional optionalOfAccount(@Nonnull Account account) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return Optional.of(account); // Optional.of() will throw NullPointerException if account is null } /** @@ -56,7 +61,8 @@ public static Optional optionalOfAccount(@Nonnull Account account) { * @return account from provider or defaultAccount */ public static Account getAccount(AccountProvider accountProvider, Account defaultAccount) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accountProvider.getAccount() + .orElse(defaultAccount); // Optional#orElse() can be used to provide default value is case Optional is empty } /** @@ -67,7 +73,10 @@ public static Account getAccount(AccountProvider accountProvider, Account defaul * @param accountService */ public static void processAccount(AccountProvider accountProvider, AccountService accountService) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + accountProvider.getAccount() + .ifPresentOrElse(accountService::processAccount, accountService::processWithNoAccount); + // one more declarative substitution of if-else operator. + // Please note its parameters: Consumer and Runnable } /** @@ -78,7 +87,12 @@ public static void processAccount(AccountProvider accountProvider, AccountServic * @return provided or generated account */ public static Account getOrGenerateAccount(AccountProvider accountProvider) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accountProvider.getAccount() + .orElseGet(Accounts::generateAccount); // functionally it works exactly the same as Optional#orElse() + // however it is based on lazy initialization using Supplier interface, which means that default value + // will not be computed (created) until Supplier#get() is called, which means it will be only computed + // when Optional is empty. This method should be used in favor of Optional#orElse() when the creation of default + // value requires additional resources } /** @@ -88,7 +102,8 @@ public static Account getOrGenerateAccount(AccountProvider accountProvider) { * @return optional balance */ public static Optional retrieveBalance(AccountProvider accountProvider) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accountProvider.getAccount() + .map(Account::getBalance); // a null-safe mapping that allows you to go from Optional object to its field } /** @@ -99,7 +114,9 @@ public static Optional retrieveBalance(AccountProvider accountProvid * @return provided account */ public static Account getAccount(AccountProvider accountProvider) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accountProvider.getAccount() + .orElseThrow(() -> new AccountNotFoundException("No Account provided!")); // in case Optional is empty + // it allows to throw a custom exception } /** @@ -109,7 +126,9 @@ public static Account getAccount(AccountProvider accountProvider) { * @return optional credit balance */ public static Optional retrieveCreditBalance(CreditAccountProvider accountProvider) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accountProvider.getAccount() + .flatMap(CreditAccount::getCreditBalance); // in case your getter already return Optional, you cannot use + // Optional#map() because it will create Optional>. In this case Optional#flatMap() should be used } @@ -121,7 +140,10 @@ public static Optional retrieveCreditBalance(CreditAccountProvider a * @return optional gmail account */ public static Optional retrieveAccountGmail(AccountProvider accountProvider) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accountProvider.getAccount() + .filter(account -> account.getEmail().split("@")[1].equals("gmail.com")); + // in case you need to check if an Optional Account meets some criteria and return it or if it does not + // then return Optional.empty() and do that in a null-safe manner } /** @@ -134,7 +156,9 @@ public static Optional retrieveAccountGmail(AccountProvider accountProv * @return account got from either accountProvider or fallbackProvider */ public static Account getAccountWithFallback(AccountProvider accountProvider, AccountProvider fallbackProvider) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accountProvider.getAccount() + .or(fallbackProvider::getAccount) // allows to use another Optional in case main Optional is empty + .orElseThrow(); // if both providers return Optional.empty() it throws NoSuchElementException } /** @@ -145,7 +169,9 @@ public static Account getAccountWithFallback(AccountProvider accountProvider, Ac * @return account with the highest balance */ public static Account getAccountWithMaxBalance(List accounts) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accounts.stream() + .max(comparing(Account::getBalance)) // as you probably know Stream#min() and Stream#max() return Optional + .orElseThrow(); } /** @@ -155,7 +181,10 @@ public static Account getAccountWithMaxBalance(List accounts) { * @return the lowest balance values */ public static OptionalDouble findMinBalanceValue(List accounts) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accounts.stream() + .map(Account::getBalance) // map all stream accounts to balances + .mapToDouble(BigDecimal::doubleValue) // map all balances to primitive double values (returns DoubleStream) + .min(); // Optional API provides special classes for primitives as well } /** @@ -165,7 +194,10 @@ public static OptionalDouble findMinBalanceValue(List accounts) { * @param accountService */ public static void processAccountWithMaxBalance(List accounts, AccountService accountService) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + accounts.stream() + .max(comparing(Account::getBalance)) // returns Optional account + .ifPresent(accountService::processAccount); // declarative if statement and processing + // the last method requires Consumer as argument, it is implements using method reference } /** @@ -175,7 +207,11 @@ public static void processAccountWithMaxBalance(List accounts, AccountS * @return total credit balance */ public static double calculateTotalCreditBalance(List accounts) { - throw new UnsupportedOperationException("Some people say that method does not work until you implement it"); + return accounts.stream() + .map(CreditAccount::getCreditBalance) // transforms each element of stream into Optional + .flatMap(Optional::stream) // uses special Optional#stream() to filter all elements that are empty + .mapToDouble(BigDecimal::doubleValue) // transform BigDecimal into primitive double (returns DoubleStream) + .sum(); // calculates a sum of primitive double } } diff --git a/crazy-streams/src/main/java/com.bobocode/CrazyStreams.java b/crazy-streams/src/main/java/com.bobocode/CrazyStreams.java index 268ea0a..188474a 100644 --- a/crazy-streams/src/main/java/com.bobocode/CrazyStreams.java +++ b/crazy-streams/src/main/java/com.bobocode/CrazyStreams.java @@ -2,6 +2,7 @@ import com.bobocode.exception.EntityNotFoundException; import com.bobocode.model.Account; +import com.bobocode.model.Sex; import java.math.BigDecimal; import java.time.Month; @@ -10,6 +11,19 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Stream; + +import static java.util.Comparator.comparing; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.counting; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.partitioningBy; +import static java.util.stream.Collectors.reducing; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; /** * Implement methods using Stream API @@ -31,7 +45,8 @@ private CrazyStreams(Collection accounts) { * @return account with max balance wrapped with optional */ public Optional findRichestPerson() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .max(comparing(Account::getBalance)); } /** @@ -41,7 +56,9 @@ public Optional findRichestPerson() { * @return a list of accounts */ public List findAccountsByBirthdayMonth(Month birthdayMonth) { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .filter(a -> a.getBirthday().getMonth().equals(birthdayMonth)) + .collect(toList()); } /** @@ -51,7 +68,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 UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .collect(partitioningBy(a -> a.getSex().equals(Sex.MALE))); } /** @@ -61,7 +79,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 UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .collect(groupingBy(a -> a.getEmail().split("@")[1])); } /** @@ -70,7 +89,9 @@ public Map> groupAccountsByEmailDomain() { * @return total number of letters of first and last names of all accounts */ public int getNumOfLettersInFirstAndLastNames() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .mapToInt(a -> a.getFirstName().length() + a.getLastName().length()) + .sum(); } /** @@ -79,7 +100,9 @@ public int getNumOfLettersInFirstAndLastNames() { * @return total balance of all accounts */ public BigDecimal calculateTotalBalance() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .map(Account::getBalance) + .reduce(BigDecimal.ZERO, BigDecimal::add); } /** @@ -88,7 +111,10 @@ public BigDecimal calculateTotalBalance() { * @return list of accounts sorted by first and last names */ public List sortByFirstAndLastNames() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .sorted(comparing(Account::getFirstName) + .thenComparing(Account::getLastName)) + .collect(toList()); } /** @@ -98,7 +124,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 UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .map(Account::getEmail) + .anyMatch(email -> email.split("@")[1].equals(emailDomain)); } /** @@ -109,7 +137,11 @@ public boolean containsAccountWithEmailDomain(String emailDomain) { * @return account balance */ public BigDecimal getBalanceByEmail(String email) { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + 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))); } /** @@ -118,7 +150,8 @@ public BigDecimal getBalanceByEmail(String email) { * @return map of accounts by its ids */ public Map collectAccountsById() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .collect(toMap(Account::getId, identity())); } /** @@ -129,17 +162,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 UnsupportedOperationException("It's your job to implement this method"); // todo + 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> groupFirstNamesByLastNames() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .collect(groupingBy(Account::getLastName, mapping(Account::getFirstName, toSet()))); } /** @@ -149,7 +185,9 @@ public Map> groupFirstNamesByLastNames() { * @return a map where a key is a birthday month and value is comma-separated first names */ public Map groupCommaSeparatedFirstNamesByBirthdayMonth() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .collect(groupingBy(a -> a.getBirthday().getMonth(), + mapping(Account::getFirstName, joining(", ")))); } /** @@ -159,7 +197,10 @@ public Map groupCommaSeparatedFirstNamesByBirthdayMonth() { * @return a map where key is a creation month and value is total balance of all accounts created in that month */ public Map groupTotalBalanceByCreationMonth() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .collect(groupingBy(a -> a.getCreationDate().getMonth(), + mapping(Account::getBalance, + reducing(BigDecimal.ZERO, BigDecimal::add)))); } /** @@ -169,7 +210,11 @@ public Map groupTotalBalanceByCreationMonth() { * @return a map where key is a letter and value is its count in all first names */ public Map getCharacterFrequencyInFirstNames() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .map(Account::getFirstName) + .flatMapToInt(String::chars) + .mapToObj(c -> (char) c) + .collect(groupingBy(identity(), counting())); } /** @@ -179,7 +224,12 @@ public Map getCharacterFrequencyInFirstNames() { * @return a map where key is a letter and value is its count ignoring case in all first and last names */ public Map getCharacterFrequencyIgnoreCaseInFirstAndLastNames() { - throw new UnsupportedOperationException("It's your job to implement this method"); // todo + return accounts.stream() + .flatMap(a -> Stream.of(a.getFirstName(), a.getLastName())) + .map(String::toLowerCase) + .flatMapToInt(String::chars) + .mapToObj(c -> (char) c) + .collect(groupingBy(identity(), counting())); } } diff --git a/declarative-sum-of-squares/src/main/java/com/bobocode/SumOfSquares.java b/declarative-sum-of-squares/src/main/java/com/bobocode/SumOfSquares.java index fc0dfde..56736c2 100644 --- a/declarative-sum-of-squares/src/main/java/com/bobocode/SumOfSquares.java +++ b/declarative-sum-of-squares/src/main/java/com/bobocode/SumOfSquares.java @@ -3,6 +3,8 @@ import com.bobocode.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 @@ -17,7 +19,7 @@ public static void main(String[] args) { * This method calculates the sum of squares of integer in the range * * @param startInclusive first element in range - * @param endInclusive last element in range + * @param endInclusive last element in range * @return the sum of squares of each element in the range */ static int calculateSumOfSquaresInRange(int startInclusive, int endInclusive) { @@ -25,11 +27,8 @@ static int calculateSumOfSquaresInRange(int startInclusive, int endInclusive) { throw new InvalidRangeException(); } - // todo: refactor using functional approach - 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/file-reader/src/main/java/com/bobocode/FileReaderException.java b/file-reader/src/main/java/com/bobocode/FileReaderException.java new file mode 100644 index 0000000..d225b9a --- /dev/null +++ b/file-reader/src/main/java/com/bobocode/FileReaderException.java @@ -0,0 +1,7 @@ +package com.bobocode; + +public class FileReaderException extends RuntimeException { + public FileReaderException(String message, Exception e) { + super(message, e); + } +} diff --git a/file-reader/src/main/java/com/bobocode/FileReaders.java b/file-reader/src/main/java/com/bobocode/FileReaders.java index 562a15b..1de4fa5 100644 --- a/file-reader/src/main/java/com/bobocode/FileReaders.java +++ b/file-reader/src/main/java/com/bobocode/FileReaders.java @@ -1,5 +1,16 @@ package com.bobocode; +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} privides an API that allow to read whole file into a {@link String} by file name. */ @@ -12,6 +23,27 @@ public class FileReaders { * @return string that holds whole file content */ public static String readWholeFile(String fileName) { - throw new UnsupportedOperationException("It's your job to make it work!"); //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/file-stats/src/main/java/com/bobocode/FileStats.java b/file-stats/src/main/java/com/bobocode/FileStats.java index 1103cb3..0a95b7d 100644 --- a/file-stats/src/main/java/com/bobocode/FileStats.java +++ b/file-stats/src/main/java/com/bobocode/FileStats.java @@ -1,10 +1,28 @@ package com.bobocode; +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. * @@ -12,7 +30,47 @@ public class FileStats { * @return new FileStats object created from text file */ public static FileStats from(String fileName) { - throw new UnsupportedOperationException("It's your job to make it work!"); //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())); } /** @@ -22,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 UnsupportedOperationException("It's your job to make it work!"); //todo + return characterCountMap.get(character).intValue(); } /** @@ -31,7 +89,15 @@ public int getCharCount(char character) { * @return the most frequently appeared character */ public char getMostPopularCharacter() { - throw new UnsupportedOperationException("It's your job to make it work!"); //todo + return mostPopularCharacter; + } + + private char findMostPopularCharacter(Map characterCountMap) { + return characterCountMap.entrySet() + .stream() + .max(Comparator.comparing(Map.Entry::getValue)) + .get() + .getKey(); } /** @@ -41,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 UnsupportedOperationException("It's your job to make it work!"); //todo + return characterCountMap.containsKey(character); } } diff --git a/lambda-math-functions/src/main/java/com.bobocode/Functions.java b/lambda-math-functions/src/main/java/com.bobocode/Functions.java index 73a32fd..f983960 100644 --- a/lambda-math-functions/src/main/java/com.bobocode/Functions.java +++ b/lambda-math-functions/src/main/java/com.bobocode/Functions.java @@ -1,5 +1,7 @@ package com.bobocode; +import static java.lang.Math.abs; + public class Functions { /** * A static factory method that creates an integer function map with basic functions: @@ -14,7 +16,11 @@ public class Functions { public static FunctionMap intFunctionMap() { FunctionMap intFunctionMap = new FunctionMap<>(); - // todo: add simple functions to the function map (abs, sgn, increment, decrement, square) + 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/linked-list/src/main/java/com/bobocode/LinkedList.java b/linked-list/src/main/java/com/bobocode/LinkedList.java index bd6176a..49eafd4 100644 --- a/linked-list/src/main/java/com/bobocode/LinkedList.java +++ b/linked-list/src/main/java/com/bobocode/LinkedList.java @@ -1,5 +1,8 @@ package com.bobocode; +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 * inner static class {@link Node}. In order to keep track on nodes, {@link LinkedList} keeps a reference to a head node. @@ -7,6 +10,21 @@ * @param generic type parameter */ public class LinkedList implements List { + final static class Node { + private T element; + private Node next; + + private Node(T element) { + this.element = element; + } + + static Node valueOf(T element) { + return new Node<>(element); + } + } + + private Node head; + private int size; /** * This method creates a list of provided elements @@ -16,7 +34,9 @@ public class LinkedList implements List { * @return a new list of elements the were passed as method parameters */ public static List of(T... elements) { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + List list = new LinkedList<>(); + Stream.of(elements).forEach(list::add); + return list; } /** @@ -26,7 +46,7 @@ public static List of(T... elements) { */ @Override public void add(T element) { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + add(size, element); } /** @@ -38,7 +58,16 @@ public void add(T element) { */ @Override public void add(int index, T element) { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + Node newNode = Node.valueOf(element); + if (index == 0) { + newNode.next = head; + head = newNode; + } else { + Node node = findNodeByIndex(index - 1); + newNode.next = node.next; + node.next = newNode; + } + size++; } /** @@ -50,7 +79,8 @@ public void add(int index, T element) { */ @Override public void set(int index, T element) { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + Node node = findNodeByIndex(index); + node.element = element; } /** @@ -62,7 +92,17 @@ public void set(int index, T element) { */ @Override public T get(int index) { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + Node node = findNodeByIndex(index); + return node.element; + } + + private Node findNodeByIndex(int index) { + Objects.checkIndex(index, size); + Node currentNode = head; + for (int i = 0; i < index; i++) { + currentNode = currentNode.next; + } + return currentNode; } /** @@ -73,10 +113,16 @@ public T get(int index) { */ @Override public void remove(int index) { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + if (index == 0) { + Objects.checkIndex(index, size); + head = head.next; + } else { + Node previousNode = findNodeByIndex(index - 1); + previousNode.next = previousNode.next.next; + } + size--; } - /** * Checks if a specific exists in he list * @@ -84,7 +130,14 @@ public void remove(int index) { */ @Override public boolean contains(T element) { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + Node currentNode = head; + while (currentNode != null) { + if (currentNode.element.equals(element)) { + return true; + } + currentNode = currentNode.next; + } + return false; } /** @@ -94,7 +147,7 @@ public boolean contains(T element) { */ @Override public boolean isEmpty() { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + return head == null; } /** @@ -104,7 +157,7 @@ public boolean isEmpty() { */ @Override public int size() { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + return size; } /** @@ -112,6 +165,7 @@ public int size() { */ @Override public void clear() { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + head = null; + size = 0; } -} +} \ No newline at end of file diff --git a/linked-queue/src/main/java/com/bobocode/LinkedQueue.java b/linked-queue/src/main/java/com/bobocode/LinkedQueue.java index 3cde892..4afb27f 100644 --- a/linked-queue/src/main/java/com/bobocode/LinkedQueue.java +++ b/linked-queue/src/main/java/com/bobocode/LinkedQueue.java @@ -8,6 +8,22 @@ * @param a generic parameter */ 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. @@ -15,7 +31,14 @@ public class LinkedQueue implements Queue { * @param element the element to add */ public void add(T element) { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + Node newNode = Node.valueOf(element); + if (head == null) { + head = tail = newNode; + } else { + tail.next = newNode; + tail = newNode; + } + size++; } /** @@ -24,7 +47,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 UnsupportedOperationException("This method is not implemented yet"); // 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; + } } /** @@ -33,7 +66,7 @@ public T poll() { * @return an integer value that is a size of queue */ public int size() { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + return size; } /** @@ -42,6 +75,6 @@ public int size() { * @return {@code true} if the queue is empty, returns {@code false} if it's not */ public boolean isEmpty() { - throw new UnsupportedOperationException("This method is not implemented yet"); // todo: implement this method + return head == null; } }