Does the Arraylist object store the last requested value in memory to access it faster the next time? Or do I need to do this myself?
Or more concretely, in terms of performance, is it better to do this :
for (int i = 0; i < myArray.size(); i++){
int value = myArray.get(i);
int result = value + 2 * value - 5 / value;
}
Instead of doing this :
for (int i = 0; i < myArray.size(); i++)
int result = myArray.get(i) + 2 * myArray.get(i) - 5 / myArray.get(i);
In terms of performance, it doesn't matter one bit. No, ArrayList doesn't cache anything, although the JITted end result could be a different issue.
If you're wondering which version to use, use the first one. It's clearer.
You can answer your (first) question yourself by looking into the actual source:
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
So: No, there is no caching taking place but you can also see that there is no much of an impact in terms of performance because the get method is essentially just an access to an array.
But it's still good to avoid multiple calls for some reasons:
int result = value + 2 * value - 5 / value is easier to understand (i.e. realizing that you use the same value three times in your calculation)
If you later decide to change the underlying list (e.g. to a LinkedList) you might end up with an impact on performance and then have to change your code to get around it.
As long as you don't synchronize the access to the list, repeated calls of get(index) might actually return different values if between two calls a call of set(index, value) has taken place (even in small souce blocks like this, it's possible to happen - BTST)
The second point has also a consequence in terms of how to access all values of a list, that leads to the decision to avoid list.get(i) altogether if you're going to iterate over all elements in a list. In that case it's better to use the Iterator or streams:
You code would then look like this:
Iterator it = myArray.iterator();
while (it.hasNext()) {
int value = it.next();
int result = value + 2 * value - 5 / value;
}
LinkedList is very slow when trying to access elements in it by specific index but can iteratre quite fast from one element to the next, so the Iterator returned by LinkedList makes use of that while the Iterator returned by ArrayList simply accesses the internal array (without the need to do the repeated range check calls you can see in the get-method above
Related
This question already has answers here:
java performance : Is storing a hashMap value in a variable redundant?
(4 answers)
Is it better to store value as variable or call method again?
(5 answers)
Calling getters on an object vs. storing it as a local variable (memory footprint, performance)
(6 answers)
Java Method invocation vs using a variable
(14 answers)
Closed 4 years ago.
When you need to call a HashMap's get on the same value a few times within a for loop, would it be more efficient to store it in a variable or to make the call two or three times?
Retrieving a value from a HashMap is an O(1) operation, assuming your keys have a reasonable implementation of hashCode().
If you're only retrieving this object a couple of times it may be a micro-optimization (read: premature optimization) to store it in a local variable, but you probably won't notice any difference either way. The real reason to store such an object in a local variable is to avoid duplicating boiler-plate code that checks the key really exists in the map, the value isn't null, etc.
Accessing data in HashMap is O(1), so in general it's quite fast. However, if you initiate a variable with the proper value from the HashMap it would be a little bit faster. If you are accessing HashMap with some key, firstly hashCode method of the key is called. If you call that once - it would be faster.
My experience shows that preparing a variable for such cases is a better solution not only because of performance purposes but also because of refactoring. If it happened you had to change some code, you made one change in HashMap call instead of many in different lines, leaving often one line unchanged (which leads to a bug).
HashMap get runs in constant time. So from efficiency point of view, it doesn't matter. Although storing the value in a variable is more cleaner.
Calling hashmap.get() creates an indirection, therefor it's will be slower than a direct variable reference. The fact that hashmap.get() has O(1) complexity has absolutely nothing to do with the answer to this question, because O(1) complexity only means that the execution complexity of the algorithm does not increase with a growing number of elements, but, it does not say anything about how many cpu cycles a run takes, it only states that it's constant.
Storing the result in a variable would probably be the most performant.
I've made a simple test with HashMap<String, String>, where both keys and values are random-generated 64-character strings. It uses 1.000.000 records in the map and goes through each of them in 2 for-loops: First is calling get() once and saving it to variable. Second is calling get() 3 times. This is done in 5 iterations.
Results (in milliseconds):
1 2 3 4 5 avg
Store in a variable: 125 126 103 104 102 | 112
Call 3 times: 151 135 137 134 152 | 142
So, for this configuration (map of string-string), calling get() once and storing result in a variable is more effective.
Code of the test:
ArrayList<String> keys;
HashMap<String, String> data;
void run() {
generateData(1_000_000);
long start, end;
for (int i = 0; i < 5; ++i) {
start = System.nanoTime();
for (String key : keys) {
String value = data.get(key);
}
end = System.nanoTime();
System.out.println("Store in a variable: " + ((end - start) / 1000 / 1000) + "ms");
start = System.nanoTime();
for (String key : keys) {
data.get(key);
data.get(key);
data.get(key);
}
end = System.nanoTime();
System.out.println("Call 3 times: " + ((end - start) / 1000 / 1000) + "ms");
}
}
void generateData(int size) {
keys = new ArrayList<>(size);
data = new HashMap<>(size);
for (int i = 0; i < size; ++i) {
String key = getRandomString(64);
keys.add(key);
data.put(key, getRandomString(64));
}
}
String getRandomString(int length) {
StringBuilder str = new StringBuilder();
for (int i = 0; i < length; ++i) {
str.append((char) ThreadLocalRandom.current().nextInt(128));
}
return str.toString();
}
I need to calculate all permutations of a collection and i have a code for that but the problem is that it is linear and takes a lot of time.
public static <E> Set<Set<E>> getAllCombinations(Collection<E> inputSet) {
List<E> input = new ArrayList<>(inputSet);
Set<Set<E>> ret = new HashSet<>();
int len = inputSet.size();
// run over all numbers between 1 and 2^length (one number per subset). each bit represents an object
// include the object in the set if the corresponding bit is 1
for (int i = (1 << len) - 1; i > 0; i--) {
Set<E> comb = new HashSet<>();
for (int j = 0; j < len; j++) {
if ((i & 1 << j) != 0) {
comb.add(input.get(j));
}
}
ret.add(comb);
}
return ret;
}
I am trying to make the computation run in parallel.
I though of the option to writing the logic using recursion and then parallel execute the recursion call but i am not exactly sure how to do that.
Would appreciate any help.
There is no need to use recursion, in fact, that might be counter-productive. Since the creation of each combination can be performed independently of the others, it can be done using parallel Streams. Note that you don’t even need to perform the bit manipulations by hand:
public static <E> Set<Set<E>> getAllCombinations(Collection<E> inputSet) {
// use inputSet.stream().distinct().collect(Collectors.toList());
// to get only distinct combinations
// (in case source contains duplicates, i.e. is not a Set)
List<E> input = new ArrayList<>(inputSet);
final int size = input.size();
// sort out input that is too large. In fact, even lower numbers might
// be way too large. But using <63 bits allows to use long values
if(size>=63) throw new OutOfMemoryError("not enough memory for "
+BigInteger.ONE.shiftLeft(input.size()).subtract(BigInteger.ONE)+" permutations");
// the actual operation is quite compact when using the Stream API
return LongStream.range(1, 1L<<size) /* .parallel() */
.mapToObj(l -> BitSet.valueOf(new long[] {l}).stream()
.mapToObj(input::get).collect(Collectors.toSet()))
.collect(Collectors.toSet());
}
The inner stream operation, i.e. iterating over the bits, is too small to benefit from parallel operations, especially as it would have to merge the result into a single Set. But if the number of combinations to produce is sufficiently large, running the outer stream in parallel will already utilize all CPU cores.
The alternative is not to use a parallel stream, but to return the Stream<Set<E>> itself instead of collecting into a Set<Set<E>>, to allow the caller to chain the consuming operation directly.
By the way, hashing an entire Set (or lots of them) can be quite expensive, so the cost of the final merging step(s) are likely to dominate the performance. Returning a List<Set<E>> instead can dramatically increase the performance. The same applies to the alternative of returning a Stream<Set<E>> without collecting the combinations at all, as this also works without hashing the Sets.
I was curious if, in Java, you could create a piece of code that keeps iterating a piece of code without the use of a for or while loop, and if so, what methods could be used to solve this?
Look at recursion. A recursive function is a function which calls itself until a base case is reached. An example is the factorial function:
int fact(int n)
{
int result;
if(n==1)
return 1;
result = fact(n-1) * n;
return result;
}
You could use the Java 8 Streams methods for iterating over the elements of a Collection. Among the methods you can use are filtering methods (get all the elements of a collection that satisfy some conditions), mapping methods (map a Collection of one type to a Collection of another type) and aggregation methods (like computing the sum of all the elements in a Collection, based on some integer member of the Element stored in the collection).
For example - Stream forEach :
List<Element> = new ArrayList<Element>();
...
list.stream().forEach (element -> System.out.println(element));
Or you can do it without a Stream :
List<Element> = new ArrayList<Element>();
...
list.forEach (element -> System.out.println(element));
Another variant of recursion:
public class LoopException extends Exception {
public LoopException(int i, int max) throws LoopException {
System.out.println( "Loop variable: "+i);
if (i < max)
throw new LoopException( i+1, max );
}
}
Of course this is just a bit of fun, don't ever do it for real.
Java does not have a goto statement (that's a lie), so that way is a dead end.
But you could always make a piece of code endlessly iterate using recursion. Old factorial function seems to be the favorite, but since it is not an infinite loop, I will go for this simple function:
int blowMyStack(int a) {
return blowMyStack(a + 1);
}
There will be many ways to do this using various features of the language. But it always falls to an underlying recursion.
In case you're referring of something like C's goto, the answer is no.
In other cases, you can use recursive functions.
Im trying to convert a linkedList into an ArrayList as shown below.
private LinkedList<myData> myLinkedList= new LinkedList<myData>();
public Collection<myData> getData()
{
return new ArrayList<myData>(myLinkedList);
}
The linkedList might be updated by multiple threads. While testing in production I get the below error. The error is not consistant. So i get it may be once in a week, month or so.
java.lang.ArrayIndexOutOfBoundsException: 15
at java.util.LinkedList.toArray(LinkedList.java:866)
at java.util.ArrayList.<init>(ArrayList.java:131)
at org.xxx.yyy.zzz.getData(Data.java:291)
Is there any way it could be related to concurrent modification of the linkedList. Appreciate any help on this.
toArray failing is only one symptom of you doing something fundamentally dangerous.
From the documentation of LinkedList:
If multiple threads access a linked list concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
You'll either need to add synchronization (not just for toArray, but basically all uses of the list) or use one of the concurrent collections which is designed to be thread-safe.
LinkedList#toArray() is implemented as such (Oracle JDK 7)
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
If you add to the LinkedList after the result array is constructed but before the for loop, then the array access expression inside the for loop will cause an ArrayIndexOutOfBoundsException when trying to access an index larger than the original size.
You should really put some synchronization barriers so that doesn't happen.
Using Java 1.6 and the AtomicLongArray, I'd like to "copy" the original AtomicLongArray into a new one. There is a constructor that takes an array (AtomicLongArray(long[])), so I thought I could just get the array from the original one and give it to the constructor.
Sadly, the actual long[] in the AtomicLongArray is private and there seem to be no getters for it. Is there any way to do this, meaning copy the values from one AtomicLongArray to another? I can't create my own class based on this class, as the sun.misc.Unsafe class is not available to me.
This is needed because I'm going to iterate over the values, and I don't want them modified by another thread during iteration. So I thought I could make a copy and use that for the iteration...
Thanks!
Phillip
I suspect you have to create your own long[] and populate it first, or just iterate over the original:
AtomicLongArray copy = new AtomicLongArray(original.length());
for (int i = 0; i < copy.length(); i++)
{
copy.set(i, original.get(i));
}
Note that although each individual operation in AtomicLongArray is atomic, there are no bulk operations - so there's no way of getting a "snapshot" of the whole array at time T. If you want that sort of behaviour, I believe you'll need to use synchronization.
This data structure allows concurrent updates to individual entries in the collection. There is not overall lock, so you can't prevent another thread changing the contents while you are iterating over it.
If you need this, you need a workaround, e.g. copy the array and loop again to check it hasn't changed. If changed, repeat. Or you need a collection which supports a global lock.
long[] copy = new long[original.length()];
boolean changed = true;
// repeat until we get an unchanged copy.
while(true) {
for (int i = 0; i < copy.length(); i++) {
long l = original.get(i);
changed |= copy[i] != l;
copy[i] = l;
}
if (!changed) break;
changed = false;
}
This is not completely safe, but may be enough for what you need.