Join extends ShuffleOperator<Object, KeyT, KV<KeyT, OutputT>> { public static <LeftT, RightT> ByBuilder<LeftT, RightT> of( PCollection<LeftT> left, PCollection<RightT> right) { return named(null).of(left, right); } private  Join(
      @Nullable String name,
      Type type,
      UnaryFunction<LeftT, KeyT> leftKeyExtractor,
      UnaryFunction<RightT, KeyT> rightKeyExtractor,
      @Nullable TypeDescriptor<KeyT> keyType,
      BinaryFunctor<LeftT, RightT, OutputT> functor,
      @Nullable TypeDescriptor<KV<KeyT, OutputT>> outputType,
      @Nullable Window<Object> window); static ByBuilder<LeftT, RightT> of(
      PCollection<LeftT> left, PCollection<RightT> right); static OfBuilder named(@Nullable String name); Type getType(); UnaryFunction<LeftT, KeyT> getLeftKeyExtractor(); UnaryFunction<RightT, KeyT> getRightKeyExtractor(); BinaryFunctor<LeftT, RightT, OutputT> getJoiner();  }
@Test public void testBuild_ImplicitName() { final Pipeline pipeline = TestUtils.createTestPipeline(); final PCollection<String> left = TestUtils.createMockDataset(pipeline, TypeDescriptors.strings()); final PCollection<String> right = TestUtils.createMockDataset(pipeline, TypeDescriptors.strings()); final PCollection<KV<Integer, String>> joined = Join.of(left, right) .by(String::length, String::length) .using( (String l, String r, Collector<String> c) -> { }) .output(); final Join join = (Join) TestUtils.getProducer(joined); assertFalse(join.getName().isPresent()); }