Java tutorial
/** * Copyright 2012 Julien Eluard * This project includes software developed by Julien Eluard: https://github.com/jeluard/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.jeluard.guayaba.base; import com.google.common.base.*; import com.google.common.collect.Iterables; import com.google.common.reflect.TypeToken; /** * Helper methods for {@link PartialFunction}. */ public final class PartialFunctions { private static final class DefinedPredicate<I, O, PF extends PartialFunction<I, O>> implements Predicate<PF> { private final I element; private DefinedPredicate(final I element) { this.element = element; } @Override public boolean apply(final PF input) { Preconditions.checkNotNull(input, "null input"); return input.isDefinedAt(this.element); } } private static final class AssignableOutputPredicate<I, O, P extends O, PF extends PartialFunction<I, O>> implements Predicate<PF> { private final Class<P> outputType; private AssignableOutputPredicate(final Class<P> element) { this.outputType = element; } @Override public boolean apply(final PF input) { Preconditions.checkNotNull(input, "null input"); final TypeToken<? extends PartialFunction> typeToken = TypeToken.of(input.getClass()); final Class<?> transformedType = typeToken.resolveType(PartialFunction.class.getTypeParameters()[1]) .getRawType(); return this.outputType.isAssignableFrom(transformedType); } } private PartialFunctions() { } /** * Find first {@link PartialFunction} applicable on `element`. * * @param <I> * @param <O> * @param <PF> * @param partialFunctions * @param element * @return result of first matching {@link PartialFunction} */ public static <I, O, PF extends PartialFunction<I, ? extends O>> Optional<PF> tryFind( final Iterable<PF> partialFunctions, final I element) { Preconditions.checkNotNull(partialFunctions, "null partialFunctions"); Preconditions.checkNotNull(element, "null element"); return Iterables.tryFind(partialFunctions, new DefinedPredicate(element)); } /** * Execute result of execution of first applicable {@link PartialFunction} on `element`. * * @param <I> * @param <O> * @param <PF> * @param partialFunctions * @param element * @return result of first matching {@link PartialFunction} */ public static <I, O, PF extends PartialFunction<I, ? extends O>> Optional<? extends O> tryFindAndTransform( final Iterable<PF> partialFunctions, final I element) { Preconditions.checkNotNull(partialFunctions, "null partialFunctions"); Preconditions.checkNotNull(element, "null element"); return PartialFunctions.transform(PartialFunctions.tryFind(partialFunctions, element), element); } /** * Execute result of execution of first {@link PartialFunction} whose return type matches specified `outputType`. * * @param <I> * @param <O> * @param <P> * @param <PF> * @param partialFunctions * @param type * @param element * @return result of first matching {@link PartialFunction} */ public static <I, O, P extends O, PF extends PartialFunction<I, ? extends O>> Optional<PF> tryFindForOutput( final Iterable<PF> partialFunctions, final Class<? extends P> type, final I element) { Preconditions.checkNotNull(partialFunctions, "null partialFunctions"); Preconditions.checkNotNull(element, "null element"); return Iterables.tryFind(partialFunctions, Predicates.and(new DefinedPredicate(element), new AssignableOutputPredicate(type))); } /** * @param <I> * @param <O> * @param <PF> * @param function * @param input * @return result of execution of optional {@link Function} */ public static <I, O, PF extends PartialFunction<I, ? extends O>> Optional<? extends O> transform( final Optional<PF> function, final I input) { return Optionals.flatten(function.transform(new Function<PF, Optional<O>>() { @Override public Optional<O> apply(final PF input2) { return Optional.fromNullable(input2.apply(input)); } })); } }