Does Java replace an object if it was the same name? This question comes to my mind daily.
Example 1: If I create an object 500 million times with the same object name, does Java create 500 million objects, or will it replace it and stay there in one object?
for (int x = 0; x < 500000000; x++) {
TestObject testObject = new TestObject();
}
Example 2: Which way is better to avoid creating a new object every click?
//Using this way?
List < ActivityManager.RunningServiceInfo > runningServiceInfoList = getRunningService();
activityMainBinding.activityMainConstraintLayout19.setOnClickListener(v - > {
runningServiceInfoList.clear();
runningServiceInfoList = getRunningService();
if (...)
});
//Or this way?
activityMainBinding.activityMainConstraintLayout19.setOnClickListener(v - > {
List < ActivityManager.RunningServiceInfo > runningServiceInfoList = getRunningService();
if (...)
});
Does Java will create 500 million objects
It might create no objects at all, if escape analysis determines that it doesn't need to, since it can just work with the field values on the heap instead.
Worrying about the number of objects created is worrying about things at the wrong level. Think about correctness first, speed later:
If TestObject is immutable, there is no reason to create it in the loop: you can create it inside the loop if you want, or move it outside and reuse the instance.
If TestObject is mutable, is there a risk that you will unintentionally leave state from previous iterations, which will corrupt the calculation in the current iteration? If so, unless creating a new TestObject is really expensive, just create new instances in the loop, because it's then more obviously correct. The JVM is really good at optimizing the life cycle of short-lived objects.
The fact that you're using the same name (in example 1), or even re-assigning to the same variable (in the first snippet of example 2) is inconsequential. A new object will be created, and the old object will be eligible for garbage collection.
Related
I have an one scenario in my application,
I have to add 20 POJO objects into ArrayList. In that case I have a method like below.
public void methodname() {
ArrayList arr = new ArrayList();
for(int i=0;i<20;i++) {
User userobj = new User();
userobj.setName("xxx");
userobj.setFirstName("xxx");
userobj.setLastName("yyy");
arr.add(userobj);
} // end of for loop
}
one of friends suggest to change the UserObj declaration outside for loop.
public void methodname() {
User userobj = new User();
ArrayList arr = new ArrayList();
for(int i=0;i<20;i++) {
userobj.setName("xxx");
userobj.setFirstName("xxx");
userobj.setLastName("yyy");
arr.add(userobj);
} // end of for loop
}
in the first approach, I created the userobj inside the for loop, so when next iteration comes previous userobj will be eligible for garbage collector..
I would like to know is there any significant performance will improve on the second approach?
I would like to know is there any significant performance will improve on the second approach?
Did you experience a difference?
When programming you should focus on correctness and readability of your code.
Do not even Think about performance unless you have an actual performance problem and you have proven by profiling that a certain construct is the cause.
The ultimate universal performance tip is:
The fastest way to do something is not doing it.
So focus on good algorithms that avoid unneeded/hidden loops rather than on syntax variants that may improve performance.
The main difference between the first and the second approach is that in the first case you create 20 different User in memory which are assigned to the array.
In the second case you create only one User in memory but change its properties 20 times and assign the same User to all 20 positions of the array.
Regardless of the first scenario or the second, your User instances created are eligible for garbage collection only when the array itself is eligible for garbage collection, expect you remove the association with the array.
Garbage collection takes place only for an instance if there is no other instance referencing it.
Both the ways, will produce different results.
In the First one, you create 20 separate Objects, and add them to the List. Thus, changes on one of them, won't affect the others.
The Second, however, has the same object. Thus, changes on one will reflect the others. Actually, at the end, the attributes of the all the Objects would be the same, i.e, equal to the last added Object
Performance-wise, you can't say. The Objects would only be eligible for garbage collection, when there are no references pointing to them. However, as both the ways perform separate functions, you can't compare them.
Alas, your Friend is wrong. The First way is what you're looking for.
It needs to be inside the loop, otherwise you are only adding the SAME user 20 times !
On the second approach you will have only one last object in the list
I think that the right way is:
- declaration outside
- instantiation inside
public void methodname() {
ArrayList arr = new ArrayList();
User userobj;
for(int i=0;i<20;i++) {
userobj = new User();
userobj.setName("xxx");
userobj.setFirstName("xxx");
userobj.setLastName("yyy");
arr.add(userobj);
} // end of for loop
}
I'm new to java. I came through the following code while reading an introductory book on Java while reading about the finalize method.
class FDemo{ int x;
FDemo(int i){
x=i;
}
protected void finalize(){
System.out.println("Finalizing " +x)
}
void generator(int i) {
FDemo o= new FDemo(i);
}
}
Now while creating objects I encountered the following in the new class
int count;
FDemo ob= new FDemo(0);
for (count=1;count<10000000;count++)
ob.generator(count);
I'm having trouble understanding how are we creating new objects using the same name 'o' in the for loop? Would we have to create a new object and then on the next iteration discard the existing object 'o' throughout the loop?
Also, why does finalize execute for 10 million but not for 1000 if we are constantly creating and discarding the same object? Like I said, I'm a beginner and this question might sound very basic or even silly for most of the people here but I would appreciate it very much if you could take out a few minutes to answer.
Thank you
Also, why does finalize execute for 10 million but not for 1000 if we
are constantly creating and discarding the same object
You really create 10 million distinct objects in this applications's lifetime, each of which gets referenced by o , one after the other.
Each time, the de-referenced one becomes eligible for garbage collection, because it has become unreachable from the application, and the garbage collector then calls it's finalize method.
How are we creating new objects using the same name 'o' in the for loop?
You should learn some C and how pointers works, Java hide this, so it can be weird some time.
In Java, there is 2 type of data : objects (like String or your FDemo) and primitives (like int, char...).
Variables that references a primitive works like you intended to, each time you give it a new value, it erase the previous one.
Variables that references objects don't work that way, they are pointers. A pointer can be seen as an address. It's clearer in C (and C++), where they are in fact primitives and can be print as well.
Next come the life time of your variables. When you quit the section where you variable is declared, it's cease to exist (but objects are not automatically destroyed and I think it's the purpose of your exercise).
As example :
public void someMethod() {
int a = 1;
// I have access to a
{ // I create a new section, generally, it's use by condition, loop...
int b = 2;
// Here I have access to a and b
} // End of my section
// b is destroyed, I still have access to a
}
// I'm outside my method, a is destroyed
Why does finalize execute for 10 million but not for 1000 if we are constantly creating and discarding the same object?
That's the purpose of the Java's Garbage Collector. It's a big system used to clean memory. It destroys (call the finalize() method) all object that don't have pointers that references them. It's only called when you really need it, because it can use a lot of processing power (in old machine, applications could freeze when the garbage collector starts).
Your object is very simple (only 1 primitive), so it doesn't use a lot of memory. That's why the garbage collector is called only when you create 10 millions objects.
Ok I'm going to break this up into parts.
How are we creating new objects using the same name 'o' in the for
loop?
So, what you are doing here is actually just overriding/re-assiging the reference variable of o to a differnt FDemo. That leaves the old one empty and eventually gets destroyed by garbage collector. (Which is what invokes the finalize() method)
Would we have to create a new object and then on the next iteration
discard the existing object 'o' throughout the loop?
Well that is exactly what you are doing, when you re assign o you are overwriting the old one.
Also, why does finalize execute for 10 million but not for 1000 if we
are constantly creating and discarding the same object?
Well, this is because java's trash collector is only triggered when a massive amount of objects are made. However, I am surprised that 100000 didn't do it.
The thing you have to remember about finalize(), its only called on the trash collection of the object. Now, thats a very unreliable process and isn't really within your control. Like #TT. said in the comments, dont rely on this. The program that you have written simpliy forces the finalize() method to eventually be invoked due to generating a massive amount of objects intentionally. It's a good way to learn about finalize and how it works, but in practice this may not be a great solution.
In my current project (OpenGL Voxel Engine) I have a serious issue when generating models. I have a very object oriented structure, meaning that even single parameters of my vertices are Objects. This way I am creating about 75000 Objects for 750 voxels in about 5 seconds. Is Java really this slow when allocating new Objects or do I miss a big failure somewhere in my code?
Very big question. Generally speaking, it depends from the object class definition and by the amount of work required to construct object.
Some issue:
avoid finalize method,
tune memory and GC in order to avoid excessive GC activity,
avoid big work during constructor,
do not use syncronization call during object construction,
use Weak references
these issues solved my problem.
See also http://oreilly.com/catalog/javapt/chapter/ch04.html
Finally let me suggest you the (deprecated) Object Pool pattern or reuse objects.
Concluding, no, generally speaking, java object creation is not slow
Of course it isn't. The following code allocates 10 million objects and stores them in an array. On my 5 year old notebook, it completes in 1.4 seconds.
public class Test {
public static void main(String[] args) {
Object[] o = new Object[10_000_000];
long start = System.nanoTime();
for (int i = 0; i < o.length; i++) {
o[i] = new Object();
}
long end = System.nanoTime();
System.out.println(Arrays.hashCode(o));
System.out.println(new BigDecimal(end - start).movePointLeft(9));
}
}
... and that's even though this benchmark is quite naive in that it doesn't trigger just in time compilation of the code under test before starting the timer.
Simply creating 75,000 objects should not take 5 seconds. Take a look at the work your constructor is doing. What else are you doing during this time besides creating the objects? Have you tried timing the code to pinpoint where delays occur?
Objects will be slower than primitives, and they will also consume considerably more memory - so it's possible you are going overboard on them. It's hard to say without seeing more details.
75000 objects will not take a long time to create though, try this:
List<Integer> numbers = new ArrayList<Integer>();
for(int i = 0;i<75000;i++){
numbers.add(i); // Note this will autobox creating an Integer object after the first 128
}
System.out.println(numbers.size());
}
http://www.tryjava8.com/app/snippets/52d070b1e4b004716da5cb4f
Total time taken less than a second.
When I put the number up to 7,500,000 it finally took a second...
The new operator in java is very fast compared to the common approach in languages without automatic memory management (e.g. the new operator is usually faster than the malloc-command in C because it does not need a system call).
Although the new operator can still be a bottleneck, it is certainly not the problem in your case. Creating 75K objects should be WAY faster than 5 seconds.
I have the same issue with creating new objects.
My object in constructor allocate single three dimensional array 64x64x64 and no more. FPS fell down to quarter of a value.
I solve this issue with reusing old object and reset it's state (BTW this method reallocate this array without lost performance).
If I move allocation array into separate method and call it after creating the object, speed does not increase to acceptable value.
This object I created is in Main game loop.
I am a bit confused on how to utilize Java's Garbage Collection to dispose of instances of objects that aren't in use anymore. I have a few questions:
In my game, I generate Cannons without storing them in a variable like so:
new Cannon("down", tileX, tileY, 65);
Will this object always be eligible for garbage collection? If yes, then when will it actually be disposed of?
==
For my Cannon class, I add all instances to a static array list upon creation. This was my first attempt at using the garbage collection:
ArrayList<Cannon> cannonList = Cannon.getCannons();
for (int i = 0; i < cannonList.size(); i++) {
Cannon c = (Cannon) cannonList.get(i);
c = null;
}
for (int i = 0; i < cannonList.size(); i++) {
cannonList.remove(i);
}
System.gc();
When I set "c = null;", does it make the original Cannon to "null", thus making it eligible for garbage collection, or does it make a new reference c to the object and then setting it to null, making it do nothing at all for me?
==
My Cannon class continuously creates instances of the EnemyProjectile class. The EnemyProjectiles class contains a boolean field called "visible". What is the correct way to dispose of my EnemyProjectile class and make it eligible for garbage collection when "visible" is equal to false?
The joy of using Java, is that memory is managed for you behind the scenes so that, unlike C or C++, you don't have to worry about deconstructing or disposing of objects. When an object is no longer "usable" (as defined by falling out of scope and being unreachable from another active object) then the garbage collector quietly reclaims the space it was occupying.
In Java, you cannot control when objects are garbage collected nor should you try.
Code that depends on a deterministic garbage collection of unused objects will invariably be fragile and difficult to maintain in Java. in part this is because different JVM implementations will garbage collect at different times. System.gc(); is, at best, a suggestion to the JVM that it do garbage collection, but is no guarantee when (or even if) it will happen.
The best thing you can do is design your program so that reference variables have the absolute shortest possible lifespan. Your code is at risk of memory leaks any time a long-lived object retains a reference to a short-lived object (listeners are an example) or when you create data structures that "manage memory" themselves (eg. your own queue or stack implementation).
ArrayList<Cannon> cannonList = Cannon.getCannons();
for (int i = 0; i < cannonList.size(); i++) {
Cannon c = (Cannon) cannonList.get(i);
c = null;
}
for (int i = 0; i < cannonList.size(); i++) {
cannonList.remove(i);
}
System.gc();
In this snippet, there are several issues:
When you use a data structure from the Java Collections API, you should use the interface as the type, not the concrete class. This is by convention, but doing so will keep your code more flexible. Instead of...
ArrayList<Cannon> cannonList = Cannon.getCannons();
write this instead (valid for any class instances that implement the List interface):
List<Cannon> cannonList = Cannon.getCannons();
When possible, you should use the enhanced for-each loop introduced with Java SE 5. It is less error prone. Your for loops should look like this:
for (Cannon c : cannonList) {
c = null; // this for loop actually accomplishes no useful work since
// the reference is null'd as soon as it gets a reference to
// a Cannon object. The reference in your ArrayList is unaffected
// by this assignment
}
cannonList.clear(); // more concise than removing each element from the list.
TL;DR: Garbage collection occurs when it happens. It is non-deterministic. You are never guaranteed when or even if it will happen. Design your Java programs to make your objects eligible for garbage collection at the earliest possible time ... and then don't worry at all about what happens.
I'm in my first programming class in high school. We're doing our end of the first semester project.
This project only involves one class, but many methods. My question is about best practice with instance variables and local variables. It seems that it would be much easier for me to code using almost only instance variables. But I'm not sure if this is how I should be doing it or if I should be using local variables more (I would just have to have methods take in the values of local variables a lot more).
My reasoning for this is also because a lot of times I'll want to have a method return two or three values, but this is of course not possible. Thus it just seems easier to simply use instance variables and never having to worry since they are universal in the class.
I haven't seen anyone discuss this so I'll throw in more food for thought. The short answer/advice is don't use instance variables over local variables just because you think they are easier to return values. You are going to make working with your code very very hard if you don't use local variables and instance variables appropriately. You will produce some serious bugs that are really hard to track down. If you want to understand what I mean by serious bugs, and what that might look like read on.
Let's try and use only instance variables as you suggest to write to functions. I'll create a very simple class:
public class BadIdea {
public Enum Color { GREEN, RED, BLUE, PURPLE };
public Color[] map = new Colors[] {
Color.GREEN,
Color.GREEN,
Color.RED,
Color.BLUE,
Color.PURPLE,
Color.RED,
Color.PURPLE };
List<Integer> indexes = new ArrayList<Integer>();
public int counter = 0;
public int index = 0;
public void findColor( Color value ) {
indexes.clear();
for( index = 0; index < map.length; index++ ) {
if( map[index] == value ) {
indexes.add( index );
counter++;
}
}
}
public void findOppositeColors( Color value ) {
indexes.clear();
for( index = 0; i < index < map.length; index++ ) {
if( map[index] != value ) {
indexes.add( index );
counter++;
}
}
}
}
This is a silly program I know, but we can use it to illustrate the concept that using instance variables for things like this is a tremendously bad idea. The biggest thing you'll find is that those methods use all of the instance variables we have. And it modifies indexes, counter, and index every time they are called. The first problem you'll find is that calling those methods one after the other can modify the answers from prior runs. So for example, if you wrote the following code:
BadIdea idea = new BadIdea();
idea.findColor( Color.RED );
idea.findColor( Color.GREEN ); // whoops we just lost the results from finding all Color.RED
Since findColor uses instance variables to track returned values we can only return one result at a time. Let's try and save off a reference to those results before we call it again:
BadIdea idea = new BadIdea();
idea.findColor( Color.RED );
List<Integer> redPositions = idea.indexes;
int redCount = idea.counter;
idea.findColor( Color.GREEN ); // this causes red positions to be lost! (i.e. idea.indexes.clear()
List<Integer> greenPositions = idea.indexes;
int greenCount = idea.counter;
In this second example we saved the red positions on the 3rd line, but same thing happened!?Why did we lose them?! Because idea.indexes was cleared instead of allocated so there can only be one answer used at a time. You have to completely finish using that result before calling it again. Once you call a method again the results are cleared and you lose everything. In order to fix this you'll have to allocate a new result each time so red and green answers are separate. So let's clone our answers to create new copies of things:
BadIdea idea = new BadIdea();
idea.findColor( Color.RED );
List<Integer> redPositions = idea.indexes.clone();
int redCount = idea.counter;
idea.findColor( Color.GREEN );
List<Integer> greenPositions = idea.indexes.clone();
int greenCount = idea.counter;
Ok finally we have two separate results. The results of red and green are now separate. But, we had to know a lot about how BadIdea operated internally before the program worked didn't we? We need to remember to clone the returns every time we called it to safely make sure our results didn't get clobbered. Why is the caller forced to remember these details? Wouldn't it be easier if we didn't have to do that?
Also notice that the caller has to use local variables to remember the results so while you didn't use local variables in the methods of BadIdea the caller has to use them to remember results. So what did you really accomplish? You really just moved the problem to the caller forcing them to do more. And the work you pushed onto the caller is not an easy rule to follow because there are some many exceptions to the rule.
Now let's try doing that with two different methods. Notice how I've been "smart" and I reused those same instance variables to "save memory" and kept the code compact. ;-)
BadIdea idea = new BadIdea();
idea.findColor( Color.RED );
List<Integer> redPositions = idea.indexes;
int redCount = idea.counter;
idea.findOppositeColors( Color.RED ); // this causes red positions to be lost again!!
List<Integer> greenPositions = idea.indexes;
int greenCount = idea.counter;
Same thing happened! Damn but I was being so "smart" and saving memory and the code uses less resources!!! This is the real peril of using instance variables like this is calling methods is order dependent now. If I change the order of the method calls the results are different even though I haven't really changed the underlying state of BadIdea. I didn't change the contents of the map. Why does the program yield different results when I call the methods in different order?
idea.findColor( Color.RED )
idea.findOppositeColors( Color.RED )
Produces a different result than if I swapped those two methods:
idea.findOppositeColors( Color.RED )
idea.findColor( Color.RED )
These types of errors are really hard to track down especially when those lines aren't right next to each other. You can completely break your program by just adding a new call in anywhere between those two lines and get wildly different results. Sure when we're dealing with small number of lines it's easy to spot errors. But, in a larger program you can waste days trying to reproduce them even though the data in the program hasn't changed.
And this only looks at single threaded problems. If BadIdea was being used in a multi-threaded situation the errors can get really bizarre. What happens if findColors() and findOppositeColors() is called at the same time? Crash, all your hair falls out, Death, space and time collapse into a singularity and the universe is swallows up? Probably at least two of those. Threads are probably above your head now, but hopefully we can steer you away from doing bad things now so when you do get to threads those bad practices don't cause you real heartache.
Did you notice how careful you had to be when calling the methods? They overwrote each other, they shared memory possibly randomly, you had to remember the details of how it worked on the inside to make it work on the outside, changing the order in which things were called produce very big changes in the next lines down, and it only could only work in a single thread situation. Doing things like this will produce really brittle code that seems to fall apart whenever you touch it. These practices I showed contributed directly to the code being brittle.
While this might look like encapsulation it is the exact opposite because the technical details of how you wrote it have to be known to the caller. The caller has to write their code in a very particular way to make their code work, and they can't do it without knowing about the technical details of your code. This is often called a Leaky Abstraction because the class is suppose to hide the technical details behind an abstraction/interface, but the technical details leak out forcing the caller to change their behavior. Every solution has some degree of leaky-ness, but using any of the above techniques like these guarantees no matter what problem you are trying to solve it will be terribly leaky if you apply them. So let's look at the GoodIdea now.
Let's rewrite using local variables:
public class GoodIdea {
...
public List<Integer> findColor( Color value ) {
List<Integer> results = new ArrayList<Integer>();
for( int i = 0; i < map.length; i++ ) {
if( map[index] == value ) {
results.add( i );
}
}
return results;
}
public List<Integer> findOppositeColors( Color value ) {
List<Integer> results = new ArrayList<Integer>();
for( int i = 0; i < map.length; i++ ) {
if( map[index] != value ) {
results.add( i );
}
}
return results;
}
}
This fixes every problem we discussed above. I know I'm not keeping track of counter or returning it, but if I did I can create a new class and return that instead of List. Sometimes I use the following object to return multiple results quickly:
public class Pair<K,T> {
public K first;
public T second;
public Pair( K first, T second ) {
this.first = first;
this.second = second;
}
}
Long answer, but a very important topic.
Use instance variables when it's a core concept of your class. If you're iterating, recursing or doing some processing, then use local variables.
When you need to use two (or more) variables in the same places, it's time to create a new class with those attributes (and appropriate means to set them). This will make your code cleaner and help you think about problems (each class is a new term in your vocabulary).
One variable may be made a class when it is a core concept. For example real-world identifiers: these could be represented as Strings, but often, if you encapsulate them into their own object they suddenly start "attracting" functionality (validation, association to other objects, etc.)
Also (not entirely related) is object consistency - an object is able to ensure that its state makes sense. Setting one property may alter another. It also makes it far easier to alter your program to be thread-safe later (if required).
Local variables internal to methods are always prefered, since you want to keep each variable's scope as small as possible. But if more than one method needs to access a variable, then it's going to have to be an instance variable.
Local variables are more like intermediate values used to reach a result or compute something on the fly. Instance variables are more like attributes of a class, like your age or name.
The easy way: if the variable must be shared by more than one method, use instance variable, otherwise use local variable.
However, the good practice is to use as more local variables as possible. Why? For your simple project with only one class, there is no difference. For a project that includes a lot of classes, there is big difference. The instance variable indicates the state of your class. The more instance variables in your class, the more states this class can have and then, the more complex this class is, the hard the class is maintained or the more error prone your project might be. So the good practice is to use as more local variable as possible to keep the state of the class as simple as possible.
Short story: if and only if a variable needs to be accessed by more than one method (or outside of the class), create it as an instance variables. If you need it only locally, in a single method, it has to be a local variable.
Instance variables are more costly than local variables.
Keep in mind: instance variables are initialized to default values while local variables are not.
Declare variables to be scoped as narrowly as possible. Declare local variables first. If this isn't sufficient, use instance variables. If this isn't sufficient, use class (static) variables.
I you need to return more than one value return a composite structure, like an array or an object.
Try to think about your problem in terms of objects. Each class represents a different type of object. Instance variables are the pieces of data that a class needs to remember in order to work, either with itself or with other objects. Local variables should just be used intermediate calculations, data that you don't need to save once you leave the method.
Try not to return more than one value from your methods in first place. If you can't, and in some cases you really can't, then I would recommend encapsulating that in a class. Just in last case I would recommend changing another variable inside your class (an instance variable). The problem with the instance variables approach is that it increases side effects - for example, you call method A in your program and it modifies some instance(s) variable(s). Over time, that leads to increased complexity in your code and maintenance becomes harder and harder.
When I have to use instance variables, I try to make then final and initialize then in the class constructors, so side effects are minimized. This programming style (minimizing the state changes in your application) should lead to better code that is easier to maintain.
Generally variables should have minimal scope.
Unfortunately, in order to build classes with minimized variable scope, one often needs to do a lot of method parameter passing.
But if you follow that advice all the time, perfectly minimizing variable scope, you
may end up with a lot of redundancy and method inflexibility with all the required objects passed in and out of methods.
Picture a code base with thousands of methods like this:
private ClassThatHoldsReturnInfo foo(OneReallyBigClassThatHoldsCertainThings big,
AnotherClassThatDoesLittle little) {
LocalClassObjectJustUsedHere here;
...
}
private ClassThatHoldsReturnInfo bar(OneMediumSizedClassThatHoldsCertainThings medium,
AnotherClassThatDoesLittle little) {
...
}
And, on the other hand, imagine a code base with lots of instance variables like this:
private OneReallyBigClassThatHoldsCertainThings big;
private OneMediumSizedClassThatHoldsCertainThings medium;
private AnotherClassThatDoesLittle little;
private ClassThatHoldsReturnInfo ret;
private void foo() {
LocalClassObjectJustUsedHere here;
....
}
private void bar() {
....
}
As code increases, the first way may minimize variable scope best, but can easily lead to a lot of method parameters being passed around. The code will usually be more verbose and this can lead to a complexity as one refactors all these methods.
Using more instance variables can reduce the complexity of lots of method parameters being passed around and can give a flexibility to methods when you are frequently reorganizing methods for clarity. But it creates more object state that you have to maintain. Generally the advice is to do the former and refrain from the latter.
However, very often, and it may depend on the person, one can more easily manage state complexity compared with the thousands of extra object references of the first case. One may notice this when business logic within methods increases and organization needs to change to keep order and clarity.
Not only that. When you reorganize your methods to keep clarity and make lots of method parameter changes in the process, you end up with lots of version control diffs which is not so good for stable production quality code. There is a balance. One way causes one kind of complexity. The other way causes another kind of complexity.
Use the way that works best for you. You will find that balance over time.
I think this young programmer has some insightful first impressions for low maintenance code.
Use instance variables when
If two functions in the class need the same value, then make it an instance variable
or
If the state is not expected to change, make it an instance variable. For example: immutable object, DTO, LinkedList, those with final variables
or
If it is an underlying data on whom actions are performed. For example: final in arr[] in the PriorityQueue.java source code file
or
Even if it is used only once and state is expected to change, make it an instance if it is used only once by a function whose parameter list should be empty. For example: HTTPCookie.java Line: 860 hashcode() function uses 'path variable'.
Similarly, use a local variable when none of these conditions match, specifically if the role of the variable would end after the stack is popped off. For example: Comparator.compare(o1, o2);