Is static bad? How to remove static variables? - java

I have some code that I am working on. It's basically takes in user input and creates a directed graph. One person can travel one way, the other person the opposite. The output is the overlap of where they can visit.
I have most everything working the way that I want it to, but I am concerned with the use of static that I have. I don't seem to fully understand it and no matter where I look, I can't find out its exact use OR how to get rid of it.
Could someone please help me to understand what static is and why it would be helpful?
Also, would it be better to move most the code from MAIN to helper methods? If I do this I have to move all my variables from main to the top of the class and then they all have to be declared as static?!

The reason everything has to be static is because you aren't creating any objects. If you were to create an object by calling new in your main method, you could use non-static variables on that object. This isn't really a good place to give you a tutorial on why you might want to use object-oriented design; you can find one of those online to read (a commenter above gave a possible reference). But the reason everything has to be static is because it's all just running from the main method, which is always static in java. If you were to call new somewhere, you could use non-static variables.

Static makes a method or a variable accessible to all the instances of a class. It's like a constant, but for classes. To make it more easy to understand some code will do the work:
public class Example {
public static int numero;
}
public class Implementation {
public static void main (String args[]) {
Example ex1 = new Example();
Example ex2 = new Example();
Example.numero=10;
System.out.println("Value for instance 1 is: " + ex1.numero);
System.out.println("Value for instance 2 is: " + ex2.numero);
}
}
Running the follwing code will output:
Value for instance 1 is: 10
Value for instance 2 is: 10
Because you set the static variable numero (number in italian) to 10.
Got it?

It looks like a lot of your static methods (findNodeInList, etc) all take the ArrayList (which represents a map) as their first argument. So instead of having it static, you could have a class Map, which stores a list of nodes and has methods on them. Then the main method would read the input, but not have to manage any nodes directly. e.g:
class Map {
ArrayList<Node> nodes;
public void addNode(Node n) { nodes.add(n); }
public int findNodeInList(String s) { ... }
...
public static void main(String[] args) {
Map peggyMap = new Map();
Map samMap = new Map();
// Read the data
samMap.add(new Node(...));
}
}
This keeps all the stuff to do with nodes/maps well encapsulated and not mixed in with stuff to do with reading the data.

Static is useful if you going to be using the class/method throught out your program and you don't what to create a instance every time you need to use that method.
For ex
public class StaticExample {
public static void reusable() {
//code here
}
}
It means you can use it like this
StaticExample.reusable();
and you don't have to create an instance like this
StaticExample staticExample = new StaticExample();
staticExample.reuseable();
I hope this help you decide whether to use static or not.

Related

Why Must this method be static(Java)?

