My first question on stackoverflow:
Ok so I am writing a java game for android and I am having trouble with initializing certain classes retrieved from a function/method. Here is my code:
static int unUsedCharacters = 10;
static Character char1;
static Character char2;
static Character char3;
static Character char4;
static Character char5;
static Character char6;
static Character char7;
static Character char8;
static Character char9;
static Character char10;
Character getFreeCharacter() {
if (char1 == new Character()) {
return char1;
} else if (char2 == new Character()) {
return char2;
// and so on... until 10
} else {
return char10;
}
}
public void createCharacter(String x) {
if (unUsedCharacters > 0) {
unUsedCharacters -= 1;
getFreeCharacter() = new Warrior();
//the warrior class extends the character class
} else {
/* no more characters */
}
}
So The problem is where I try to do:
getFreeCharacter() = new Warrior();
It says:
Variable expected.
Any suggestions?
(It is probarly super easy, but this is all new to me)
Thank you for reading/responding
An expression of this form...
(char1 == new Character())
... will always evaluate to false (or throw an exception). The new operator never produces a null result, and it never produces a reference to an object that existed before, but those alternatives cover all the possible values of char1 at any time. More likely you want something like this:
if (char1 == null) {
char1 = new Character();
return char1;
}
In truth, though, I would never hold the ten characters in ten independent variables. I'd probably use a List of Characters, or at worst an array.
Having gotten past that, you have a different problem. The Character you return is already an object assigned to the intended slot. You can set its properties (to the extent that its class allows you to do so), but you cannot replace it with a different object by assigning to it. Indeed, you cannot assign directly to the method result at all, but even if you stored it in a variable, assigning a different object to that variable would not have the effect you want.
(Note, by the way, that I am distinguishing between assigning to members of the method return value, which you can do, and assigning to the value itself, which you cannot do.)
I think you would be best off getting rid of getFreeCharacter() altogether. If you structure your class better then you won't need it. Instead of declaring char1 ... char10 like so:
// Yuck, don't do this
Character char1;
Character char2;
// ...
Character char1;
... do as I suggested earlier and use a List:
import java.util.ArrayList;
import java.util.List;
public MyGame {
List<Character> characters = new ArrayList<>();
// ...
}
Then, your createCharacter() method can have this form:
public void createCharacter(String x) {
if (characters.size() < 10) {
characters.add(new Warrior());
} else {
/* no more characters */
}
}
Elsewhere, you can retrieve elements of the character list via its get() method, e.g. characters.get(0). The List instance takes care of a whole lot of details that you will otherwise have to write your own code for.
Related
This is a simple question:
Is it possible to have an enum with a variable value ?
To be clear i would like to create an enum corresponding to an error code returned by a function which is two bytes, so i would like to do something like
public enum ErrorCode {
ERR_NONE ((byte)0x9000), // No error
ERR_PARAM ((byte)0x8200), // Parameter error
ERR_DATA ((byte)0x83XX), // XX could be any value
}
how to return ERR_DATA for all values beginning by 0x83 ?
Is it possible ?
Thanks
Here's an implementation following Dawood ibn Kareem's suggestion in comments above.
Some points:
This implementation throws an exception if a code matches two enum values. You would need to decide whether you wanted that behaviour, or just return the first match. In that case the ordering of the enum values becomes significant.
You can add new constructors for common cases, e.g. I have one for a value which matches a single code. You could add one for a value which matches a range of codes.
You might also want to throw an exception if no ErrorCode matches the integer code. This implementation returns null in that case, so you'll get an NPE if the caller doesn't check for null, but you won't know what value triggered it.
import java.util.function.Predicate;
public enum ErrorCode {
ERR_NONE (0x9000), // No error
ERR_PARAM (0x8200), // Parameter error
ERR_DATA (n -> (n >= 0x8300 && n <= 0x83FF)), // 0x83XX
ERR_ANOTHER_83 (0x8377);
private final Predicate<Integer> forValue;
ErrorCode(Predicate<Integer> matches) {
this.forValue = matches;
}
ErrorCode(int singleValue) {
this(n -> n == singleValue);
}
public static ErrorCode forInt(int code) {
ErrorCode matchingCode = null;
for (ErrorCode c : ErrorCode.values()) {
if (c.forValue.test(code)) {
if (matchingCode != null) {
throw new RuntimeException("ErrorCodes " + matchingCode.name()
+ " and " + c.name() + " both match 0x"
+ Integer.toHexString(code));
} else {
matchingCode = c;
}
}
}
return matchingCode;
}
public static void main(String[] args) {
System.out.println(ErrorCode.forInt(0x8312));
System.out.println(ErrorCode.forInt(0x9000));
System.out.println(ErrorCode.forInt(0x8377));
}
}
Write a method which, given 0x83NN as input, returns ERR_DATA. Done.
ErrorCode errorCode(int n) {
if (n == 0x9000)
return ERR_NONE;
else if (n == 0x8200)
return ERR_PARAM;
else if (n >= 0x8300 && n <= 0x83ff)
return ERR_DATA;
else
throw new IllegalArgumentException();
}
You have to write code to look up the value in any case. There's no intrinsic 'associate this integer value with this enum constant, and provide a lookup for enum constant given an integer value'.
Note that, for this, there's no need to store the numeric value inside each member of the enum. And also note that your constructor calls like ERR_NONE(0x9000) are not valid unless you've defined a suitable constructor. And if you do define a suitable constructor, you'll need to decide on a single value for the argument of ERR_DATA.
I believe it cannot be the case. According to Oracle Doc,
An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it.
Popular problem: print all combinations of input.
Both the first code block and 2nd code block have the same structures. I did debug and track stack, but couldn't understand. That's why I'm posting.
If input is List, the following code works and I understand it.
remain should be backtracked.
ex: input list = ["a", "b", "c"]
public void sublists(List<String> list) {
List<String> chosen = new ArrayList<>();
sublists(chosen, list);
}
private void sublists(List<String> chosen, List<String> remain) {
if(remain.size() == 0) {
System.out.println(chosen);
}
else {
String first = remain.remove(0);
// choose/explore INC. first
chosen.add(first);
sublists(chosen, remain);
// choose/explore EXC first
chosen.remove(chosen.size() -1);
sublists(chosen, remain);
// un-choose for backtracking
remain.add(first);
}
}
However, the same question but different input type, when input is String, doesn't need backtracking of remain in the code below.
Q1: why remain += C; is not reachable in code block below while remain.add(first); is reachable in the code block above even though these two code blocks have the same code structure? In both code block, recursion method get called recursively.
Q2: remain += C; not even needed since it's automatically backed its removed char. Why?
// ex: input s = "abc"
public void combination2(String s) {
combination2Helper("", s);
}
private void combination2Helper(String chosen, String remain) {
if (remain.length() == 0) {
System.out.println(chosen);
}
else {
char C = remain.charAt(0);
chosen += C;
remain = remain.substring(1);
// inc. C + remain w/o C
combination2Helper(chosen, remain);
// exc. C + remain w/o C
chosen = chosen.substring(0, chosen.length() -1 );
combination2Helper(chosen, remain);
// why this backtrack of ramin is not reachable unlike when remain is list
// backtrackig this line is not needed.
remain += C;
}
Besides if the input is string, we don't even need such a long line of code right above.
The following code is working.
Q3: Theoretically we need to backtrack what we've chosen after the recursion call for exhaustive search but why this code doesn't need backtracking of chosen nor remain when the input type is String?
When the input is List, if don't use backtracking, it doesn't work.
I'm confused why the backtracking is not reachable ( not needed ) when input is String while List is needed.
private void combination2Helper(String chosen, String remain) {
if (remain.length() == 0) {
System.out.println(chosen);
}
else {
combination2Helper(chosen, remain.substring(1));
combination2Helper(chosen+remain.charAt(0), remain.substring(1));
}
}
In the list version, you do not need to add C again to the list remain if you copy the list first:
remain = new ArrayList<>(remain);
String first = remain.remove(0);
In the string version, the statement remain += C; will be reached, but it has no real effect, because the value will never be used again. So it can be removed by optimization. The situation is similar to copying the list in the list version. Look at these statements:
char C = remain.charAt(0);
chosen += C;
remain = remain.substring(1);
remain is an argument of the method. This will be assigned with the actual parameter, when the method is called. remain then behaves like a local variable of the method. When a new value is assigned to it inside the method, this will not change the variable passed by the caller (the reference to the string is passed by value).
In my Java program's constructor I have the following:
thirdRow.add(button);
button.setActionCommand("Sumbit");
button.addActionListener(this);
And here is the corresponding actionPerformed method that's supposed to take 3 values from some textfields and store them into arrays:
public void actionPerformed(ActionEvent e)
{
String arg = e.getActionCommand();
if (arg == "Submit")
{
//enlarge arrays
qtyStr = enlargeArray(qtyStr);
typeStr = enlargeArray(typeStr);
colorStr = enlargeArray(colorStr);
//add from textfields into current
qtyStr[qtyStr.length-1] = qty.getText();
typeStr[typeStr.length-1] = type.getText();
colorStr[colorStr.length-1] = color.getText();
}
}
//method to enlarge an array by 1
public String[] enlargeArray(String[] currentArray)
{
String[] newArray = new String[currentArray.length + 1];
for (int i = 0; i<currentArray.length; i++)
newArray[i] = currentArray[i];
return newArray;
}
When I run the application, populate the textfields, and click the submit button nothing happens. How can I verify that my string arrays are being appended like they're supposed to?
You've a problem here: if (arg == "Submit")
Don't compare Strings using ==. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two objects are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of
if (fu == "bar") {
// do something
}
do,
if ("bar".equals(fu)) {
// do something
}
or,
if ("bar".equalsIgnoreCase(fu)) {
// do something
}
Also, for safety's sake, I try to use String constants wherever possible so as not to be tripped up by misspellings.
If you want to do your code this way, I would probably do two things:
1) maintain index fields for each array for the next free index, and
2) I wouldn't recommend resizing your array by 1 each time, as our current code is running through the array 2 n times (n = array length), 1st to initialize the array, and 2nd to create a new array.
Two options to optimize thisL one would be be to look into the Arrays class. it contains methods such as Array.copyOf() that can perhaps be useful here. You could also check if the array is full, and if it is then resize it by a number greater than one to reduce extra work.
For instance:
import java.util.Arrays;
class Test{
private String[] a;
private int next;
public Test(int size){
a = new String[size];
next = 0;
}
public void add(String s){
if(next == a.length){
Arrays.copyOf(a, a.length+1);
}
a[next] = s;
next++;
}
}
The easiest way would be to use an ArrayList (or any class that implements the java.util.List interface), as previously mentioned by Jon Skeet - it will do all the work for you.
I am implementing a form of leftist min heap, which stores arbitrary words by length. So, I have written a wrapper class for Scanner, and changed the compareTo, like so
public class ScannerWrapper implements Comparable<String>
//a Scanner, sc and a String, current
public int compareTo(String str){
if(current.length() > str.length()) return -1;
if(current.length() > str.length()) return 1;
else return 0;
}
where current = sc.next() and is not the \n character.
in this case, if I have ScannerWrapper.next() > foo , where foo is an arbitrary string of length > ScannerWrapper.next();
will it use the compareTo(String) that I have written, returning false, or will it do some other random thing?
After reading your question several times I think I understand what you're asking now. If you're trying to compare two instances of class ScannerWrapper with the comparison operators, then no, it's not going to work.
You can't overload operators in Java (you can in C++), therefore in order to compare instances of ScannerWrapper with each other you're going to have to call the compareTo() method.
Also, both of your if statement conditions are the same, so you might want to fix that up.
It's difficult to understand your question - so you might consider rephrasing it. Here's a shot in the dark :
public class ScannerWrapper implements Comparable<ScannerWrapper>
//your wrapper has a handle to the scanned data. Presumably it's
//initialized on construction, which is omitted here
private final String scannedData;
public String getScannedData() {
return this.scannedData;
}
public int compareTo(ScannerWrapper other) {
//if this scannedData is longer than the other, return 1
if(this.str.length() > other.getStr().length()) {
return 1;
} else if(this.scannedData.length() < other.getScannedData().length()) {
//if the other scannedData is longer return -1
return -1;
}
//if they are equal return 0
return 0;
}
}
In the expression of a while loop, is it possible to initialise a variable, then use that as part of the expression?
It's probably simpler in code:
while (int a = someMethod(), a<b)
It would be possible to just add another method, and so have to following:
private boolean whileLoopTest() {
int a = someMethod();
return a<b;
}
public void originalMethod() {
while (whileLoopTest()) {
//...
but this doesn't seem as neat.
EDIT
I also don't want to directly compare the method to my variable, as it is compared to several variable, and so if would be a long, unreadable mess. A better example of what I want would be:
while (int a = SomeClass.someStaticMethod(), -1<a && a<b)
It's not true in my case, but this would be a equally valid question if someStaticMethod() took a long time to return - I would only want to call it once.
I'm fairly new to StackOverflow, so I'm not sure if giving other situations where this would apply is what I should be doing.
int a;
while((a = someMethod()) < b){
//do something
}
A common use for this is reading from a file:
BufferedReader fileIn = ...
String line;
while((line = fileIn.readLine()) != null){
//do something
}
fileIn.close();
/edit
You can do this for your new scenario:
int a;
while(-1 < (a = SomeClass.staticMethod()) && a < b) {
//do something
}
Once the left hand portion of the && statement is executed, the return value of SomeClass.staticMethod() is stored in a, which carries over the the right hand portion of the statement.
Why not just not assign the value to "a" if you are not using it anyways?
while (someMethod() < b) { doSomething() }
If you actually do need "a" then your alternate solution would not work. The solution then would be either to save it (which I do not consider unneat) or what Kerrek said.
You can use the function directly without using a local variable like this:
while ( someMethod() < b) { /* ... */}
This, if your method returns intended value. (If you are casting it to a local variable, it's supposed to)
EDIT: For your second question.
Your concern is understandable, but if you are assigning that methods value to a local variable inside while loop's boolean expression, in every loop where "While" checks the expression, you are assigning methods' return value to local variable, which means you are calling that method in every iteration. That doesn't change anything from my first answer.