Skip to content

Commit 4633697

Browse files
committed
avoid creating a new Either where not necessary, add filterLeft
1 parent 8115e0a commit 4633697

File tree

4 files changed

+84
-23
lines changed

4 files changed

+84
-23
lines changed

src/main/java/io/jbock/util/Either.java

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ public static <L, R> Either<L, R> right(R value) {
8787
* @param <R2> the new RHS type
8888
* @return an equivalent instance if this is a Left, otherwise a Right containing
8989
* the result of applying {@code mapper} to the RHS value
90+
* @throws NullPointerException if the {@code mapper} returns a {@code null} result
9091
*/
91-
public final <R2> Either<L, R2> map(Function<? super R, ? extends R2> mapper) {
92-
return fold(Either::left, r -> right(mapper.apply(r)));
93-
}
92+
public abstract <R2> Either<L, R2> map(
93+
Function<? super R, ? extends R2> mapper);
9494

9595
/**
9696
* If this is a Right, returns the result of applying the mapper function to the RHS value.
@@ -101,22 +101,21 @@ public final <R2> Either<L, R2> map(Function<? super R, ? extends R2> mapper) {
101101
* @return an equivalent instance if this is a Left, otherwise the result of
102102
* applying {@code mapper} to the RHS value
103103
*/
104-
public final <R2> Either<L, R2> flatMap(
105-
Function<? super R, ? extends Either<? extends L, ? extends R2>> mapper) {
106-
return fold(Either::left, r -> narrow(mapper.apply(r)));
107-
}
104+
public abstract <R2> Either<L, R2> flatMap(
105+
Function<? super R, ? extends Either<? extends L, ? extends R2>> mapper);
108106

109107
/**
110108
* If this is a Left, returns a Left containing the LHS value.
111109
* If this is a Right, applies the predicate function to the RHS value.
112110
* If the predicate function returns an empty result,
113111
* returns a Right containing the RHS value.
114-
* If the result is not empty, returns a Left containing that result.
112+
* If the result is not empty, returns a Left containing the result.
115113
*
116114
* @param predicate a function that acts as a filter predicate
117115
* @return filter result
118116
*/
119-
public abstract Either<L, R> filter(Function<? super R, LeftOptional<? extends L>> predicate);
117+
public abstract Either<L, R> filter(
118+
Function<? super R, LeftOptional<? extends L>> predicate);
120119

121120
/**
122121
* If this is a Left, returns a Left containing the result of applying the mapper function to the LHS value.
@@ -126,8 +125,10 @@ public final <R2> Either<L, R2> flatMap(
126125
* @param <L2> the new LHS type
127126
* @return an equivalent instance if this is a Right, otherwise a Left containing
128127
* the result of applying {@code mapper} to the LHS value
128+
* @throws NullPointerException if the {@code mapper} returns a {@code null} result
129129
*/
130-
public abstract <L2> Either<L2, R> mapLeft(Function<? super L, ? extends L2> mapper);
130+
public abstract <L2> Either<L2, R> mapLeft(
131+
Function<? super L, ? extends L2> mapper);
131132

132133
/**
133134
* If this is a Left, returns the result of applying the mapper function to the LHS value.
@@ -141,6 +142,19 @@ public final <R2> Either<L, R2> flatMap(
141142
public abstract <L2> Either<L2, R> flatMapLeft(
142143
Function<? super L, ? extends Either<? extends L2, ? extends R>> mapper);
143144

145+
/**
146+
* If this is a Right, returns a Right containing the RHS value.
147+
* If this is a Left, applies the predicate function to the LHS value.
148+
* If the predicate function returns an empty result,
149+
* returns a Left containing the LHS value.
150+
* If the result is not empty, returns a Right containing the result.
151+
*
152+
* @param predicate a function that acts as a filter predicate
153+
* @return filter result
154+
*/
155+
public abstract Either<L, R> filterLeft(
156+
Function<? super L, Optional<? extends R>> predicate);
157+
144158
/**
145159
* If this is a Right, returns the RHS value.
146160
* Otherwise throws an exception produced by the exception supplying function.
@@ -150,7 +164,8 @@ public abstract <L2> Either<L2, R> flatMapLeft(
150164
* @return the RHS value, if this is a Right
151165
* @throws X the result of applying {@code exceptionSupplier} to the LHS value, if this is a Left
152166
*/
153-
public abstract <X extends Throwable> R orElseThrow(Function<? super L, ? extends X> exceptionSupplier) throws X;
167+
public abstract <X extends Throwable> R orElseThrow(
168+
Function<? super L, ? extends X> exceptionSupplier) throws X;
154169

155170
/**
156171
* If this is a Left, returns the result of applying the {@code leftMapper} to the LHS value.
@@ -165,15 +180,16 @@ public abstract <U> U fold(
165180
Function<? super L, ? extends U> leftMapper,
166181
Function<? super R, ? extends U> rightMapper);
167182

168-
169183
/**
170184
* If this is a Left, performs the {@code leftAction} with the LHS value.
171185
* Otherwise performs the {@code rightAction} with the RHS value.
172186
*
173187
* @param leftAction action to run if this is a Left
174188
* @param rightAction action to run if this is a Right
175189
*/
176-
public abstract void ifPresentOrElse(Consumer<? super L> leftAction, Consumer<? super R> rightAction);
190+
public abstract void ifPresentOrElse(
191+
Consumer<? super L> leftAction,
192+
Consumer<? super R> rightAction);
177193

178194
/**
179195
* Returns {@code true} if this is a Left, otherwise {@code false}.

src/main/java/io/jbock/util/Left.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ public Optional<R> getRight() {
3232
return Optional.empty();
3333
}
3434

35+
@Override
36+
public <R2> Either<L, R2> map(Function<? super R, ? extends R2> mapper) {
37+
return same();
38+
}
39+
40+
@Override
41+
public <R2> Either<L, R2> flatMap(Function<? super R, ? extends Either<? extends L, ? extends R2>> mapper) {
42+
return same();
43+
}
44+
3545
@Override
3646
public Either<L, R> filter(Function<? super R, LeftOptional<? extends L>> predicate) {
3747
return same();
@@ -47,6 +57,15 @@ public <L2> Either<L2, R> flatMapLeft(Function<? super L, ? extends Either<? ext
4757
return narrow(mapper.apply(value));
4858
}
4959

60+
@Override
61+
public Either<L, R> filterLeft(Function<? super L, Optional<? extends R>> predicate) {
62+
Optional<? extends R> test = predicate.apply(value);
63+
if (test.isEmpty()) {
64+
return same();
65+
}
66+
return Right.create(test.orElseThrow());
67+
}
68+
5069
@Override
5170
public <X extends Throwable> R orElseThrow(Function<? super L, ? extends X> exceptionSupplier) throws X {
5271
throw exceptionSupplier.apply(value);
@@ -90,7 +109,7 @@ public int hashCode() {
90109

91110
@SuppressWarnings("unchecked")
92111
private <R2> Either<L, R2> same() {
93-
// return new Left<>(value);
112+
// equivalently: return new Left<>(value);
94113
return (Either<L, R2>) this;
95114
}
96115
}

src/main/java/io/jbock/util/Right.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ public Optional<R> getRight() {
3232
return Optional.of(value);
3333
}
3434

35+
@Override
36+
public <R2> Either<L, R2> map(Function<? super R, ? extends R2> mapper) {
37+
return create(mapper.apply(value));
38+
}
39+
40+
@Override
41+
public <R2> Either<L, R2> flatMap(Function<? super R, ? extends Either<? extends L, ? extends R2>> mapper) {
42+
return narrow(mapper.apply(value));
43+
}
44+
3545
@Override
3646
public Either<L, R> filter(Function<? super R, LeftOptional<? extends L>> predicate) {
3747
LeftOptional<? extends L> test = predicate.apply(value);
@@ -51,6 +61,11 @@ public <L2> Either<L2, R> flatMapLeft(Function<? super L, ? extends Either<? ext
5161
return same();
5262
}
5363

64+
@Override
65+
public Either<L, R> filterLeft(Function<? super L, Optional<? extends R>> predicate) {
66+
return same();
67+
}
68+
5469
@Override
5570
public <X extends Throwable> R orElseThrow(Function<? super L, ? extends X> exceptionSupplier) throws X {
5671
return value;
@@ -94,7 +109,7 @@ public int hashCode() {
94109

95110
@SuppressWarnings("unchecked")
96111
private <L2> Either<L2, R> same() {
97-
// return new Right<>(value);
112+
// equivalently: return new Right<>(value);
98113
return (Either<L2, R>) this;
99114
}
100115
}

src/test/java/io/jbock/util/EitherTest.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import static org.junit.jupiter.api.Assertions.assertEquals;
1111
import static org.junit.jupiter.api.Assertions.assertFalse;
12+
import static org.junit.jupiter.api.Assertions.assertSame;
1213
import static org.junit.jupiter.api.Assertions.assertThrows;
1314
import static org.junit.jupiter.api.Assertions.assertTrue;
1415

@@ -53,16 +54,16 @@ void testGetRight() {
5354
@Test
5455
void testMap() {
5556
Either<String, String> left = Either.left("1");
56-
assertEquals(left, left.map(s -> "A")); // Left is unchanged
57+
assertSame(left, left.map(s -> "A")); // Left is unchanged
5758
Either<?, String> right = Either.right("1");
5859
assertEquals(Either.right(1), right.map(Integer::parseInt));
5960
}
6061

6162
@Test
6263
void testFlatMap() {
6364
Either<Integer, String> left = Either.left(2);
64-
assertEquals(left, left.flatMap(s -> Either.right("1"))); // Left is unchanged
65-
assertEquals(left, left.flatMap(s -> Either.left(1))); // Left is unchanged
65+
assertSame(left, left.flatMap(s -> Either.right("1"))); // Left is unchanged
66+
assertSame(left, left.flatMap(s -> Either.left(1))); // Left is unchanged
6667
Either<Integer, String> right = Either.right("1");
6768
assertEquals(Either.right(11), right.flatMap(s -> Either.right(11)));
6869
assertEquals(Either.left(11), right.flatMap(s -> Either.left(11)));
@@ -73,7 +74,7 @@ void testMapLeft() {
7374
Either<String, ?> left = Either.left("1");
7475
assertEquals(Either.left(1), left.mapLeft(Integer::parseInt));
7576
Either<String, String> right = Either.right("1");
76-
assertEquals(right, right.mapLeft(s -> "A")); // Right is unchanged
77+
assertSame(right, right.mapLeft(s -> "A")); // Right is unchanged
7778
}
7879

7980
@Test
@@ -82,20 +83,30 @@ void testFlatMapLeft() {
8283
assertEquals(Either.left(11), left.flatMapLeft(s -> Either.left(11)));
8384
assertEquals(Either.right(11), left.flatMapLeft(s -> Either.right(11)));
8485
Either<String, Integer> right = Either.right(2);
85-
assertEquals(right, right.flatMapLeft(s -> Either.left("1"))); // Right is unchanged
86-
assertEquals(right, right.flatMapLeft(s -> Either.right(1))); // Right is unchanged
86+
assertSame(right, right.flatMapLeft(s -> Either.left("1"))); // Right is unchanged
87+
assertSame(right, right.flatMapLeft(s -> Either.right(1))); // Right is unchanged
8788
}
8889

8990
@Test
9091
void testFilter() {
9192
Either<String, ?> left = Either.left("1");
92-
assertEquals(left, left.filter(r -> LeftOptional.of("2"))); // Left is unchanged
93-
assertEquals(left, left.filter(r -> LeftOptional.empty())); // Left is unchanged
93+
assertSame(left, left.filter(r -> LeftOptional.of("2"))); // Left is unchanged
94+
assertSame(left, left.filter(r -> LeftOptional.empty())); // Left is unchanged
9495
Either<String, String> right = Either.right("1");
9596
assertEquals(Either.left("2"), right.filter(r -> LeftOptional.of("2")));
9697
assertEquals(right, right.filter(r -> LeftOptional.empty()));
9798
}
9899

100+
@Test
101+
void testFilterLeft() {
102+
Either<?, String> right = Either.right("1");
103+
assertSame(right, right.filterLeft(r -> Optional.of("2"))); // Right is unchanged
104+
assertSame(right, right.filterLeft(r -> Optional.empty())); // Right is unchanged
105+
Either<String, String> left = Either.left("1");
106+
assertEquals(Either.right("2"), left.filterLeft(r -> Optional.of("2")));
107+
assertEquals(left, left.filterLeft(r -> Optional.empty()));
108+
}
109+
99110
@Test
100111
void testOrElseThrow() {
101112
Either<String, ?> left = Either.left("1");

0 commit comments

Comments
 (0)