Java Code Examples for com.google.common.collect.Iterables#getLast()

The following examples show how to use com.google.common.collect.Iterables#getLast() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: CollectionSearchTests.java    From java_in_examples with Apache License 2.0 6 votes vote down vote up
private static void testGetLast() {
    Collection<String> collection = Lists.newArrayList("a1", "a2", "a3", "a8");
    OrderedIterable<String> orderedIterable = FastList.newListWith("a1", "a2", "a3", "a8");
    Iterable<String> iterable = collection;

    // вернуть последней элемент коллекции
    Iterator<String> iterator = collection.iterator(); // c помощью JDK
    String jdk = "1";
    while(iterator.hasNext()) {
        jdk = iterator.next();
    }
    String guava = Iterables.getLast(iterable, "1"); // с помощью guava
    String apache = CollectionUtils.get(collection, collection.size()-1);  // c помощью Apache
    String gs = orderedIterable.getLast(); // c помощью GS
    String stream = collection.stream().skip(collection.size()-1).findFirst().orElse("1"); // c помощью Stream API
    System.out.println("last = " + jdk + ":" + guava + ":" + apache + ":" + gs + ":" + stream); // напечатает last = a8:a8:a8:a8:a8
}
 
Example 2
Source File: NormalizeJsVarargs.java    From j2cl with Apache License 2.0 5 votes vote down vote up
@Override
public Node rewriteInvocation(Invocation invocation) {
  MethodDescriptor target = invocation.getTarget();
  if (!target.isJsMethodVarargs()) {
    return invocation;
  }
  Expression lastArgument = Iterables.getLast(invocation.getArguments());

  // If the last argument is an array literal, or an array creation with array literal,
  // unwrap array literal, and pass the unwrapped arguments directly.
  if (lastArgument instanceof ArrayLiteral) {
    return MethodCall.Builder.from(invocation)
        .replaceVarargsArgument(((ArrayLiteral) lastArgument).getValueExpressions())
        .build();
  }

  if (lastArgument instanceof NewArray) {
    ArrayLiteral arrayLiteral = ((NewArray) lastArgument).getArrayLiteral();
    if (arrayLiteral != null) {
      return MethodCall.Builder.from(invocation)
          .replaceVarargsArgument(arrayLiteral.getValueExpressions())
          .build();
    }
  }

  // Here we wrap the vararg type with InternalPreconditions.checkNotNull before applying the
  // spread operator because the spread of a null causes a runtime exception in Javascript.
  // The reason for this is that there is a mismatch between Java varargs and Javascript varargs
  // semantics.  In Java, if you pass a null for the varargs it passes a null array rather than
  // an array with a single null object.  In Javascript however we pass the values of the
  // varargs as arguments not as an array so there is no way to express this.
  // checkNotNull errors out early if null is passed as a jsvararg parameter.
  return MethodCall.Builder.from(invocation)
      .replaceVarargsArgument(
          RuntimeMethods.createCheckNotNullCall(lastArgument).prefixSpread())
      .build();
}
 
Example 3
Source File: WorkflowTest.java    From copybara with Apache License 2.0 5 votes vote down vote up
@Test
public void testSquashCustomLabel() throws Exception {
  origin.addSimpleChange(/*timestamp*/ 0);
  origin.addSimpleChange(/*timestamp*/ 1);
  options.workflowOptions.lastRevision = resolveHead();
  origin.addSimpleChange(/*timestamp*/ 2);
  origin.addSimpleChange(/*timestamp*/ 3);

  extraWorkflowFields = ImmutableList.of("experimental_custom_rev_id = \"CUSTOM_REV_ID\"");

  Workflow<?, ?> workflow = skylarkWorkflow("default", SQUASH);

  workflow.run(workdir, ImmutableList.of(HEAD));
  assertThat(destination.processed).hasSize(1);
  ProcessedChange change = Iterables.getOnlyElement(destination.processed);
  assertThat(change.getRevIdLabel()).isEqualTo("CUSTOM_REV_ID");
  assertThat(change.getOriginRef().asString()).isEqualTo("3");

  options.workflowOptions.lastRevision = null;

  workflow = skylarkWorkflow("default", SQUASH);

  assertThat(
      Iterables.getOnlyElement(
          workflow.getInfo().migrationReferences()).getLastMigrated().asString()).isEqualTo("3");

  origin.addSimpleChange(/*timestamp*/ 4);
  origin.addSimpleChange(/*timestamp*/ 5);

  workflow.run(workdir, ImmutableList.of(HEAD));
  ProcessedChange last = Iterables.getLast(destination.processed);
  assertThat(last.getOriginChanges()).hasSize(2);
  assertThat(last.getOriginChanges().get(0).getRevision().asString()).isEqualTo("5");
  assertThat(last.getOriginChanges().get(1).getRevision().asString()).isEqualTo("4");
}
 