For some background, I'm currently on chapter 8 in my book, we finished talking about arraylists, arrays, if statements, loops etc. Now this part of the book talks about call by reference,value and some other pretty neat things that seem odd to me at first.I've read What situation to use static and some other SO questions, and learned quite a bit as well.
Consider the following example my book gave (among many examples)
There is another reason why static methods are sometimes necessary. If
a method manipulates a class that you do not own, you cannot add it to
that class. Consider a method that computes the area of a rectangle.
The Rectangle class in the standard library has no such feature, and
we cannot modify that class. A static method solves this problem:
public class Geometry
{
public static double area(Rectangle rect)
{
return rect.getWidth() * rect.getHeight();
}
// More geometry methods can be added here.
}
Now we can tell you why the main method is static. When the program
starts, there aren’t any objects. Therefore, the first method in the
program must be a static method.
Ok, thats pretty cool, up until now I've just been really blindly putting public in front of all my methods, so this is great to know. But the review small problem on the next page caught my attention
The following method computes the average of an array list of numbers:
public static double average(ArrayList<Double> values)
Why must it be a static method?
Here I was like wait a sec. I'm pretty sure I did this without using static before. So I tried doing this again and pretty easily came up with the following
import java.util.ArrayList;
class ArrList
{
private double sum;
public ArrList()
{
sum = 0;
}
public double average(ArrayList <Double> values)
{
for(int i = 0; i < values.size() ; i++)
{
sum+=values.get(i);
}
return sum / values.size();
}
}
public class Average
{
public static void main(String [] args)
{
ArrList arrListObj = new ArrList();
ArrayList<Double> testArrList = new ArrayList<Double>();
testArrList.add(10.0);
testArrList.add(50.0);
testArrList.add(20.0);
testArrList.add(20.0);
System.out.println(arrListObj.average(testArrList));
}
}
TLDR
Why does my book say that public static double average(ArrayList<Double> values) needs to be static?
ATTEMPT AT USING STATIC
public class Average
{
public static void main(String [] args)
{
ArrayList<Double> testArrList = new ArrayList<Double>();
ArrayList<Double> testArrListTwo = new ArrayList<Double>();
testArrList.add(10.0);
testArrList.add(50.0);
testArrList.add(20.0);
testArrList.add(20.0);
testArrListTwo.add(20.0);
testArrListTwo.add(20.0);
testArrListTwo.add(20.0);
System.out.println(ArrList.average(testArrList));
System.out.println(ArrList.average(testArrListTwo)); // we don't get 20, we get 53.3333!
}
}
It doesn't.
The only method which needs to be static is the initial main() method. Anything and everything else is up to you as the programmer to decide what makes sense in your design.
static has nothing to do with public accessors (as you allude to), and it has nothing to do with the technical operation being performed. It has everything to do with the semantics of the operation and the class which holds it.
An instance (non-static) method exists on a particular instance of a class. Semantically it should perform operations related to that specific instance. A static method exists on a class in general and is more conceptual. It doesn't do anything to a particular instance (unless it's provided an instance of something as a method argument of course).
So you really just need to ask yourself about the semantics of the operation. Should you need new instance of an object to perform an operation? Or should the operation be available without an instance? That depends on the operation, on what the objects represent, etc.
If it is not static, then any other class that wants to use this method must first create an instance of this object.
From some other class:
Average.average(new ArrayList<Double>()); // legal only if static
new Average().average(new ArrayList<Double>()); // necessary if not static
// and only makes sense if Average can be instantiated in the first place
It's legal to make it an instance (i.e. not static) variable, but the method is actually harder to understand. If it is static then whoever reads the code knows it does not use any member variables of the class.
// In the class body
int x = 0; // member variable
public static double average() {
x = x + 1; // illegal
}
The less something can do, the easier to understand what it does do.
Static methods like the area, average are usually utility functions. You don't need any object to use an utility function. For example consider Math.pow you don't need to instantiate any object to use the power function, just use Math.pow(10.0, 2.0) to get (10.0)^2
In short :
Static method means class method, that is no instance of that object is needed to invoke.
whereas your average method is an instance method, you need an object to invoke that method.

creating arrays on-demand in java

