Skip to content

Commit 5bdf4f6

Browse files
committed
feat: 调整join
1. join调整到独立目录 2. 移除Collection相关的api,精简接口数 3. 增加JoinOn类,简化flattenStream()的外部使用,外部可以不需要依赖flattenStream()
1 parent 8fc9f1e commit 5bdf4f6

5 files changed

Lines changed: 223 additions & 38 deletions

File tree

src/main/java/com/github/lokic/javaplus/NullData.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import java.util.List;
55
import java.util.stream.Stream;
66

7-
class NullData {
7+
public class NullData {
88
private static final List<?> NULL_LIST = createNullList();
99

1010
private static <T> List<T> createNullList() {

src/main/java/com/github/lokic/javaplus/Join.java renamed to src/main/java/com/github/lokic/javaplus/join/Join.java

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
package com.github.lokic.javaplus;
1+
package com.github.lokic.javaplus.join;
22

3+
import com.github.lokic.javaplus.NullData;
34
import com.github.lokic.javaplus.tuple.Tuple;
45
import com.github.lokic.javaplus.tuple.Tuple2;
56

@@ -12,6 +13,9 @@
1213

1314
public class Join {
1415

16+
public static <T> JoinStream<T> stream(Stream<T> stream) {
17+
return new JoinStream<>(stream);
18+
}
1519

1620
public static <T1, T2> JoinType<T1, T2> innerJoin(Stream<T1> left, Stream<T2> right) {
1721
return new JoinType<>(left, right, t -> t.getT1() != null && t.getT2() != null);
@@ -29,68 +33,66 @@ public static <T1, T2> JoinType<T1, T2> fullOuterJoin(Stream<T1> left, Stream<T2
2933
return new JoinType<>(left, right, t -> !(t.getT1() == null && t.getT2() == null));
3034
}
3135

32-
public static <T1, T2> JoinType<T1, T2> innerJoin(Collection<T1> left, Collection<T2> right) {
33-
return innerJoin(left.stream(), right.stream());
34-
}
35-
36-
public static <T1, T2> JoinType<T1, T2> leftOuterJoin(Collection<T1> left, Collection<T2> right) {
37-
return leftOuterJoin(left.stream(), right.stream());
38-
}
39-
40-
public static <T1, T2> JoinType<T1, T2> rightOuterJoin(Collection<T1> left, Collection<T2> right) {
41-
return rightOuterJoin(left.stream(), right.stream());
42-
}
43-
44-
public static <T1, T2> JoinType<T1, T2> fullOuterJoin(Collection<T1> left, Collection<T2> right) {
45-
return fullOuterJoin(left.stream(), right.stream());
46-
}
4736

48-
public static class JoinStream<T1, T2> {
37+
public static class JoinStream<T> {
38+
private final Stream<T> left;
4939

50-
private final Stream<Tuple2<T1, T2>> left;
51-
52-
private JoinStream(Stream<Tuple2<T1, T2>> stream) {
53-
this.left = stream;
40+
private JoinStream(Stream<T> left) {
41+
this.left = left;
5442
}
5543

56-
public Stream<Tuple2<T1, T2>> stream() {
44+
public Stream<T> stream() {
5745
return left;
5846
}
5947

60-
public <R> Stream<R> flattenStream(Function<? super Tuple2<T1, T2>, ? extends R> mapper) {
48+
public <R> Stream<R> flattenStream(Function<? super T, ? extends R> mapper) {
6149
return left.map(mapper);
6250
}
6351

64-
public <T3> JoinType<Tuple2<T1, T2>, T3> innerJoin(Stream<T3> right) {
52+
public <T3> JoinType<T, T3> innerJoin(Stream<T3> right) {
6553
return Join.innerJoin(left, right);
6654
}
6755

68-
public <T3> JoinType<Tuple2<T1, T2>, T3> leftOuterJoin(Stream<T3> right) {
56+
public <T3> JoinType<T, T3> leftOuterJoin(Stream<T3> right) {
6957
return Join.leftOuterJoin(left, right);
7058
}
7159

72-
public <T3> JoinType<Tuple2<T1, T2>, T3> rightOuterJoin(Stream<T3> right) {
60+
public <T3> JoinType<T, T3> rightOuterJoin(Stream<T3> right) {
7361
return Join.rightOuterJoin(left, right);
7462
}
7563

76-
public <T3> JoinType<Tuple2<T1, T2>, T3> fullOuterJoin(Stream<T3> right) {
64+
public <T3> JoinType<T, T3> fullOuterJoin(Stream<T3> right) {
7765
return Join.fullOuterJoin(left, right);
7866
}
7967

80-
public <T3> JoinType<Tuple2<T1, T2>, T3> innerJoin(Collection<T3> right) {
81-
return innerJoin(right.stream());
68+
public <U, K, R> JoinStream<R> innerJoin(Stream<U> right, JoinOn<T, U, K, R> on) {
69+
Stream<R> stream = innerJoin(right)
70+
.on(on.getLeftKey(), on.getRightKey())
71+
.flattenStream(on.getFlatten());
72+
return new JoinStream<>(stream);
8273
}
8374

84-
public <T3> JoinType<Tuple2<T1, T2>, T3> leftOuterJoin(Collection<T3> right) {
85-
return leftOuterJoin(right.stream());
75+
public <U, K, R> JoinStream<R> leftOuterJoin(Stream<U> right, JoinOn<T, U, K, R> on) {
76+
Stream<R> stream = leftOuterJoin(right)
77+
.on(on.getLeftKey(), on.getRightKey())
78+
.flattenStream(on.getFlatten());
79+
return new JoinStream<>(stream);
8680
}
8781

88-
public <T3> JoinType<Tuple2<T1, T2>, T3> rightOuterJoin(Collection<T3> right) {
89-
return rightOuterJoin(right.stream());
82+
83+
public <U, K, R> JoinStream<R> rightOuterJoin(Stream<U> right, JoinOn<T, U, K, R> on) {
84+
Stream<R> stream = rightOuterJoin(right)
85+
.on(on.getLeftKey(), on.getRightKey())
86+
.flattenStream(on.getFlatten());
87+
return new JoinStream<>(stream);
9088
}
9189

92-
public <T3> JoinType<Tuple2<T1, T2>, T3> fullOuterJoin(Collection<T3> right) {
93-
return fullOuterJoin(right.stream());
90+
91+
public <U, K, R> JoinStream<R> fullOuterJoin(Stream<U> right, JoinOn<T, U, K, R> on) {
92+
Stream<R> stream = fullOuterJoin(right)
93+
.on(on.getLeftKey(), on.getRightKey())
94+
.flattenStream(on.getFlatten());
95+
return new JoinStream<>(stream);
9496
}
9597
}
9698

@@ -106,7 +108,7 @@ private JoinType(Stream<T1> left, Stream<T2> right, Predicate<Tuple2<T1, T2>> jo
106108
this.joinMatcher = joinMatcher;
107109
}
108110

109-
public <K> JoinStream<T1, T2> on(Function<T1, K> leftKey, Function<T2, K> rightKey) {
111+
public <K> JoinStream<Tuple2<T1, T2>> on(Function<T1, K> leftKey, Function<T2, K> rightKey) {
110112
Stream<Tuple2<T1, T2>> stream = Stream.concat(leftWrappedStream, rightWrappedStream)
111113
.collect(Collectors.toMap(
112114
t -> matchKey(t, leftKey, rightKey),
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.github.lokic.javaplus.join;
2+
3+
import com.github.lokic.javaplus.functional.function.Function2;
4+
import com.github.lokic.javaplus.functional.function.Function3;
5+
import com.github.lokic.javaplus.functional.function.Function4;
6+
import com.github.lokic.javaplus.functional.function.Function5;
7+
import com.github.lokic.javaplus.functional.tuple.Tuple2Flattened;
8+
import com.github.lokic.javaplus.tuple.*;
9+
10+
import java.util.function.Function;
11+
12+
public class JoinOn<T, U, K, R> {
13+
14+
private final Function<T, K> leftKey;
15+
private final Function<U, K> rightKey;
16+
private final Function<? super Tuple2<T, U>, ? extends R> flatten;
17+
18+
private JoinOn(Function<T, K> leftKey, Function<U, K> rightKey, Function<? super Tuple2<T, U>, ? extends R> flatten) {
19+
this.leftKey = leftKey;
20+
this.rightKey = rightKey;
21+
this.flatten = flatten;
22+
}
23+
24+
public static <T1, TT, KK> JoinOn<T1, TT, KK, Tuple2<T1, TT>> on(Function<T1, KK> f1, Function<TT, KK> f2) {
25+
return new JoinOn<>(f1, f2, Tuple2Flattened::flatten2);
26+
}
27+
28+
public static <T1, T2, TT, KK> JoinOn<Tuple2<T1, T2>, TT, KK, Tuple3<T1, T2, TT>> on(Function2<T1, T2, KK> f1, Function<TT, KK> f2) {
29+
return new JoinOn<>(t -> f1.apply(t.getT1(), t.getT2()), f2, Tuple2Flattened::flatten3);
30+
}
31+
32+
public static <T1, T2, T3, TT, KK> JoinOn<Tuple3<T1, T2, T3>, TT, KK, Tuple4<T1, T2, T3, TT>> on(Function3<T1, T2, T3, KK> f1, Function<TT, KK> f2) {
33+
return new JoinOn<>(t -> f1.apply(t.getT1(), t.getT2(), t.getT3()), f2, Tuple2Flattened::flatten4);
34+
}
35+
36+
public static <T1, T2, T3, T4, TT, KK> JoinOn<Tuple4<T1, T2, T3, T4>, TT, KK, Tuple5<T1, T2, T3, T4, TT>> on(Function4<T1, T2, T3, T4, KK> f1, Function<TT, KK> f2) {
37+
return new JoinOn<>(t -> f1.apply(t.getT1(), t.getT2(), t.getT3(), t.getT4()), f2, Tuple2Flattened::flatten5);
38+
}
39+
40+
public static <T1, T2, T3, T4, T5, TT, KK> JoinOn<Tuple5<T1, T2, T3, T4, T5>, TT, KK, Tuple6<T1, T2, T3, T4, T5, TT>> on(Function5<T1, T2, T3, T4, T5, KK> f1, Function<TT, KK> f2) {
41+
return new JoinOn<>(t -> f1.apply(t.getT1(), t.getT2(), t.getT3(), t.getT4(), t.getT5()), f2, Tuple2Flattened::flatten6);
42+
}
43+
44+
public Function<T, K> getLeftKey() {
45+
return leftKey;
46+
}
47+
48+
public Function<U, K> getRightKey() {
49+
return rightKey;
50+
}
51+
52+
public Function<? super Tuple2<T, U>, ? extends R> getFlatten() {
53+
return flatten;
54+
}
55+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package com.github.lokic.javaplus.join;
2+
3+
import com.github.lokic.javaplus.tuple.Tuple;
4+
import com.github.lokic.javaplus.tuple.Tuple2;
5+
import com.github.lokic.javaplus.tuple.Tuple3;
6+
import org.assertj.core.api.Assertions;
7+
import org.junit.Test;
8+
9+
import java.util.List;
10+
import java.util.function.Function;
11+
import java.util.stream.Collectors;
12+
import java.util.stream.Stream;
13+
14+
import static com.github.lokic.javaplus.join.JoinOn.on;
15+
16+
public class Join2Test {
17+
18+
@Test
19+
public void test_innerJoin() {
20+
21+
List<Tuple2<Integer, String>> list = Join.stream(Stream.of(1, 2, 3, 4))
22+
.innerJoin(Stream.of("2", "3", "5"), on(i -> String.valueOf(i), Function.identity()))
23+
.stream()
24+
.collect(Collectors.toList());
25+
26+
Assertions.assertThat(list)
27+
.containsExactly(Tuple.of(2, "2"), Tuple.of(3, "3"));
28+
}
29+
30+
@Test
31+
public void test_innerJoin_repeatKey() {
32+
33+
List<Tuple2<Integer, String>> list = Join.stream(Stream.of(1, 2, 2, 3, 4))
34+
.innerJoin(Stream.of("2", "3", "5"), on(i -> String.valueOf(i), Function.identity()))
35+
.stream()
36+
.collect(Collectors.toList());
37+
38+
Assertions.assertThat(list)
39+
.containsExactly(Tuple.of(2, "2"), Tuple.of(2, "2"), Tuple.of(3, "3"));
40+
}
41+
42+
@Test
43+
public void test_leftOuterJoin() {
44+
List<Tuple2<Integer, String>> list = Join.stream(Stream.of(1, 2, 3, 4))
45+
.leftOuterJoin(Stream.of("2", "3", "5"), on(i -> String.valueOf(i), Function.identity()))
46+
.stream()
47+
.collect(Collectors.toList());
48+
49+
Assertions.assertThat(list)
50+
.containsExactly(Tuple.of(1, null), Tuple.of(2, "2"), Tuple.of(3, "3"), Tuple.of(4, null));
51+
}
52+
53+
@Test
54+
public void test_leftOuterJoin_empty() {
55+
List<Tuple2<Integer, String>> list = Join.stream(Stream.of(1, 2, 3, 4))
56+
.leftOuterJoin(Stream.empty(), on(i -> String.valueOf(i), Function.identity()))
57+
.stream()
58+
.collect(Collectors.toList());
59+
60+
Assertions.assertThat(list)
61+
.containsExactly(Tuple.of(1, null), Tuple.of(2, null), Tuple.of(3, null), Tuple.of(4, null));
62+
}
63+
64+
@Test
65+
public void test_rightOuterJoin() {
66+
List<Tuple2<Integer, String>> list = Join.stream(Stream.of(1, 2, 3, 4))
67+
.rightOuterJoin(Stream.of("2", "3", "5"), on(i -> String.valueOf(i), Function.identity()))
68+
.stream()
69+
.collect(Collectors.toList());
70+
71+
Assertions.assertThat(list)
72+
.containsExactly(Tuple.of(2, "2"), Tuple.of(3, "3"), Tuple.of(null, "5"));
73+
}
74+
75+
76+
@Test
77+
public void test_fullOuterJoin() {
78+
List<Tuple2<Integer, String>> list = Join.stream(Stream.of(1, 2, 3, 4))
79+
.fullOuterJoin(Stream.of("2", "3", "5"), on(i -> String.valueOf(i), Function.identity()))
80+
.stream()
81+
.collect(Collectors.toList());
82+
83+
Assertions.assertThat(list)
84+
.containsExactly(Tuple.of(1, null), Tuple.of(2, "2"), Tuple.of(3, "3"),
85+
Tuple.of(4, null), Tuple.of(null, "5"));
86+
}
87+
88+
@Test
89+
public void test_joinStream_leftOuterJoin() {
90+
List<Tuple3<Integer, String, String>> list = Join.stream(Stream.of(1, 2, 3, 4))
91+
.leftOuterJoin(Stream.of("2", "3", "5"), on(i -> String.valueOf(i), Function.identity()))
92+
.leftOuterJoin(Stream.of("1"), on((a, b) -> String.valueOf(a), Function.identity()))
93+
.stream()
94+
.collect(Collectors.toList());
95+
96+
Assertions.assertThat(list)
97+
.containsExactly(
98+
Tuple.of(1, null, "1"),
99+
Tuple.of(2, "2", null),
100+
Tuple.of(3, "3", null),
101+
Tuple.of(4, null, null));
102+
}
103+
104+
@Test
105+
public void test_nullKey() {
106+
List<Tuple2<Integer, Integer>> list = Join.stream(Stream.of(new KeyBox(1), new KeyBox(2), new KeyBox(3), new KeyBox(4), new KeyBox(null)))
107+
.leftOuterJoin(Stream.of(2, 3, 5), on(KeyBox::getKey, Function.identity()))
108+
.stream()
109+
.map(t -> Tuple.of(t.getT1().getKey(), t.getT2()))
110+
.collect(Collectors.toList());
111+
Assertions.assertThat(list)
112+
.containsExactly(Tuple.of(1, null), Tuple.of(2, 2), Tuple.of(3, 3),
113+
Tuple.of(4, null), Tuple.of(null, null));
114+
115+
}
116+
117+
public static class KeyBox {
118+
private final Integer key;
119+
120+
public KeyBox(Integer key) {
121+
this.key = key;
122+
}
123+
124+
public Integer getKey() {
125+
return key;
126+
}
127+
}
128+
}

src/test/java/com/github/lokic/javaplus/JoinTest.java renamed to src/test/java/com/github/lokic/javaplus/join/JoinTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.github.lokic.javaplus;
1+
package com.github.lokic.javaplus.join;
22

33
import com.github.lokic.javaplus.functional.tuple.TupleFlattened;
44
import com.github.lokic.javaplus.functional.tuple.TupleFunctional;

0 commit comments

Comments
 (0)