有的地方要用一個簡單的數組緩存運算結果,空間換時間,但是要求萬一內存不夠,要這些結果能被釋放(WeakReference),所以有了這個工具類。
/*
* Copyright 2012 raistlic ([email protected])
*
* 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.
*/
import java.lang.ref.WeakReference;
import java.util.Iterator;
/**
* This class simply encapsulates an array to be used as a cache, which holds
* weak references.
*
* It is intended to store "not so important" contents, which can be GCed
* when required.
*
* The iterator of this class can be used to iterate it, or remove elements
* from it, removing elements using the iterator will not effect the subsequent
* elements' positions.
*
* @author raistlic
* @date 27/09/2012
*/
public class WeakArray<E> implements Iterable<E> {
@SuppressWarnings({"unchecked", "rawtypes"})
private WeakReference<E>[] data;
public WeakArray(int size) {
if( size < 0 )
throw new IllegalArgumentException("Invalid array size: " + size);
data = (WeakReference<E>[])new WeakReference[size];
}
public int length() {
return data.length;
}
public void set(int index, E element) {
// potentially throws ArrayIndexOutOfBoundsException
if( get(index) != element )
data[index] = new WeakReference<E>(element);
}
public E get(int index) {
// potentially throws ArrayIndexOutOfBoundsException
WeakReference<E> ref = data[index];
return ref == null ? null : ref.get();
}
public void remove(int index) {
// potentially throws ArrayIndexOutOfBoundsException
data[index] = null;
}
@Override
public Iterator<E> iterator() {
return new IndexIterator();
}
private class IndexIterator implements Iterator<E> {
private int index = 0;
@Override
public boolean hasNext() {
return index < length();
}
@Override
public E next() {
// potentially throws ArrayIndexOutOfBoundsException
E result = get(index);
index++;
return result;
}
@Override
public void remove() {
// potentially throws ArrayIndexOutOfBoundsException
WeakArray.this.remove(index);
index++;
}
}
}
上一篇文章裏用來計算階乘的工具類 Calculator,可以使用 WeakArray 來cache運算結果,修改如下:
/*
* Copyright 2012 raistlic ([email protected])
*
* 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.
*/
import java.math.BigInteger;
/**
* This class is intended to provide convenient facilities for
* frequently used maths calculations that {@code java.lang.Math}
* does not cover.
*
* @date 08/08/2012
* @author raistlic
*/
public final class Calculator {
private Calculator() {}
private static final WeakArray<BigInteger> FACT_POOL =
new WeakArray<BigInteger>(1024);
public static BigInteger factorial(int number) {
if( number < 0 )
throw new IllegalArgumentException();
BigInteger result = null;
if( number < FACT_POOL.length() )
result = FACT_POOL.get(number);
if( result == null ) {
int lastCachedIndex = lastCachedFactIndex(number);
if( lastCachedIndex > 0 )
result = FACT_POOL.get(lastCachedIndex);
if( result == null )
result = BigInteger.ONE;
for(int i = Math.max(2, lastCachedIndex+1); i <= number; i++) {
result = result.multiply(BigInteger.valueOf(i));
if( i < FACT_POOL.length() )
FACT_POOL.set(i, result);
}
}
return result;
}
private static int lastCachedFactIndex(int number) {
for(int i=Math.min(number, FACT_POOL.length()-1); i>=0; i--) {
if( FACT_POOL.get(i) != null )
return i;
}
return -1;
}
}