I consider myself an intermediate Java programmer having been at it for a year and a half and having some experience in other languages. However I have run into an issue that I feel I need an experts help on.
As I understand it arrays when created by java exist somewhat outside of where they were created i.e. if you create an array called s in one class and another called s in a second class then try to use both those classes as part of a program you will run into problems with them overwriting each other.
However this brings me to an interesting dilemma. What if one wanted to create a unique array on-demand for an infinite number of sets of user input. i.e. is it possible to have the user enter a string value for use as the array name or have a generic value that then gets a number or letter appended to it. This is more a theoretical issue (there being other ways to accomplish the same thing) but any insight would be greatly appreciated.
i.e. is it possible to have the user enter a string value for use as
the array name or have a generic value that then gets a number or
letter appended to it.
The user should not need to care about your array names. The name of an array should neither be visible to the user, nor should it affect your application in any way.
If you want to allow the user to create collections of elements that he can store under a FriendlyName you could use a (Hash)map for that:
Map<String, Integer[]> userDefinedArrays = new HashMap<>();
userDefinedArrays.put("NameTheUserSelectsForThisArray", new Integer[]{1,2,3});
The "Key" of this map will be the FriendlyName provided by the user - he still does not know, that the actual map is called userDefinedArrays - or even someMapThatHoldsSomeThingsTheUserWantToUse.
The name of a actual variable needs to be set during designtime and is fixed (at least in java)
if you create an array called s in one class and another called s in a second class then try to use both those classes as part of a program you will run into problems with them overwriting each other.
No! Each Variable declared exists inside it's own scope! You can change the value of an array inside it's scope, and also reuse the same name inside different scopes - it doesn't matter. If you try to redeclare a variable already existing withing the current scope your compiler will warn you! - you simple can not do that.
Example:
class MyApplication{
public static void Main(String[] args){
Integer[] arr1;
Integer[] arr1; //Compiler error!
}
}
but:
class MyApplication{
public static void Main(String[] args){
Integer[] arr1;
Integer[] arr2;
}
}
or
class MyApplication{
public static void Main(String[] args){
foo();
bar();
}
public static void foo(){
Integer[] arr1;
}
public static void bar(){
Integer[] arr1;
}
}
is fine. arr1 just exists within the scope of either foo() or bar().
As I understand it arrays when created by java exist somewhat outside of where they were created i.e. if you create an array called s in one class and another called s in a second class then try to use both those classes as part of a program you will run into problems with them overwriting each other.
I think maybe you are misunderstanding. This will not happen unless you do it intentionally like yshavit points out in your comments. A member of a class named S in the class Cat, will not point to a member named S in the Dog class. You would have to go out of your way to do this.
In short, this will not happen by accident most of the time if you are instantiating your classes without passing references between them when you do.
What if one wanted to create a unique array on-demand for an infinite number of sets of user input.
You may want to use an ArrayList
ArrayList<String[]> myList = new ArrayList<String[]>();
Or a hashmap
Map<Integer,String[]> myMap = new HashMap<Integer,String[]>();
Which one you use depends on what you are using it for. If you need faster access to arbitrary elements use a map. If you plan to access them iteratively, an ArrayList will work fine.
is it possible to have the user enter a string value for use as the array name or have a generic value that then gets a number or letter appended to it. This is more a theoretical issue (there being other ways to accomplish the same thing) but any insight would be greatly appreciated.
In this case you want to use the hashmap solution, You can choose the key type of a map in java quite easily.
You will want to read this
http://docs.oracle.com/javase/6/docs/api/java/util/Map.html
or this, to get started.
http://docs.oracle.com/javase/6/docs/api/java/util/ArrayList.html
Two different class you're talking about is ClassOne & ClassTwo in my example. As you told, there is some kind of conflict while keeping the field name same. I've used arr for both classes. The reason to make MyArray super class is just code reuse. Why I used abstract MyArray class & why I used public static field isn't our matter of discussion. In TestApp, I've used arr of both classes ClassOne & ClassTwo without any problem.is it possible to have the user enter a string value for use as the array nameIMHO it may be possible using Reflection API or Dynamically Typed Language can do it. I'm not much sure about that.
class ClassOne extends MyArray {
public static int[] arr = new int[5];
}
class ClassTwo extends MyArray {
public static int[] arr = new int[5];
}
abstract class MyArray {
public static void setValue(int arr[], int index, int value) {
arr[index] = value;
}
public static void printArray(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
public class TestApp {
public static void main(String[] args) {
ClassOne.setValue(ClassOne.arr, 1, 30);
ClassTwo.setValue(ClassTwo.arr, 1, 50);
ClassOne.printArray(ClassOne.arr);
ClassOne.printArray(ClassTwo.arr);
ClassTwo.printArray(ClassOne.arr);
ClassTwo.printArray(ClassTwo.arr);
}
}

Using XML-derived Variables in the Main Method

so I am making a game where the player's skill damage is determined by their Skill Level and their weapon Mastery. The two values are stored in an XML document, and I am using DOM to retrieve the values, and am trying to print their sum to the console.
public class Damage {
public String skillName = "Bash"; //name of the skill
Xml config = new Xml("C:/character.xml","config");//part of the XML retrieving
Xml version = config.child("Character");//another part of the XML retrieving
int mastery = version.integer("Mastery"); //mastery of the skill
int skillLevel = version.integer("skillName");//skill level
int skillDamage = mastery + skillLevel; //adding the two values together
public static void main(String[] args) {
System.out.println(skillDamage);
}
}
When I run this code, it tells me that I can't have non-static variables in the static Main method. However, when I place the static tag before the int on the variables, it results in 0.
My question is: How can I make the variables static but still produce the sum of the two XML values? Could I somehow collect the non-static data from the XML, make it static, and then use that?
Try
System.out.println(new Damage().skillDamage);
Because you need a instance for non-static class-variables
You need to create an instance of your Damage class first, if you want to use its non-static variables/members. Put your main method like this:
public static void main(String[] args) {
Damage dmg = new Damage();
System.out.println(dmg.skillDamage);
}
I don't think you want the variables to be static.
1) Make skillDamage a public int
2) Then, just create your object in your main method:
Damage d = new Damage();
System.out.println(d.skillDamage);
It would probably be best to encapsulate skillDamage in a method, something like
public int getSkillDamage(){...}
Imagine that you have class cow. You can create instances of that class, for example berta and milka . That would mean, that you have two cows and their behaviour is based on class cow.
If you define something static it means, it is static to its class, therefore you can not define specific actions for each cow.
You should have a new class, for example "GameEngine", you should have all what you need there and you should create it with something like : GameEngine ge = new GameEngine(); and then use methods like ge.readXML();

