All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.lang3.concurrent.Memoizer Maven / Gradle / Ivy

Go to download

Apache Commons Lang, a package of Java utility classes for the classes that are in java.lang's hierarchy, or are considered to be so standard as to justify existence in java.lang. The code is tested using the latest revision of the JDK for supported LTS releases: 8, 11, 17 and 21 currently. See https://github.com/apache/commons-lang/blob/master/.github/workflows/maven.yml Please ensure your build environment is up-to-date and kindly report any build issues.

There is a newer version: 3.17.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.commons.lang3.concurrent;

import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * 

* Definition of an interface for a wrapper around a calculation that takes a * single parameter and returns a result. The results for the calculation will * be cached for future requests. *

*

* This is not a fully functional cache, there is no way of limiting or removing * results once they have been generated. However, it is possible to get the * implementation to regenerate the result for a given parameter, if an error * was thrown during the previous calculation, by setting the option during the * construction of the class. If this is not set the class will return the * cached exception. *

*

* Thanks should go to Brian Goetz, Tim Peierls and the members of JCP JSR-166 * Expert Group for coming up with the original implementation of the class. It * was also published within Java Concurrency in Practice as a sample. *

* * @param * the type of the input to the calculation * @param * the type of the output of the calculation * * @since 3.6 */ public class Memoizer implements Computable { private final ConcurrentMap> cache = new ConcurrentHashMap<>(); private final Computable computable; private final boolean recalculate; /** *

* Constructs a Memoizer for the provided Computable calculation. *

*

* If a calculation is thrown an exception for any reason, this exception * will be cached and returned for all future calls with the provided * parameter. *

* * @param computable * the computation whose results should be memorized */ public Memoizer(final Computable computable) { this(computable, false); } /** *

* Constructs a Memoizer for the provided Computable calculation, with the * option of whether a Computation that experiences an error should * recalculate on subsequent calls or return the same cached exception. *

* * @param computable * the computation whose results should be memorized * @param recalculate * determines whether the computation should be recalculated on * subsequent calls if the previous call failed */ public Memoizer(final Computable computable, final boolean recalculate) { this.computable = computable; this.recalculate = recalculate; } /** *

* This method will return the result of the calculation and cache it, if it * has not previously been calculated. *

*

* This cache will also cache exceptions that occur during the computation * if the {@code recalculate} parameter is the constructor was set to * {@code false}, or not set. Otherwise, if an exception happened on the * previous calculation, the method will attempt again to generate a value. *

* * @param arg * the argument for the calculation * @return the result of the calculation * @throws InterruptedException * thrown if the calculation is interrupted */ @Override public O compute(final I arg) throws InterruptedException { while (true) { Future future = cache.get(arg); if (future == null) { final Callable eval = () -> computable.compute(arg); final FutureTask futureTask = new FutureTask<>(eval); future = cache.putIfAbsent(arg, futureTask); if (future == null) { future = futureTask; futureTask.run(); } } try { return future.get(); } catch (final CancellationException e) { cache.remove(arg, future); } catch (final ExecutionException e) { if (recalculate) { cache.remove(arg, future); } throw launderException(e.getCause()); } } } /** *

* This method launders a Throwable to either a RuntimeException, Error or * any other Exception wrapped in an IllegalStateException. *

* * @param throwable * the throwable to laundered * @return a RuntimeException, Error or an IllegalStateException */ private RuntimeException launderException(final Throwable throwable) { if (throwable instanceof RuntimeException) { return (RuntimeException) throwable; } else if (throwable instanceof Error) { throw (Error) throwable; } else { throw new IllegalStateException("Unchecked exception", throwable); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy