kevin-lee / j8plus Goto Github PK
View Code? Open in Web Editor NEWLibrary containing useful tools for Java 8
Home Page: https://j8plus.kevinly.dev
License: Other
Library containing useful tools for Java 8
Home Page: https://j8plus.kevinly.dev
License: Other
shh
for more FunctionsCurrently shh
works for only AnnoyingFunction
and AnnoyingBiFunction
.
e.g.)
// run does not take anything nor does it return any result.
doSomething(shh(() -> doItWithAnnoyance.run());
// accept returns nothing
doSomething(shh(x -> doItWithAnnoyance. accept(x)));
// get takes no argument and returns a result.
doSomething(shh(() -> doItWithAnnoyance.get());
shh
for the rest of the FunctionsFor practicality, it should support more functions types likes Consumer
, Supplier
, functions with more than two parameters.
// doItWithAnnoyance takes more than two arguments and returns a result
doSomething(shh((id, name, isMember, code) -> doItWithAnnoyance(id, name, isMember, code)));
// There should be shh for functions using primitive types. e.g.) BooleanSupplier, IntConsumer, IntFunction, etc.
Function types can be curried but there should be also utility functions for currying. The reason for that is to make any existing methods useful which means method references can be curried. For the first step, currying
methods should be added for Function types.
e.g.)
public class Something {
public String checkIt2(Integer i1, Integer i2) {
return "The params are " + i1 + " and " + i2 + ".";
}
public String checkIt3(Integer i1, Integer i2, Integer i3) {
return "The params are " + i1 + ", " + i2 + " and " + i3 + ".";
}
}
// Then checkIt2 and checkIt3 can be curried using currying methods.
import static cc.kevinlee.functional.spicy.Curry.*;
final Something something = new Something();
final Function<Integer, String> function = currying(something::checkIt2, 1);
System.out.println(function.apply(2)); // result: "The params are 1 and 2."
final Function2<Integer, Integer, String> function2 = currying(something::checkIt3, 1);
System.out.println(function2.apply(2, 3)); // result: "The params are 1, 2 and 3."
Add Maybe.toOptional
.
Version: 0.1.1
Add Maybe.toOptional
to convert Maybe
to Optional
.
Maybe.just(1).toOptional();
Maybe.<Integer>nothing().toOptional();
Fix Maybe.toString()
to handle nested Maybe
s properly
Version: 0.4.0
Current Maybe.toString()
when used on nested Maybe
s.
Maybe.maybe(Maybe.maybe(999));
// Maybe<Just> = Just(Maybe<Integer> = Just(999))
It should be
Maybe.maybe(Maybe.maybe(999));
// Maybe<Maybe<Integer>> = Just(Just(999))
More examples
Maybe.maybe(Maybe.maybe(Maybe.maybe(999)));
// Maybe<Maybe<Integer>> = Just(Just(Just(999)))
Maybe.maybe(Maybe.maybe(Maybe.nothing()));
// Maybe<Maybe<Maybe>> = Just(Just(Nothing))
Add Maybe
Add Maybe
which is similar to Java's Optional
but unlike Optional
, Maybe
is Serializable
. Optional
also has two factory methods which are of
and ofNullable
. of
throws a NPE
when null
is passed. Maybe
's just
should return Nothing
instead. It's not good to allow just to accept null
yet that's because of Java's nature. It's at least null-safe with that way.
Maybe.just(1) // Maybe<Integer> = Just(1)
Maybe.just<String>(null) // Maybe<String> = Nothing
Maybe.nothing<String>() // Maybe<String> = Nothing
map
and flatMap
Maybe.just(1).map(n -> n + 99) // Maybe<Integer> = Just(100)
Maybe.nothing<Integer>().map(n -> n * 2) // Maybe<Integer> = Nothing
final Integer maybeX = Maybe.just(123); // Maybe<Integer> = Just(123)
final Integer maybeY = Maybe.just(111); // Maybe<Integer> = Just(111)
maybeX.flatMap(x -> maybeY.map(y -> x + y)) // Maybe<Integer> = Just(234)
filter
Maybe.just(11).filter(x -> x < 10) // Maybe<Integer> = Nothing
Maybe.just(11).filter(x -> x > 10) // Maybe<Integer> = Just(11)
Maybe.nothing<Integer>().filter(x -> x >= 0) // Maybe<Integer> = Nothing
Maybe.nothing<Integer>().filter(x -> x < 0) // Maybe<Integer> = Nothing
Maybe.nothing<Integer>().filter(x -> true) // Maybe<Integer> = Nothing
ap
Maybe.just(5).ap(() -> Maybe.just(i -> i * 2)) // Maybe<Integer> = Just(10)
Maybe.nothing<Integer>().ap(() -> Maybe.nothing()) // Maybe<Integer> = Nothing
fold
(Catamorphism)Maybe.just(3).fold(x -> x * x, () -> 0) // Integer = 9
Maybe.just(3).fold(x -> x.toString, () -> "no value") // String = "3"
Maybe.nothing<Integer>().fold(x -> x * x, () -> 0) // Integer = 0
Maybe.nothing<Integer>().fold(x -> x.toString(), () -> "no value") // String = "no value"
getOrElse
Maybe.just(999).getOrElse(() -> 0) // Integer = 999
Maybe.nothing<Integer>().getOrElse(() -> 0) // Integer = 0
orElse
Maybe.just(999).orElse(() -> Maybe.just(111)) // Maybe<Integer> = 999
Maybe.nothing<Integer>().orElse(() -> Maybe.just(111)) // Maybe<Integer> = 111
isJust
/ isNothing
Maybe.just(999).isJust() // boolean = true
Maybe.just(999).isNothing() // boolean = false
Maybe.nothing<Integer>().isJust() // boolean = false
Maybe.nothing<Integer>().isNothing() // boolean = true
forEach
Maybe.just(5).forEach(System.out::println) // "5" is printed out
Maybe.nothing<Integer>().forEach(System.out::println) // nothing happens.
fromEither
final Either<String, Integer> a = Either.right(123);
Maybe.fromEither(a) // Maybe<Integer> = Just(123)
final Either<String, Integer> b = Either.left("error");
Maybe.fromEither(b) // Maybe<Integer> = Nothing
fromOptional
final Optional<String> a = Optional.ofNullable(null); // Optional.empty
Maybe.fromOptional(a) // Maybe<String> = Nothing
final Optional<String> a = Optional.ofNullable("abc"); // Optional<String> // Optional(abc)
Maybe.fromOptional(a) // Maybe<String> = Just("abc")
Java APIs are still tightly coupled to checked Exception which makes it hard to work with lambda expressions or method references.
So for instance, if a method takes a functional interface, which does not throw any checked exception, as a parameter and the actual one passed is a method reference that throws a checked one (or a lambda expression which may throw it), it will cause a compile time error.
e.g.)
private <E, T> T doItWithAnnoyance(E whatEver) throws Exception {
throw new Exception("Annoying exception!");
}
private static <E, T> T testSomething(E someInput, Function<E, T> function) {
return function.apply(someInput);
}
// ...
testSomething(whatever, this::doItWithAnnoyance); // <- compile time error: Unhandled exception: java.lang.Exception
testSomething(null, x -> doItWithAnnoyance(x)); // <- compile time error: Unhandled exception: java.lang.Exception
// ...
A solution might be wrapping the lambda expression or method reference with a higher-order function which catches any checked exception and throws unchecked one instead.
e.g.)
testSomething(whatever, shh(this::doItWithAnnoyance)); // <- NO compile time error anymore
testSomething(null, shh(x -> doItWithAnnoyance(x))); // <- NO compile time error anymore
This is a sub-task for shh for more functions (#28).
AnnoyingPredicate
typeAnnoyingPredicate
AnnoyingBiPredicate
typeAnnoyingBiPredicate
This is a sub-task for shh for more functions (#68).
AnnoyingBooleanPredicate
, AnnoyingDoublePredicate
, AnnoyingIntPredicate
and AnnoyingLongPredicate
typesAnnoyingBooleanPredicate
, AnnoyingDoublePredicate
, AnnoyingIntPredicate
and AnnoyingLongPredicate
.Add Either.doIfRight
Version: 1.0.1
Each FunctionN interface
in types
package (functional interface) should have curried
which returns curried Function.
e.g.)
final Function4<Integer, Integer, Integer, Integer, Integer> f4 = (i1, i2, i3, i4) -> i1 + i2 + i3 + i4;
final Function3<Integer, Integer, Integer, Integer> plus1000 = f4.curried(1000);
System.out.println(plus1000.apply(200, 30, 4)); // result: 1234
System.out.println(plus1000.apply(1, 2, 3)); // result: 1006
It also requires to have Function2<T1, T2, R>
which extends java.util.function.BiFunction<T, U, R>
. The Function2
should have curried method returns java.util.function.Function<T, R>
.
e.g.)
final Function2<Integer, Integer, Integer> f2 = (i1, i2) -> i1 + i2;
final Function<Integer, Integer> plus1 = f2.curried(1);
System.out.println(plus1.apply(1)); // result: 2
System.out.println(plus1.apply(9)); // result: 10
Change the just
method to maybe
Version: 0.4.0
Current:
Maybe.just(null) // Nothing
Maybe.just(1) // Just(1)
New:
Maybe.maybe(null) // Nothing
Maybe.maybe(1) // Just(1)
Swap Maybe.fold
parameters.
Version: 0.1.1
Current Maybe.fold
has parameters handling a just case then a nothing case in order.
Change Maybe.fold(just case, nothing case)
to Maybe.fold(nothing case, just case)
.
Maybe.just(1).fold(() -> "no number", i -> "number: " + i)
// String = number: 1
Maybe.<Integer>nothing().fold(() -> "no number", i -> "number: " + i)
// String = no number
Change cc.kevinlee.functional.Functions
to cc.kevinlee.functional.Funs
to make it more fun!
Also cc.kevinlee.functional.types.annoying.AnnoyingFunctions
to cc.kevinlee.functional.types.annoying.AnnoyingFuns
Well, Functions
is kind of too long especially when using a ClassName.method()
way.
Functions.applying(...) // too long!
I was thinking about making it even F
or Fs
but there were issues.
F
might look like a generic type parameter.Fs
might sound weird to Java programmers who are more familiar with longer descriptive words like ConcurrentHashMap
, LinkedList
, etc.So Funs
is just enough to have lots of fun!
Add Maybe.toEither
Version: 0.1.1
Add Maybe.toEither
to convert Maybe
to Either
. Maybe.toEither()
takes Supplier
to handle Left
case.
Maybe.just(1).toEither(() -> "error");
Maybe.<Integer>nothing().toEither(() -> "error");
Each ConsumerN interface
in types
package (functional interface) should have curried
which returns curried Consumer just like Functions.
e.g.)
final Consumer2<Integer, Integer> addAndPrint = (i1, i2) -> System.out.println("i1 + i2 = " + (i1 + i2));
final Consumer<Integer> addTenAndPrint = addAndPrint.curried(10);
System.out.println(addAndPrint.accept(1 , 2)); // result: i1 + i2 = 3
System.out.println(addTenAndPrint.accept(101)); // result: i1 + i2 = 111
It also requires to have Consumer2<T1, T2>
which extends java.util.function.BiConsumer<T, U>
. The Consumer2
should have curried method returns java.util.function.Consumer<T>
.
Add runOrRethrowCause
Version: 0.2.0
public void foo() throws RuntimeException {
try {
// some code
doSomething();
} catch (final SomeException ex) {
throw new RuntimeException(ex);
}
}
runOrRethrowCause(SomeException.class, () -> foo()) // will throw SomeException
Add Either.getLeftOrElse
Version: 1.0.1
Either.<String, Integer>right(1).getLeftOrElse(() -> "Default"); // String = Default
Either.<String, Integer>left("ERROR").getLeftOrElse(() -> "Default"); // String = ERROR
Add Either
type
Either
type should be added to handle some cases where the expected data is either one or something else (e.g. either SomeError
or Result
).
e.g.) Exception handling. If a method may throw an exception, it can be like.
public Either<SomeError, User> doSomething(final String id) {
try {
final Something something = doActualWork(id);
return Either.right(something);
}
catch (final SomeRuntimeExeption e) {
return Either.left(new SomeError(e));
}
}
public class UserError {
public abstract String getMessage();
static class UserNotFound extends UserError {
private final String id;
public UserNotFound(String id) {
this.id = id;
}
@Override
public String getMessage() {
return "User with the given id, " + id +", not found";
}
}
public static UserError userNotFound(final String id) {
return new UserNotFound(id);
}
}
public Either<UserError, User> updateEmail(final String id, final Email email) {
return Either.fromOptional(
findUser(id)
, () -> UserError.userNotFound(id)
)
.map(user -> user.setEmail(email));
}
Either<A, B>
should be right-biased meaning the function passed to map
and flatMap
should be applied on B
not A
.
final Either<UserNotFoundError, User> userFound = UserService.findUser(id);
return userFound.map(
User::getFullName // getFullName returns String
);
// result might be either Left(UserNotFoundError)
// or Right("User's full name")
For operation on Left
, leftMap
and leftFlatMap
are used.
final Either<UserNotFoundError, User> userFound = UserService.findUser(id);
return userFound.leftMap(
UserNotFoundError::getMessage // getMessage returns String
);
// result might be either Left(String)
// or Right(User)
There should be an easy way to use any given value depending on any given condition. It if the given predicate is satisfied using the given value, it use the value. Otherwise, it uses the given alternative value. Calculation or evaluation of the alternative value might be expensive so it should be lazily evaluated if and only if it is required.
So the call site looks like,
final Integer num1 = 5;
final Integer result1 = useIfSatisfy(num1, i -> i > 0, () -> 1); // result: 5 as 5 is greater than 0.
final Integer result2 = useIfSatisfy(num1, i -> i < 0, () -> -1); // result: -1 as 5 is NOT less than 0 so it uses
// the alternative returned from the given function (lazily evaluated).
Add getOrRethrowCause
with Predicate
Version: 0.3.0
public <T> T doItThrowingMyException() throws Exception {
throw new MyException("This is MyException!");
}
AnnoyingFuns.getOrRethrowCause(
throwable -> throwable instanceof MyException,
AnnoyingFuns.shh(() -> doItThrowingMyException())
) // It will throw MyException instead of RuntimeException with MyException as its cause
This is a sub-task for shh for more functions (#68).
AnnoyingBooleanConsumer
, AnnoyingDoubleConsumer
, AnnoyingIntConsumer
and AnnoyingLongConsumer
typesAnnoyingBooleanConsumer
, AnnoyingDoubleConsumer
, AnnoyingIntConsumer
and AnnoyingLongConsumer
.This is a sub-task for shh for more functions (#68).
AnnoyingBooleanSupplier
, AnnoyingDoubleSupplier
, AnnoyingIntSupplier
and AnnoyingLongSupplier
typesAnnoyingBooleanSupplier
, AnnoyingDoubleSupplier
, AnnoyingIntSupplier
and AnnoyingLongSupplier
.Make Either.Left
and Either.Right
final.
This is a sub-task for shh for more functions (#28).
AnnoyingSupplier
typeAnnoyingSupplier
This is a sub-task for shh for more functions (#68).
AnnoyingPredicate3
typeAnnoyingPredicate3
AnnoyingPredicate4
typeAnnoyingPredicate4
AnnoyingPredicate5
typeAnnoyingPredicate5
AnnoyingPredicate6
typeAnnoyingunction6
AnnoyingPredicate7
typeAnnoyingPredicate7
AnnoyingPredicate8
typeAnnoyingPredicate8
AnnoyingPredicate9
typeAnnoyingPredicate9
AnnoyingPredicate10
typeAnnoyingPredicate10
This is a sub-task for shh for more functions (#28).
AnnoyingConsumer
typeAnnoyingConsumer
The current build.sbt
has test dependency libs as normal compile
ones.
libraryDependencies ++= List(
"junit" % "junit" % s"${junitVersion}",
"cc.kevinlee" % "test0ster1" % s"${testosteroneVersion}" % "test",
"org.assertj" % "assertj-core" % "3.0.0",
"org.mockito" % "mockito-all" % "1.10.19",
"org.elixirian" % "kommonlee-test" % "0.0.18-SNAPSHOT"
)
This has to be
libraryDependencies ++= List(
"junit" % "junit" % s"${junitVersion}" % "test",
"cc.kevinlee" % "test0ster1" % s"${testosteroneVersion}" % "test",
"org.assertj" % "assertj-core" % "3.0.0" % "test",
"org.mockito" % "mockito-all" % "1.10.19" % "test",
"org.elixirian" % "kommonlee-test" % "0.0.18-SNAPSHOT" % "test"
)
Because these are all for only testing.
Each PredicateN interface
in types
package (functional interface) should have curried
which returns curried Predicate just like Functions.
e.g.)
final Predicate2<Integer, Integer> twoPositives = (i1, i2) -> i1 > 0 && i2;
final Predicate<Integer> onePositive = twoPositives.curried(1);
System.out.println(twoPositives.test(1 , 2)); // result: true
System.out.println(onePositive.test(2)); // result: true
System.out.println(onePositive.test(-1)); // result: false
It also requires to have Predicate2<T1, T2>
which extends java.util.function.BiPredicate<T, U>
. The Predicate2
should have curried method returns java.util.function.Predicate<T>
.
Fix the duplicate XML elements in pom.xml
generated by sbt when publishing.
The current pom setup in build.sbt
causes the following problems when publishing to Maven Central
/io/kevinlee/j8plus/0.1.0/j8plus-0.1.0.pom Duplicated tag: 'url' (position: START_TAG seen ...</developers>\n <url>... @34:10) Invalid POM: /io/kevinlee/j8plus/0.1.0/j8plus-0.1.0.pom: Parsing Error: Duplicated tag: 'url' (position: START_TAG seen ...</developers>\n <url>... @34:10) Dropping existing partial staging repository.
The duplicate elements were added as build.sbt
contains pomExtra
which has elements already added by other sbt SettingKey
s.
Remove the pomExtra
as the elements in pomExtra
are set by other settings.
Add Either.toMaybe
Version: 0.1.1
Add Either.toMaybe
to convert Either
to Maybe
.
Either.<String, Integer>right(1).toMaybe();
Either.<String, Integer>left("error").toMaybe();
Add runOrRethrowCause
with Predicate
Version: 0.3.0
public void doItThrowingMyException() throws Exception {
throw new MyException("This is MyException!");
}
AnnoyingFuns.runOrRethrowCause(
throwable -> throwable instanceof MyException,
AnnoyingFuns.shh(() -> doItThrowingMyException())
) // It will throw MyException instead of RuntimeException with MyException as its cause
As Java 8 still doesn't have any tuple types, it would be better to have one in J8+.
It might looks like
final Pair<Integer, String> idAndName = tuple(1, "Kevin");
final Tuple2<Integer, String> idAndName = tuple(1, "Kevin");
final Tuple3<Integer, String, Boolean> idNameAndActive = tuple(1, "Kevin", true);
// and so on
Does Tuple have to be a Product type? If so, should Product type be added as well? ๐ค
Set up GitHub Actions.
Make Maybe
Serializable
.
Add Either.toOptional
Version: 0.1.1
Add Either.toOptional
to convert Either
to Optional
.
Either.<String, Integer>right(1).toOptional();
Either.<String, Integer>left("error").toOptional();
Change toString
to show Just
and Nothing
are Maybe
.
Version: 0.4.0
Current:
Maybe.just(1).toString() // Just(1)
Maybe.nothing() // Nothing
New:
Maybe.just(1).toString() // Maybe<Integer> = Just(1)
Maybe.nothing() // Maybe = Nothing
This is a sub-task for shh for more functions (#28).
AnnoyingRunnable
and AnnoyingRunner
typesAnnoyingRunnable
and AnnoyingRunner
Current Functions.reversed()
returns Comparator<? super T>
and the given parameter is also Comparator<? super T>
. A problem of this is it cannot be assigned to a variable for the Comparator of T type.
e.g.)
final Comparator<Integer> intCmp = Integer::compareTo;
final Comparator<Integer> reversedIntCmp = reversed(integerComparator); // compile-time error!
Add Either.getOrElse
Version: 1.0.1
Either.<String, Integer>right(1).getOrElse(() -> 999); // Integer = 1
Either.<String, Integer>left("ERROR").getOrElse(() -> 999); // Integer = 999
Publish using sbt 1.3.13
Version: 1.0.0
Because of this issue in sbt, j8plus doesn't work on some applications using Spring Boot with this bug.
So publish j8plus again with sbt 1.3.13.
This is a sub-task for shh for more functions (#68).
AnnoyingFunction3
typeAnnoyingFunction3
AnnoyingFunction4
typeAnnoyingFunction4
AnnoyingFunction5
typeAnnoyingFunction5
AnnoyingFunction6
typeAnnoyingFunction6
AnnoyingFunction7
typeAnnoyingFunction7
AnnoyingFunction8
typeAnnoyingFunction8
AnnoyingFunction9
typeAnnoyingFunction9
AnnoyingFunction10
typeAnnoyingFunction10
Array lacks some essential methods like isEmpty()
. In some cases, having this method can be useful.
An example might be like this.
final String uniqueWords =
listOfString.stream()
.map(this::doSomethingReturnsEmptyList) // List<String[]>
.flatMap(Arrays::stream)
.distinct()
.sorted()
.collect(joining(", "));
In this if the line
contains only white space chars, the result may contain and empty String so it may become like
Something, blah, , blah2
As you can see, there is an empty String between blah
and blah2
(blah
, ,blah2
).
This can be solved by
final String uniqueWords =
listOfString.stream()
.map(this::doSomethingReturnsEmptyList) // List<String[]>
.filter(each -> each.length != 0)
.flatMap(Arrays::stream)
.distinct()
.sorted()
.collect(joining(", "));
but words.length != 0
is too low-level code to check if an array is empty or not. This can be improved if there is isNotEmpty()
method for array.
final String uniqueWords =
listOfString.stream()
.map(this::doSomethingReturnsEmptyList) // List<String[]>
.filter(each -> ArrayFuns.isNotEmpty(each))
.flatMap(Arrays::stream)
.distinct()
.sorted()
.collect(joining(", "));
Or even a method reference can be used and it becomes more concise.
final String uniqueWords =
listOfString.stream()
.map(this::doSomethingReturnsEmptyList) // List<String[]>
.filter(ArrayFuns::isNotEmpty)
.flatMap(Arrays::stream)
.distinct()
.sorted()
.collect(joining(", "));
Change group id for publishing from kevinlee
to io.kevinlee
as it might be a problem when the project is published to any central repository.
Use Hedgehog for testing.
Create a doc website for J8+
Version:
Add rethrowCause
Version: 0.2.0
public Result foo() throws RuntimeException {
try {
// some code
return a;
} catch (final SomeException ex) {
throw new RuntimeException(ex);
}
}
getOrRethrowCause(SomeException.class, () -> foo()) // will throw SomeException
This is a sub-task for shh for more functions (#68).
AnnoyingBooleanFunction
, AnnoyingDoubleFunction
, AnnoyingIntFunction
and AnnoyingLongFunction
typesAnnoyingBooleanFunction
, AnnoyingDoubleFunction
, AnnoyingIntFunction
and AnnoyingLongFunction
.Add fromMaybe
to Either
.
final Maybe<Integer> maybeNumber = Maybe.just(1);
Either.fromMaybe(maybeNumber, () -> "No number found")
// Either<String, Integer> = Right(1)
final Maybe<Integer> maybeNumber = Maybe.<Integer>nothing();
Either.fromMaybe(maybeNumber, () -> "No number found")
// Either<String, Integer> = Left("No number found")
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.