Example 4
Source File: DexProducedFromJavaLibraryThatContainsClassFilesTest.java    From buck with Apache License 2.0 5 votes vote down vote up
@Test
public void testGetBuildStepsWhenThereAreNoClassesToDex() throws Exception {
  ActionGraphBuilder graphBuilder = new TestActionGraphBuilder();
  DefaultJavaLibrary javaLibrary =
      JavaLibraryBuilder.createBuilder("//foo:bar").build(graphBuilder);
  javaLibrary
      .getBuildOutputInitializer()
      .setBuildOutputForTests(new JavaLibrary.Data(ImmutableSortedMap.of()));
  javaLibrary.setJavaClassHashesProvider(new FakeJavaClassHashesProvider());

  BuildContext context = FakeBuildContext.NOOP_CONTEXT;
  FakeBuildableContext buildableContext = new FakeBuildableContext();
  ProjectFilesystem projectFilesystem = new FakeProjectFilesystem();

  BuildTarget buildTarget = BuildTargetFactory.newInstance("//foo:bar#dex");
  DexProducedFromJavaLibrary preDex =
      new DexProducedFromJavaLibrary(
          buildTarget,
          projectFilesystem,
          graphBuilder,
          TestAndroidPlatformTargetFactory.create(),
          javaLibrary);
  List<Step> steps = preDex.getBuildSteps(context, buildableContext);

  ExecutionContext executionContext = TestExecutionContext.newBuilder().build();

  Step recordArtifactAndMetadataStep = Iterables.getLast(steps);
  assertThat(recordArtifactAndMetadataStep.getShortName(), startsWith("record_"));
  int exitCode = recordArtifactAndMetadataStep.execute(executionContext).getExitCode();
  assertEquals(0, exitCode);
}
 
Example 5
Source File: AmazonKinesisSinkTask.java    From kinesis-kafka-connector with Apache License 2.0 5 votes vote down vote up
@Override
public void onFailure(Throwable t) {
	if (t instanceof UserRecordFailedException) {
		Attempt last = Iterables.getLast(((UserRecordFailedException) t).getResult().getAttempts());
		throw new DataException("Kinesis Producer was not able to publish data - " + last.getErrorCode() + "-"
				+ last.getErrorMessage());

	}
	throw new DataException("Exception during Kinesis put", t);
}
 
Example 6
Source File: CommentManager.java    From binnavi with Apache License 2.0 5 votes vote down vote up
/**
 * This function provides the append comment functionality for any given Implementation of a
 * {@link CommentingStrategy}. It uses the methods of the interface to only have one algorithm
 * with different objects that can be commented.
 *
 * @param strategy The {@link CommentingStrategy} which holds the function forwarders.
 * @param commentText The commenting text to append.
 *
 * @return The generated comment.
 *
 * @throws CouldntSaveDataException if the comment could not be stored in the database.
 * @throws CouldntLoadDataException if the list of comments now associated with the commented
 *         object could not be loaded from the database.
 */
private synchronized List<IComment> appendComment(
    final CommentingStrategy strategy, final String commentText)
    throws CouldntSaveDataException, CouldntLoadDataException {

  final IUser user = CUserManager.get(provider).getCurrentActiveUser();

  final List<IComment> currentComments = new ArrayList<IComment>();

  if (strategy.isStored()) {
    currentComments.addAll(strategy.appendComment(commentText, user.getUserId()));
  } else {
    currentComments.addAll(strategy.getComments() == null ? new ArrayList<IComment>()
        : Lists.newArrayList(strategy.getComments()));
    final IComment parent = currentComments.isEmpty() ? null : Iterables.getLast(currentComments);
    final IComment newComment = new CComment(null, user, parent, commentText);
    currentComments.add(newComment);
  }

  strategy.saveComments(currentComments);
  for (final IComment comment : currentComments) {
    commentIdToComment.put(comment.getId(), comment);
  }

  for (final CommentListener listener : listeners) {
    try {
      strategy.sendAppendedCommentNotifcation(listener, Iterables.getLast(currentComments));
    } catch (final Exception exception) {
      CUtilityFunctions.logException(exception);
    }
  }
  return currentComments;
}
 
