1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.core.util;
28
29 import java.util.HashMap;
30 import java.util.LinkedHashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Objects;
34 import java.util.function.BinaryOperator;
35 import java.util.function.Function;
36 import java.util.function.Supplier;
37 import java.util.stream.Collector;
38 import java.util.stream.Collectors;
39 import java.util.stream.Stream;
40
41 import edu.umd.cs.findbugs.annotations.NonNull;
42
43 public final class CustomCollectors {
44 private CustomCollectors() {
45
46 }
47
48 @SuppressWarnings("null")
49 @NonNull
50 public static <T> Function<T, T> identity() {
51 return Function.identity();
52 }
53
54 public static Collector<CharSequence, ?, String> joiningWithOxfordComma(@NonNull String conjunction) {
55 return Collectors.collectingAndThen(Collectors.toList(), withOxfordComma(conjunction));
56 }
57
58 private static Function<List<CharSequence>, String> withOxfordComma(@NonNull String conjunction) {
59 return list -> {
60 int size = list.size();
61 if (size < 2) {
62 return String.join("", list);
63 }
64 if (size == 2) {
65 return String.join(" " + conjunction + " ", list);
66 }
67
68 int last = size - 1;
69 return String.join(", " + conjunction + " ",
70 String.join(", ", list.subList(0, last)),
71 list.get(last));
72 };
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public static <V, K> Stream<V> distinctByKey(
91 @NonNull Stream<V> stream,
92 @NonNull Function<? super V, ? extends K> keyMapper) {
93 return distinctByKey(stream, keyMapper, (key, value1, value2) -> value2);
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public static <V, K> Stream<V> distinctByKey(
115 @NonNull Stream<V> stream,
116 @NonNull Function<? super V, ? extends K> keyMapper,
117 @NonNull DuplicateHandler<K, V> duplicateHander) {
118 Map<K, V> uniqueRoles = stream
119 .collect(toMap(
120 keyMapper,
121 identity(),
122 duplicateHander,
123 LinkedHashMap::new));
124 return uniqueRoles.values().stream();
125 }
126
127 @NonNull
128 public static <T, K, V> Collector<T, ?, Map<K, V>> toMap(
129 @NonNull Function<? super T, ? extends K> keyMapper,
130 @NonNull Function<? super T, ? extends V> valueMapper,
131 @NonNull DuplicateHandler<K, V> duplicateHander) {
132 return toMap(keyMapper, valueMapper, duplicateHander, HashMap::new);
133 }
134
135 @NonNull
136 public static <T, K, V, M extends Map<K, V>> Collector<T, ?, M> toMap(
137 @NonNull Function<? super T, ? extends K> keyMapper,
138 @NonNull Function<? super T, ? extends V> valueMapper,
139 @NonNull DuplicateHandler<K, V> duplicateHander,
140 Supplier<M> supplier) {
141 return ObjectUtils.notNull(
142 Collector.of(
143 supplier,
144 (map, item) -> {
145 K key = keyMapper.apply(item);
146 V value = Objects.requireNonNull(valueMapper.apply(item));
147 V oldValue = map.get(key);
148 if (oldValue != null) {
149 value = duplicateHander.handle(key, oldValue, value);
150 }
151 map.put(key, value);
152 },
153 (map1, map2) -> {
154 map2.forEach((key, value) -> {
155 V oldValue = map1.get(key);
156 V newValue = value;
157 if (oldValue != null) {
158 newValue = duplicateHander.handle(key, oldValue, value);
159 }
160 map1.put(key, newValue);
161 });
162 return map1;
163 }));
164 }
165
166 @FunctionalInterface
167 public interface DuplicateHandler<K, V> {
168 @NonNull
169 V handle(K key, @NonNull V value1, V value2);
170 }
171
172 @NonNull
173 public static <T> BinaryOperator<T> useFirstMapper() {
174 return (value1, value2) -> value1;
175 }
176
177 @NonNull
178 public static <T> BinaryOperator<T> useLastMapper() {
179 return (value1, value2) -> value2;
180 }
181 }