私は、次のコードを持っています
public class TeeingCollector {
public static void main(String[] args) {
// var strs = List.of("abc");
var dividedStrings = Stream.of("foo", "hello", "bar", "world")
.collect(Collectors.teeing(
Collectors.filtering((String s) -> s.length() <= 3, Collectors.toList()),
Collectors.filtering((String s) -> s.length() > 3, Collectors.toList()),
List::of
));
System.out.println(dividedStrings);
}
private static class Employee {
boolean isActive;
public Employee(boolean isActive) {
this.isActive = isActive;
}
public boolean isActive() {
return isActive;
}
@Override
public String toString() {
return "Employee{" +
"isActive=" + isActive +
'}';
}
}
private static class MaxMin {
int max;
int min;
MaxMin(int max, int min) {
this.max = max;
this.min = min;
}
@Override
public String toString() {
return "MaxMin{" +
"max=" + max +
", min=" + min +
'}';
}
}
}
私は端末からそのクラスを実行した場合とjava src/TeeingCollector.java
、私は次のエラーを取得します:
src/TeeingCollector.java:14: error: incompatible types: inferred type does not conform to equality constraint(s)
.collect(Collectors.teeing(
^
inferred: List<String>
equality constraints(s): List<Object>,R
where R,T,A are type-variables:
R extends Object declared in method <T,A,R>filtering(Predicate<? super T>,Collector<? super T,A,R>)
T extends Object declared in method <T,A,R>filtering(Predicate<? super T>,Collector<? super T,A,R>)
A extends Object declared in method <T,A,R>filtering(Predicate<? super T>,Collector<? super T,A,R>)
1 error
error: compilation failed
私は、行のコメントを解除した場合var strs = List.of("abc");
、コードは問題なく実行されます。
(MacOSのための)Javaバージョン:
OpenJDK Runtime Environment (build 12+33)
OpenJDK 64-Bit Server VM (build 12+33, mixed mode, sharing)
次のバージョン(古い)と同じコードを実行してもエラーが生じていません
OpenJDK Runtime Environment (build 12-ea+23)
OpenJDK 64-Bit Server VM (build 12-ea+23, mixed mode, sharing)
注:私はそれがその後、実行コンパイルした場合、唯一のようですので、私は、MacOSのためのビルドの両方ですべてのエラーを持っていないjava TeeingCollector.java
正常に動作しません
TL;コンパイラの動作は、Java言語外の環境面を含めて完全に無関係なもの、に依存するDRは、これは、明らかにバグです。
私はあなたの例を簡略化の実装を統合Collectors.teeing
し、Predicate.not
JDK 12 JDK 9からJavaバージョンを使用してコードをテストすることができるように、実施例に。
これは、との相互作用のいくつかの種類だったことを私が最初に考えながら、という注意var
含めることが許さ右手側の一般的な構築物での型推論、より多くのテストは、変数の明示的な型を使用するときにも問題が存在することを明らかにし、テストでJDK 9。
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
import java.util.stream.Collector;
public class Temp5 {
public static void main(String[] args) {
// List<Character> strs = List.of("abc");
List<List<Character>> lettersAndNumbers = Stream.of('5', 't', 'o', '9', 'p', '1', 'h')
.collect(teeing(
Collectors.filtering(Character::isLetter, Collectors.toList()),
Collectors.filtering(not(Character::isLetter), Collectors.toList()),
List::of
));
}
public static <T, R1, R2, R>
Collector<T, ?, R> teeing(Collector<? super T, ?, R1> downstream1,
Collector<? super T, ?, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger) {
return teeing0(downstream1, downstream2, merger);
}
private static <T, A1, A2, R1, R2, R>
Collector<T, ?, R> teeing0(Collector<? super T, A1, R1> downstream1,
Collector<? super T, A2, R2> downstream2,
BiFunction<? super R1, ? super R2, R> merger) {
Objects.requireNonNull(downstream1, "downstream1");
Objects.requireNonNull(downstream2, "downstream2");
Objects.requireNonNull(merger, "merger");
Supplier<A1> c1Supplier = Objects.requireNonNull(downstream1.supplier(), "downstream1 supplier");
Supplier<A2> c2Supplier = Objects.requireNonNull(downstream2.supplier(), "downstream2 supplier");
BiConsumer<A1, ? super T> c1Accumulator =
Objects.requireNonNull(downstream1.accumulator(), "downstream1 accumulator");
BiConsumer<A2, ? super T> c2Accumulator =
Objects.requireNonNull(downstream2.accumulator(), "downstream2 accumulator");
BinaryOperator<A1> c1Combiner = Objects.requireNonNull(downstream1.combiner(), "downstream1 combiner");
BinaryOperator<A2> c2Combiner = Objects.requireNonNull(downstream2.combiner(), "downstream2 combiner");
Function<A1, R1> c1Finisher = Objects.requireNonNull(downstream1.finisher(), "downstream1 finisher");
Function<A2, R2> c2Finisher = Objects.requireNonNull(downstream2.finisher(), "downstream2 finisher");
Collector.Characteristics[] characteristics;
Set<Collector.Characteristics> c1Characteristics = downstream1.characteristics();
Set<Collector.Characteristics> c2Characteristics = downstream2.characteristics();
EnumSet<Collector.Characteristics> c = EnumSet.noneOf(Collector.Characteristics.class);
c.addAll(c1Characteristics);
c.retainAll(c2Characteristics);
c.remove(Collector.Characteristics.IDENTITY_FINISH);
characteristics = c.toArray(new Collector.Characteristics[0]);
class PairBox {
A1 left = c1Supplier.get();
A2 right = c2Supplier.get();
void add(T t) {
c1Accumulator.accept(left, t);
c2Accumulator.accept(right, t);
}
PairBox combine(PairBox other) {
left = c1Combiner.apply(left, other.left);
right = c2Combiner.apply(right, other.right);
return this;
}
R get() {
R1 r1 = c1Finisher.apply(left);
R2 r2 = c2Finisher.apply(right);
return merger.apply(r1, r2);
}
}
return Collector.of(PairBox::new, PairBox::add, PairBox::combine, PairBox::get, characteristics);
}
@SuppressWarnings("unchecked")
static <T> Predicate<T> not(Predicate<? super T> target) {
Objects.requireNonNull(target);
return (Predicate<T>)target.negate();
}
}
その結果は悲惨です。すべてのバージョンはちょうどマイナーバージョンを変更した場合でも、コードの正確性について異なる意見を持つことができます。まあ、でもOpenJDKのを使用しての代わりに、Oracleの分布が異なる結果を持つことができます。また、コードにしても、最小の変更は、それに影響を与えることができます。あなたが述べてきたように、実際の宣言にコメントを変更すると、結果を変更することができ、それでもコメントを削除すると、一部のJDKバージョンの結果を変更します。ただ、変化する値を使用してのように、Stream.of('5', 't', 'o', '9', 'p', '1')
代わりのStream.of('5', 't', 'o', '9', 'p', '1', 'h')
変更いくつかのバージョンの成果。
私の結論は、コンパイラの実装に何かの繰り返し順序のように、特定のセットアップのために何かの安定に依存しますが、実際には予測できないということですHashMap
。そして、JDKのバージョン自体がその一部であるように思われます。これはまた、代わりのLinuxまたはWindowsのMacOSのを使用した場合、結果が変わることがあり理由を説明するだろう。でも、他のと一緒に、このソースファイルをコンパイルし、無関係なソースファイルは、結果を変更することができます。