What are some best practices and tricks when passing values from a main() to an Array Stack in a different class?

I am trying to pass values from my private static void main(...) into a class that has an array stack initialized in the constructor. I was wondering how to take the values I assign to a variable in the main() and push that value onto the array stack within this innerClass?
I know that the array stack works, I have implemented this class before without a problem, but I was only using the arrayStack() I had created and a main(). The addition of the third class is confusing me.
Without getting too deep in my code, I was hopping someone could explain (or point me to some resources) to me how to pass arguments to a stack that is initialized in a constructor, with arguments from the main() method of a different class (same package)?
Example of where I'm trying to get values to:
package program2;
public class Exec {
public Exec(DStack ds) {
/*I have initilized an arrayStack to hold doubles (i.e. DStack).
* I can use ds.push()/pop()/top() etc.
* I cannot take the value from Calculator.java and push that value
* here, which is what I need help understanding?
* */
ds.push(Calculator.i); //I would expect an error here, or the value stored in
//Calculator.i to be added to the stack. Instead program
//terminates.
}
}
Where I would like to take the values from:
package program2;
public class Calculator {
public static double i;
public static void main(String[] args) {
i=9; //I'm expecting that by using Calculator.i in the Exec class that
//I should be able to push 'i' onto the stack.
}
}
This question goes along with a question and answer I was able to get working yesterday here: Get answer from user input and pass to another class. There are three differences, one, I am no longer selecting an answer from the menu and performing an action. Two, I would like know how to get items on a stack versus comparing the String in a series of if/else statements. Lastly, I would like to know a little more detail about the nuts and bolts of this action.
You seem to completely misunderstand how an application works. When you launch your program, java executes your main method. All its instructions are executed in sequence until the end of the method is reached. If you haven't started any other thread from this method, when the last instruction in the main method has been executed, the program terminates.
In this case, the main method contains only one instruction:
i = 9;
So this instruction is executed, and since it's the last one, the program terminates. You don't even reference the Exec class anywhere, so this class isn't even loaded by the JVM.
If you want to use the Exec class, then you have to do something with is somewhere in the program. For example, you could do
i = 9;
DStack dstack = new DStack();
Exec exec = new Exec(dstack);
Note that storing something in a public static variable in order for some other object to be able to get this value is a very poor form of parameter passing. If an Exec object needs a value to work, then it should be an argument of its constructor:
public Exec(DStack ds, double value) {
ds.push(value);
}
and in the main method, you would use a local variable and not a public static variable:
double i = 9;
DStack dstack = new DStack();
Exec exec = new Exec(dstack, i);
If I understand your question correctly, you should create an instance of the Exec class. You can also create an instance of DStack within your program and pass it the Exec constructor after pushing the double value onto the stack.
package program2;
public class Calculator {
public static double i;
public static void main(String[] args) {
DStack dStack = new DStack();
dStrack.push(i);
Exec exec = new Exec(dStack);
}
}
I think you are confusing the concept of class vs. instance. You don't pass values to classes, you pass values to instances (static fields are sometimes called class variables and can make things confusing, but ignore that for now).
In a nutshell, a class is the code for that class you wrote. An instance is the actual thing that was spawned from that definition of class and actually does stuff. So the number one trick is to "instanciate" your class and create an instance. Then you pass whatever values you want to pass it like below:
class Foo {
public static main(String[] args) {
Bar bar = new Bar(); // <-- now you have an instance called bar
bar.arrayStack.push(args[0]); // <-- Now it's passed!
}
class Bar {
ArrayStack arrayStack;
Bar(){
arrayStack = new ArrayStack();
}
}

How can I get the Class object in a static method without using the class name?

I have
public class A {
static X s_x = new X(A.class);
}
and
public class B {
static X s_x = new X(B.class);
}
and so on for many classes without any special relationship or commonality. What I really wish I could do is have s_x initialized in a superclass, but with descendant-class-specific code; this is impossible since static code is not overridable. So, I want to at least make my copy-paste easier. I want a magic expression which evaluates to the Class object, i.e. to write:
static X s_x = new X(/* magic expression here */);
where the magic expression is the same regardless of the class in which I declare my X in, but does the same as the examples above. Second-best option would be a static method to the same effect.
Notes:
Java 6 if possible.
This question is not (necessarily) about logging...
I also had this strange requirement once and I tried to search but did not find anything, so I guess the answer is it's not possible may be.
But I was told to rethink my approach and when I tried I figure out the same solution without this strange requirement. So please rethink your approach. I'm sure you'll be able to solve it like me. Also, if you can post the problem/scenario you are trying to solve,may be I can help.
In the HotSpot/OpenJDK you can use
Class c = Reflection.getCallerClass(1)
Note: this is an internal API and might not work on all JVMs.
In Java 7 you can use the class java.lang.invoke.MethodHandles for this:
Class c = MethodHandle.lookup().lookupClass()
You will probably get a warning about using a raw type instead of the parameterized version Class<X> but I can't see how you can avoid that without reverting to hard-coding the class name yourself.
Here's a one-liner that should work in Java 5+ JVM and doesn't add any additional imports to your code:
new Object(){}.getClass().getEnclosingClass()
It creates an anonymous inner class, gets its Class object, then gets its enclosing class instance, which should be your class. For example:
public class HelloClass {
static final Class<?> THIS_CLASS = new Object(){}.getClass().getEnclosingClass();
public static void main(String[] args) {
System.out.println(THIS_CLASS); // prints "class HelloClass"
}
}
In the context of your question:
static X s_x = new X(new Object(){}.getClass().getEnclosingClass());
I think the only solution is to extract the class name from the current stack-trace (see Thread.getStackTrace()), which will give it to you as a String, from which you can get a Class object using Class.forName(String), but that's much uglier than your current approach.
You can do this but some re-factoring in your approach is needed:
Try this out:
class X
{
public X(String cName)
{
try
{
Class.forName(cName);
}catch(ClassNotFoundException cne)
{}
}
}
public class Test
{
static X x1 = new X(Thread.currentThread().getStackTrace()[1].getClassName());
}
In case you want to create a logging object, you can use lombok to inject a logging object for you.
Example from the page:
#Log
public class LogExample {
public static void main(String... args) {
log.error("Something's wrong here");
}
}
Some of the answers here have the idea for a solution, but not quite the code snippet I need. So here it is, working on any JVM:
static X s_x = new X(getClassStatic());
public static Class<?> getClassStatic() {
try {
// we're using the third highest stack element, since the
// first highest is the getStackTrace() method, followed by this method itself. We
// want the calling code's class.
String name = Thread.currentThread().getStackTrace()[2].getClassName();
return Class.forName(name);
} catch (ClassNotFoundException e) {
// shouldn't be able to get here...
return null;
}
}
or, for selected JVMs, as per Peter Lawrey's suggestion:
static X s_x = new X(getCallerClass(1));

Categories