Example 7
Source File: Key.java    From async-datastore-client with Apache License 2.0 5 votes vote down vote up
/**
 * Return element key id, or null if not set.
 *
 * This is a shortcut for {@code Key.getPath().get(Key.getPath().size() - 1).getId()}
 *
 * @return the key id.
 */
public Long getId() {
  final com.google.datastore.v1.Key.PathElement element = Iterables.getLast(key.getPathList(), null);
  if (element == null) {
    return null;
  }
  return isId(element) ? element.getId() : null;
}
 
Example 8
Source File: ResponseExceptionHandler.java    From hawkbit with Eclipse Public License 1.0 5 votes vote down vote up
/**
 * Method for handling exception of type {@link MultipartException} which is
 * thrown in case the request body is not well formed and cannot be
 * deserialized. Called by the Spring-Framework for exception handling.
 *
 * @param request
 *            the Http request
 * @param ex
 *            the exception which occurred
 * @return the entity to be responded containing the exception information
 *         as entity.
 */
@ExceptionHandler(MultipartException.class)
public ResponseEntity<ExceptionInfo> handleMultipartException(final HttpServletRequest request,
        final Exception ex) {

    logRequest(request, ex);

    final List<Throwable> throwables = ExceptionUtils.getThrowableList(ex);
    final Throwable responseCause = Iterables.getLast(throwables);

    if (responseCause.getMessage().isEmpty()) {
        LOG.warn("Request {} lead to MultipartException without root cause message:\n{}", request.getRequestURL(),
                ex.getStackTrace());
    }

    final ExceptionInfo response = createExceptionInfo(new MultiPartFileUploadException(responseCause));
    return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
 
Example 9
Source File: MatrixParameterResolver.java    From everrest with Eclipse Public License 2.0 5 votes vote down vote up
@Override
public Object resolve(org.everrest.core.Parameter parameter, ApplicationContext context) throws Exception {
    String param = matrixParam.value();
    TypeProducer typeProducer = typeProducerFactory.createTypeProducer(parameter.getParameterClass(), parameter.getGenericType());
    List<PathSegment> pathSegments = context.getUriInfo().getPathSegments(!parameter.isEncoded());

    PathSegment pathSegment = Iterables.getLast(pathSegments, null);

    return typeProducer.createValue(param,
                                    pathSegment == null ? new MultivaluedHashMap<>() : pathSegment.getMatrixParameters(),
                                    parameter.getDefaultValue());
}
 
Example 10
Source File: Key.java    From async-datastore-client with Apache License 2.0 5 votes vote down vote up
/**
 * Return element key name, or null if not set.
 *
 * This is a shortcut for {@code Key.getPath().get(Key.getPath().size() - 1).getName()}
 *
 * @return the key name.
 */
public String getName() {
  final com.google.datastore.v1.Key.PathElement element = Iterables.getLast(key.getPathList(), null);
  if (element == null) {
    return null;
  }
  return isName(element) ? element.getName() : null;
}
 
Example 11
Source File: OrcTester.java    From presto with Apache License 2.0 5 votes vote down vote up
private void testMapRoundTrip(Type type, List<?> readValues)
        throws Exception
{
    Type mapType = mapType(type, type);

    // maps cannot have a null key, so select a value to use for the map key when the value is null
    Object readNullKeyValue = Iterables.getLast(readValues);

    // values in simple map
    testRoundTripType(
            mapType,
            readValues.stream()
                    .map(value -> toHiveMap(value, readNullKeyValue))
                    .collect(toList()));

    if (structuralNullTestsEnabled) {
        // values and nulls in simple map
        testRoundTripType(
                mapType,
                insertNullEvery(5, readValues).stream()
                        .map(value -> toHiveMap(value, readNullKeyValue))
                        .collect(toList()));

        // all null values in simple map
        testRoundTripType(
                mapType,
                readValues.stream()
                        .map(value -> toHiveMap(null, readNullKeyValue))
                        .collect(toList()));
    }
}
 
Example 12
Source File: LogbackListAppender.java    From vjtools with Apache License 2.0 5 votes vote down vote up
/**
 * 返回之前append的最后一个log.
 */
public ILoggingEvent getLastLog() {
	if (logs.isEmpty()) {
		return null;
	}
	return Iterables.getLast(logs);
}
 
Example 13
Source File: RefineEffectiveStatementImpl.java    From yangtools with Eclipse Public License 1.0 4 votes vote down vote up
RefineEffectiveStatementImpl(final StmtContext<Descendant, RefineStatement, ?> ctx) {
    super(ctx);
    qname = Iterables.getLast(ctx.coerceStatementArgument().getNodeIdentifiers());
    path = ctx.getSchemaPath().get();
    refineTargetNode = (SchemaNode) ctx.getEffectOfStatement().iterator().next().buildEffective();
}
 
Example 14
Source File: PostgreSQLLocalInstructionCommentTests.java    From binnavi with Apache License 2.0 4 votes vote down vote up
@Before
public void loadCodeNode() throws CouldntLoadDataException, CPartialLoadException,
    LoadCancelledException, MaybeNullException {
  codeNode = (CCodeNode) loadCodeNode(getNotepadModule(), "sub_1002B87");
  instruction = Iterables.getLast(codeNode.getInstructions());
}
 
Example 15
Source File: MethodMatcher.java    From api-compiler with Apache License 2.0 4 votes vote down vote up
public MethodMatcher(MethodPattern pattern, Method method, HttpAttribute httpConfig) {
  this.pattern = pattern;
  this.method = method;
  this.httpConfig = httpConfig;

  matches = false;

  // Check http method.
  if (httpConfig.getMethodKind() != pattern.httpMethod()) {
    return;
  }

  // Check name regexp.
  nameMatcher = pattern.nameRegexp().matcher(method.getSimpleName());
  if (!nameMatcher.matches()) {
    return;
  }

  // Determine match on last segment.
  List<PathSegment> flatPath = httpConfig.getFlatPath();
  PathSegment lastSegment = Iterables.getLast(flatPath);
  switch (pattern.lastSegmentPattern()) {
    case CUSTOM_VERB_WITH_COLON:
      // Allow only standard conforming custom method which uses <prefix>:<literal>.
      matches =
          lastSegment instanceof LiteralSegment
              && ((LiteralSegment) lastSegment).isTrailingCustomVerb();
      break;
    case CUSTOM_VERB:
      // Allow both a custom verb literal and a regular literal, the latter is for supporting
      // legacy custom verbs.
      matches = lastSegment instanceof LiteralSegment;
      break;
    case VARIABLE:
      matches = lastSegment instanceof WildcardSegment;
      break;
    case LITERAL:
      matches =
          lastSegment instanceof LiteralSegment
              && !((LiteralSegment) lastSegment).isTrailingCustomVerb();
      break;
  }
}
 
Example 16
Source File: PostgreSQLNotificationProviderTest.java    From binnavi with Apache License 2.0 4 votes vote down vote up
@Test
public void testDeleteTextNodeCommentSync()
    throws CouldntSaveDataException,
    CouldntLoadDataException,
    LoadCancelledException,
    CPartialLoadException,
    InterruptedException,
    CouldntDeleteException {

  final CView databaseOneTextNodeView = databaseOneModuleTwo.getContent()
      .getViewContainer().createView(" TEXT NODE TESTING VIEW ", "");
  CViewInserter.insertView(databaseOneView, databaseOneTextNodeView);
  final INaviTextNode databaseOneTextNode =
      databaseOneTextNodeView.getContent().createTextNode(new ArrayList<IComment>());
  databaseOneTextNodeView.save();

  databaseTwoModuleTwo.close();
  databaseTwoModuleTwo.load();
  databaseTwoView.load();

  final INaviView databaseTwoTextNodeView =
      Iterables.getLast(databaseTwoModuleTwo.getContent().getViewContainer().getUserViews());

  INaviTextNode databaseTwoTextNode = null;
  assertEquals(databaseOneTextNodeView.getName(), databaseTwoTextNodeView.getName());
  databaseTwoTextNodeView.load();

  for (final INaviViewNode node : databaseTwoTextNodeView.getContent().getGraph().getNodes()) {
    if (node instanceof INaviTextNode) {
      databaseTwoTextNode = (INaviTextNode) node;
    }
  }
  assertNotNull(databaseTwoTextNode);
  assertEquals(databaseTwoTextNode.getId(), databaseOneTextNode.getId());

  final List<IComment> comments =
      databaseOneTextNode.appendComment(" TEST NOTIFICATION PROVIDER TESTS (TEXT NODE COMMENT) ");

  synchronized (lock) {
    lock.await(1000, TimeUnit.MILLISECONDS);
  }

  final List<IComment> oneAfter = databaseOneTextNode.getComments();
  final List<IComment> twoAfter = databaseTwoTextNode.getComments();

  assertNotNull(oneAfter);
  assertNotNull(twoAfter);
  assertEquals(1, oneAfter.size());
  assertEquals(1, twoAfter.size());
  assertEquals(oneAfter, twoAfter);

  final int oneTwoSize = oneAfter.size();
  final int twoTwoSize = twoAfter.size();

  databaseOneTextNode.deleteComment(Iterables.getLast(comments));

  // The wait is necessary to have the poll function complete and propagate the changes from
  // database one to two over the PostgreSQL back end.
  synchronized (lock) {
    lock.await(1000, TimeUnit.MILLISECONDS);
  }

  final List<IComment> oneThree = databaseOneTextNode.getComments();
  final List<IComment> twoThree = databaseTwoTextNode.getComments();

  assertEquals(oneTwoSize - 1, oneThree.size());
  assertEquals(twoTwoSize - 1, twoThree.size());
  assertEquals(oneThree, twoThree);
}
 
Example 17
Source File: BenchmarkResult.java    From trainbenchmark with Eclipse Public License 1.0 4 votes vote down vote up
public RunResult getLastRunResult() {
	return Iterables.getLast(runResults);
}
 
Example 18
Source File: PostgreSQLTextNodeCommentTests.java    From binnavi with Apache License 2.0 4 votes vote down vote up
/**
 * This test checks if the delete of a comment in a series of comments works if the comment is a
 * comment in the middle.
 *
 * <pre>
 * Comment 1:      Comment 1:
 * Comment 2:  ->
 * Comment 3:      Comment 3:
 * </pre>
 *
 */
@Test
public void deleteTextNodeComment7()
    throws CouldntDeleteException,
    CouldntLoadDataException,
    LoadCancelledException,
    MaybeNullException,
    CPartialLoadException,
    CouldntSaveDataException {

  final INaviTextNode textNode = setupTextNode();

  final List<IComment> storedComments =
      textNode.getComments() == null ? new ArrayList<IComment>() : textNode.getComments();
  final IComment lastComment =
      storedComments.size() == 0 ? null : Iterables.getLast(storedComments);
  final IUser user = new UniqueTestUserGenerator(getProvider()).nextActiveUser();

  final String comment1String = " Comment 1: ";
  final int comment1Id =
      getProvider().appendTextNodeComment(textNode, comment1String, user.getUserId());
  final IComment comment1 = new CComment(comment1Id, user, lastComment, comment1String);

  final String comment2String = " Comment 2: ";
  final int comment2Id =
      getProvider().appendTextNodeComment(textNode, comment2String, user.getUserId());
  final IComment comment2 = new CComment(comment2Id, user, comment1, comment2String);

  final String comment3String = " Comment 3: ";
  final int comment3Id =
      getProvider().appendTextNodeComment(textNode, comment3String, user.getUserId());
  final IComment comment3 = new CComment(comment3Id, user, comment2, comment3String);

  final ArrayList<IComment> commentsBeforeDelete = getProvider().loadCommentById(comment3Id);

  assertNotNull(commentsBeforeDelete);
  assertEquals(storedComments.size() + 3, commentsBeforeDelete.size());
  assertTrue(commentsBeforeDelete.contains(comment1));
  assertTrue(commentsBeforeDelete.contains(comment2));
  assertTrue(commentsBeforeDelete.contains(comment3));
  assertEquals(comment3, Iterables.getLast(commentsBeforeDelete));
  assertEquals(comment2, commentsBeforeDelete.get(commentsBeforeDelete.size() - 2));
  assertEquals(comment1, commentsBeforeDelete.get(commentsBeforeDelete.size() - 3));

  getProvider().deleteTextNodeComment(textNode, comment2Id, user.getUserId());

  final ArrayList<IComment> commentsAfterDelete1 = getProvider().loadCommentById(comment2Id);

  assertNotNull(commentsAfterDelete1);
  assertTrue(commentsAfterDelete1.isEmpty());

  final ArrayList<IComment> commentsAfterDelete2 = getProvider().loadCommentById(comment3Id);

  assertNotNull(commentsAfterDelete2);
  assertEquals(storedComments.size() + 2, commentsAfterDelete2.size());

  final IComment comment3AfterDelete = new CComment(comment3Id, user, comment1, comment3String);

  assertTrue(commentsAfterDelete2.contains(comment3AfterDelete));
  assertTrue(commentsAfterDelete2.contains(comment1));
  assertEquals(comment3AfterDelete, Iterables.getLast(commentsAfterDelete2));
  assertEquals(comment1, commentsAfterDelete2.get(commentsAfterDelete2.size() - 2));
}
 
Example 19
Source File: UpdateNodeResolutions.java    From curiostack with MIT License 4 votes vote down vote up
@TaskAction
public void exec() throws IOException {
  var config = getProject().getExtensions().getByType(NodeSetupExtension.class);

  JsonNode root = OBJECT_MAPPER.readTree(packageJson());
  if (!root.has("resolutions")) {
    logPackageJsonError();
    return;
  }

  Map<String, String> oldResolutions =
      OBJECT_MAPPER.convertValue(root.get("resolutions"), NODE_DEPENDENCIES);
  String baseWebVersion = oldResolutions.get("@curiostack/base-web");

  if (baseWebVersion == null) {
    logPackageJsonError();
    return;
  }

  Map<String, String> managedDependencies = new HashMap<>();
  List<String> excludes = config.getExcludes().get();

  for (var pkg : CURIOSTACK_PACKAGES) {
    String packageFolder = Iterables.getLast(PACKAGE_SPLITTER.splitToList(pkg));
    File localPackageJson = getProject().file("common/web/" + packageFolder + "/package.json");
    if (!localPackageJson.exists()) {
      localPackageJson = getProject().file("node_modules/" + pkg + "/package.json");
    }
    if (!localPackageJson.exists()) {
      throw new GradleException(
          "Could not find "
              + pkg
              + "'s package.json to check resolutions. Did yarn run correctly?");
    }

    Map<String, String> dependencies =
        OBJECT_MAPPER.convertValue(
            OBJECT_MAPPER.readTree(localPackageJson).get("dependencies"), NODE_DEPENDENCIES);
    dependencies.forEach(
        (name, version) -> {
          if (!excludes.contains(name)) {
            managedDependencies.put(name, version);
          }
        });
  }

  if (checkOnly) {
    managedDependencies.forEach(
        (name, version) -> {
          if (!version.equals(oldResolutions.get(name))) {
            throw new GradleException(
                "Resolution ["
                    + name
                    + "@"
                    + version
                    + "] out of date versus base-web version. "
                    + "Run updateNodeResolutions to update them.");
          }
        });
    return;
  }

  Map<String, String> newResolutions = new TreeMap<>();
  newResolutions.putAll(oldResolutions);
  newResolutions.putAll(managedDependencies);

  // Recreate new root instead of replacing field to preserve order.
  ObjectNode newRoot = OBJECT_MAPPER.getNodeFactory().objectNode();

  for (Entry<String, JsonNode> field : ImmutableList.copyOf(root.fields())) {
    if (!field.getKey().equals("resolutions")) {
      newRoot.set(field.getKey(), field.getValue());
    } else {
      newRoot.putPOJO("resolutions", newResolutions);
    }
  }

  OBJECT_MAPPER.writeValue(packageJson(), newRoot);
}
 
Example 20
Source File: Match.java    From ProjectAres with GNU Affero General Public License v3.0 2 votes vote down vote up
/**
 * Return the most recent {@link Competitor} that the given player
 * has been a member of, since the match was committed. Returns null
 * if the player has never competed in this match, or the match has
 * not been committed yet.
 *
 * @see #commit
 */
default @Nullable Competitor getLastCompetitor(PlayerId playerId) {
    return Iterables.getLast(getPastCompetitors(playerId), null);
}