I have a string (breakmsg) that I would like to be the same for every if statement, with an integer value that needs to change depending on what it is declared as inside the if statement. How would I go about changing the value of the value variable after I have already declared the breakmsg string? Previous attempts are commented inside the code.
Here is my current code:
private int value;
public void setValue(int v){
value = v;
}
#EventHandler
public void onBlockBreak(BlockBreakEvent e) {
Block b = e.getBlock();
Player p = e.getPlayer();
//int value = 0;
String breakmsg = ChatColor.GREEN + "You gained " + ChatColor.GOLD + value + ChatColor.GREEN + " points for collecting " + ChatColor.AQUA + b.getType() + ChatColor.GREEN + ".";
#SuppressWarnings("deprecation")
int itemID = p.getItemInHand().getTypeId();
if (b.getType() == Material.DIAMOND_ORE) {
if (itemID == 257 || itemID == 278) {
//value = 5;
setValue(5);
int points = getConfig().getInt("players." + p.getUniqueId() + ".points");
getConfig().set("players." + p.getUniqueId() + ".points", points + value);
saveConfig();
startScoreboard();
e.getPlayer().sendMessage(breakmsg);
}
}
if (b.getType() == Material.GOLD_ORE) {
if (itemID == 257 || itemID == 285 || itemID == 278) {
//value = 3;
setValue(3);
int points = getConfig().getInt("players." + p.getUniqueId() + ".points");
getConfig().set("players." + p.getUniqueId() + ".points", points + value);
saveConfig();
startScoreboard();
e.getPlayer().sendMessage(breakmsg);
}
}
}
You could wrap that logic in a private function.
private String generateBreakMsgFrom(Block block, int value) {
return ...
}
Then within the if statements rather than setting value you can do:
breakmsg = generateBreakMsgFrom(b, 5);
Please note that you could and should probably also simply set the message after the if statements, but still you want to extract the message generation logic into a private function.
I would really recommend you to read Clean Code. Your function is very long, it is doing multiple things, it has a lot of magic numbers and quite a lot of code duplication...
EDIT: Since you declared int value in your function I haven't realized that it was an instance variable, therefore.
private String generateBreakMsgForBlock(Block block) {
return ... //you can use value from here once properly set
}
Related
As you can see that I am trying to increment the variable 'c' when the accelerometer z-axis value greater than 12. But I can do it at one time, it will change the value 0 to 1 after executing the program. But I want to collect how many times the z-axis value becomes more than 12.
#Override
public void onSensorChanged (SensorEvent event) {
textView.setText(event.values[0] + "");
textView1.setText(event.values[1] + "");
textView2.setText(event.values[2] + "");
String s = new String();
s = textView2.getText().toString().trim();
Float t = Float.parseFloat(s);
int c = 0;
if (t > 11) {
c++;
txt.setText(Integer.toString(c));
}
}
int counter = 0;
#Override
public void onSensorChanged (SensorEvent event) {
textView.setText(event.values[0] + "");
textView1.setText(event.values[1] + "");
textView2.setText(event.values[2] + "");
String s = new String();
s = textView2.getText().toString().trim();
Float t = Float.parseFloat(s);
int c = 0; // ???
if (t > 11) {
c++;
counter++;
txt.setText(Integer.toString(c));
System.out.println("I need to learn how to use global
variables.\n
also the thing has been greater than \"12\"
"+counter" times."
);
}
}
Also maybe using more meaningful variable names other than "textView#" would make it less of a pain for people to figure out what you're trying to do.
You can define the variable c as a field member like below:
public class MainActivity {
private int c = 0;
(...)
#Override
public void onSensorChanged (SensorEvent event) {
textView.setText(event.values[0] + "");
textView1.setText(event.values[1] + "");
textView2.setText(event.values[2] + "");
String s = new String();
s = textView2.getText().toString().trim();
Float t = Float.parseFloat(s);
if (t > 11) {
c++;
txt.setText(Integer.toString(c));
}
}
}
We have a program that compares thousands of pairs of Students by checking each field of the Student and counting the diffs:
class Student{
String name;
String address;
String biologyCourse;
.....
// about 100 other fields
}
And the counter POJO class:
class Counters{
long bothStudentsHaveName;
long onlyLeftHasName;
long onlyRightHasName;
......
// number of fields in Student * 3 (both, only left, only right)
}
Our compare function accepts 2 students plus the counters object and needs to scan the fields and update the relevant counters:
public void compareStudents(Student left, Student right, Counters counters){
if (!StringUtils.isEmpty(left.name) && !StringUtils.isEmpty(right.name) ){
counters.bothStudentsHaveName++;
} else if (StringUtils.isEmpty(left.name) && !StringUtils.isEmpty(right.name)){
counters.onlyRightHasName++;
} else if (!StringUtils.isEmpty(left.name) && StringUtils.isEmpty(right.name))){
counters.onlyLeftHasName++;
}
/// and now??
}
At this point, we can add 100s more triplets of if/else like the above - but we believe there should be a much easier way to do that.
Reflection can be an option or maybe X dimensions arrays, but can we somehow write the code so the comparison and counting will be much more generic?
I have solved your problem with one single loop. But here I'm assuming that naming convention for all the fields will be the same as described in your question. Here I am dynamically accessing the Student fields and updating Counter fields accordingly. Here is the complete solution:
Solution Class:
public class Solution {
public void compareStudents(Student left, Student right, Counter counter) throws Exception {
for (Field field : Student.class.getDeclaredFields()) {
Object leftValue = field.get(left);
Object rightValue = field.get(right);
String fieldName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
if(leftValue != null && rightValue != null) {
Field counterField = Counter.class.getDeclaredField("bothStudentsHave" + fieldName);
counterField.set(counter, (long) counterField.get(counter) + 1);
} else if (leftValue != null) {
Field counterField = Counter.class.getDeclaredField("onlyLeftHas" + fieldName);
counterField.set(counter, (long) counterField.get(counter) + 1);
} else if (rightValue != null) {
Field counterField = Counter.class.getDeclaredField("onlyRightHas" + fieldName);
counterField.set(counter, (long) counterField.get(counter) + 1);
}
}
}
}
Student Class:
class Student {
String name;
String address;
String biologyCourse;
}
Counter Class:
class Counter {
// name
long bothStudentsHaveName;
long onlyLeftHasName;
long onlyRightHasName;
// address
long bothStudentsHaveAddress;
long onlyLeftHasAddress;
long onlyRightHasAddress;
// biologyCourse
long bothStudentsHaveBiologyCourse;
long onlyLeftHasBiologyCourse;
long onlyRightHasBiologyCourse;
// ... and so on
#Override
public String toString() {
return "Counter{" + "\n" +
"\tbothStudentsHaveName = " + bothStudentsHaveName + "\n" +
"\t, onlyLeftHasName = " + onlyLeftHasName + "\n" +
"\t, onlyRightHasName = " + onlyRightHasName + "\n" +
"\t, bothStudentsHaveAddress = " + bothStudentsHaveAddress + "\n" +
"\t, onlyLeftHasAddress = " + onlyLeftHasAddress + "\n" +
"\t, onlyRightHasAddress = " + onlyRightHasAddress + "\n" +
"\t, bothStudentsHaveBiologyCourse = " + bothStudentsHaveBiologyCourse + "\n" +
"\t, onlyLeftHasBiologyCourse = " + onlyLeftHasBiologyCourse + "\n" +
"\t, onlyRightHasBiologyCourse = " + onlyRightHasBiologyCourse + "\n" +
'}';
}
}
Tester Class:
public class Tester {
public static void main(String[] args) throws Exception {
// Creating Dummy Variables
Student student1 = new Student();
student1.name = "Test";
student1.biologyCourse = "Yes";
Student student2 = new Student();
student2.name = "Test1";
student2.address = "abc street";
Counter counter = new Counter();
// Comparing Students
Solution solution = new Solution();
solution.compareStudents(student1, student2, counter);
// Printing Counter
System.out.println(counter);
}
}
Output:
Counter{
bothStudentsHaveName = 1
, onlyLeftHasName = 0
, onlyRightHasName = 0
, bothStudentsHaveAddress = 0
, onlyLeftHasAddress = 0
, onlyRightHasAddress = 1
, bothStudentsHaveBiologyCourse = 0
, onlyLeftHasBiologyCourse = 1
, onlyRightHasBiologyCourse = 0
}
If you keep repreating the same basic pattern of fields, then consider extracting that into a class. For example introduce a FieldComparison class that looks a little like this:
public class FieldComparisonCounter {
public int bothHave;
public int onlyLeftHas;
public int onlyRightHas;
// constructor, getters, setters left as an exercise for the reader
}
Then have a Map<String,FieldComparisonCounter> counters somewhere and a method like this:
public void compareField(String fieldName, String leftValue, String rightValue) {
FieldComparisonCounter counter = counters.get(fieldName);
if (counter == null) {
counter = new FieldComparisonCounter();
counters.put(fieldName, counter);
}
boolean leftHas = !StringUtils.isEmpty(leftValue);
boolean rightHas = !StringUtils.isEmpty(rightValue);
if (leftHas && rightHas) {
counter.bothHave++;
} else if (leftHas) {
counter.onlyLeftHas++;
} else if (rightHas) {
counter.onlyRightHas++;
}
}
Then adding a new field comparison is as simple as calling
compareField("name", left.name, right.name);
I've worked on the project in my school and stuck with an error. I cannot run this code since it has an error 'randA2 is already defined in method main(String[])' How can I fix it?
String [] A = {"Russia", "Saudi_Arabia", "Egypt", "Uruguay"};
int A1 = A.length;
int randA1 = (int)(Math.random()*A1);
int randA2 = (int)(Math.random()*A1);
int randA3 = (int)(Math.random()*A1);
int randA4 = (int)(Math.random()*A1);
while(randA1 == randA2) {
int randA2 = (int)(Math.random()*A1);
}
while(randA1 == randA3) {
int randA3 = (int)(Math.random()*A1);
}
while(randA2 == randA3) {
int randA3 = (int)(Math.random()*A1);
}
while(randA1 == randA4) {
int randA4 = (int)(Math.random()*A1);
}
while(randA2 == randA4) {
int randA4 = (int)(Math.random()*A1);
}
while(randA3 == randA4) {
int randA4 = (int)(Math.random()*A1);
}
String AnnounceA1 = A[randA1] +" " + "VS" + " " + A[randA2];
System.out.println(AnnounceA1);
String AnnounceA2 = A[randA3] +" " + "VS" + " " + A[randA4];
System.out.println(AnnounceA2);
I would like to use another way to solve your problem, all you need is :
String[] contries = {"Russia", "Saudi_Arabia", "Egypt", "Uruguay"};
Collections.shuffle(Arrays.asList(contries));
String announceA1 = contries[0] + " VS " + contries[1];
System.out.println(announceA1);
String announceA2 = contries[2] + " VS " + contries[3];
System.out.println(announceA2);
If you want to reassign a new value to a variable in Java, then you don't need to declare its type again. So your first while loop should look like this:
while (randA1 == randA2) {
randA2 = (int)(Math.random()*A1);
}
But besides this, your code has a logical problem, and it won't actually generate 4 unique random numbers. Actually, if you control which numbers you accept, they aren't really random. I would go with this version:
String[] teams = { "Russia", "Saudi_Arabia", "Egypt", "Uruguay" };
Set<Integer> rands = new HashSet<>();
while (rands.size() < teams.length) {
rands.add((int)(Math.random()*teams.length));
}
String AnnounceA1 = teams[rands[0]] +" " + "VS" + " " + teams[rands[1]];
System.out.println(AnnounceA1);
String AnnounceA2 = teams[rands[2]] +" " + "VS" + " " + teams[rands[3]];
System.out.println(AnnounceA2);
The strategy in my suggested version of your code is using a set to hold 4 random integers (which is the number of teams in your example). It is a property of sets that every entry has to be unique. So, if we iterate this set, adding random integers, we will eventually end up with 4 unique random integers. Then, we can use them to choose team names to display in your output message.
You redefine your vars inside the while loops.
Ommit the int declaration iside the while loops:
...
while(randA1 == randA2) {
randA2 = (int)(Math.random()*A1);
}
while(randA1 == randA3) {
randA3 = (int)(Math.random()*A1);
}
...
Java is a type safety language. This is different to for example JavaScript. Inside JavaScipt the JIT (Just in time compiler) would not complain, because it is allowed to redefine variables, event if the type is changing.
I have the following code for a conversion program:
private void convertButtonActionPerformed(java.awt.event.ActionEvent evt) {
int type, value;
double conversion;
String output;
type = Integer.parseInt(conversionchoiceInput.getText());
value = Integer.parseInt(valueInput.getText());
if (type == 1)
{
conversion = inchesToCentimetres(value);
output = value + " inches = " + Math.round(conversion) + " centimetres";
}
else if (type == 2)
{
}
else if (type == 3)
{
}
else if (type == 4)
{
}
outputLabel.setText(output);
}
It says "variable output might not have been initiaized" when I already have?
Thanks!
The problem is that output needs to be initialised no matter what execution path the program takes. It is only initialised in the if path. Therefore, you need to give it a default value at the start (of empty string or something) or set it in all branches.
String output = "";
or
if (type == 1)
{
conversion = inchesToCentimetres(value);
output = value + " inches = " + Math.round(conversion) + " centimetres";
}
else if (type == 2)
{
output = "";
}
else if (type == 3)
{
output = "";
}
else if (type == 4)
{
output = "";
}
Naturally, the first option is the best.
If type != 1, then output isn't initialized. And even if you give output a value in each of the if branches (1, 2, 3, 4) output might not have been initialized, as if type < 1 or > 4 it still has no value.
You have just declared the variable there which is different from initializing it.
I want to put State objects (which are HashMaps with Character as key and State as Value into an ArrayList named allStates. Should I override the equals and hashCode methods here? Why? How?
This code is for the Automaton and State classes I've built so far:
class State extends HashMap<Character, State>{
boolean isFinal;
boolean isInitial;
int stateId;
State () {
isInitial=false;
isFinal = false;
}
public boolean equals (Object o){
boolean isEqual = false;
State compare = (State)o;
if ((compare.stateId)==this.stateId)
{
return true;
}
return isEqual;
}
public int hashCode() {
int theHashCode = stateId%7;
return theHashCode;
}
}
class Automaton{
List <State> allStates;
//private List<State> finalStates;
int theInitialStateIntIndex;
State actualState;
char [] alphabet;
Automaton() {
allStates = new ArrayList<State>();
}
public void setAllStates (int numberOfStates) {
for (int i =0; i <numberOfStates; i++) {
State newState = new State();
newState.stateId = i;
allStates.add(newState);
}
}
public void setAlphabet (String alphabetLine){
alphabet = alphabetLine.toCharArray();
}
public void markFinalStates (String [] finalStates){
for (int index =0; index<finalStates.length; index++) {
int aFinalStateId = Integer.parseInt(finalStates[index]);
State aFinalState = allStates.get(aFinalStateId);
aFinalState.isFinal = true;
allStates.add(aFinalStateId, aFinalState);
/*DEBUG*/
aFinalState = allStates.get(aFinalStateId);
if ((aFinalState.isFinal)==true)
System.out.println("THE STATE " + aFinalStateId + " IS MARKED AS FINAL");
}
}
public void markInitialState (int initialStateId) {
State theInitialState = allStates.get(initialStateId);
theInitialState.isInitial=true;
allStates.add(initialStateId, theInitialState);
theInitialStateIntIndex = initialStateId;
/*DEBUG*/
System.out.println("THE INITIAL STATE ID IS " + initialStateId);
theInitialState = allStates.get(initialStateId);
if ((theInitialState.isInitial)==true)
System.out.println("THE STATE " + initialStateId + " IS MARKED AS INITIAL");
}
public void setTransitions(int stateId, String transitionsLine){
State theOneToChange = allStates.get(stateId);
String [] statesToReachStringSplitted = transitionsLine.split(" ");
for (int symbolIndex=0; symbolIndex<statesToReachStringSplitted.length;symbolIndex++){
int reachedState= Integer.parseInt(statesToReachStringSplitted[symbolIndex]);
theOneToChange.put(alphabet[symbolIndex],allStates.get(reachedState));
System.out.println("THE STATE " + stateId + " REACHES THE STATE " + reachedState + " WITH THE SYMBOL " + alphabet[symbolIndex]);
}
allStates.add(stateId, theOneToChange);
}
public int findInitialState(){
int index =0;
cycle: for (; index<allStates.size(); index++){
State s = allStates.get(index);
if (s.isInitial==true) {
break cycle;
}
} return index;
}
public void processString (String string)
{
StringBuilder stepString= new StringBuilder (string);
int actualStateIntIndex;
System.out.println("THE FOUND INITIAL ONE IS "+ theInitialStateIntIndex);
State firstState = allStates.get(theInitialStateIntIndex);
actualState = firstState;
while (stepString.length()>0){
Character characterToProcess = stepString.charAt(0);
stepString.deleteCharAt(0);
State nextState;
nextState = ((State)actualState.get(characterToProcess)); // pasa al siguiente State
actualState = nextState;
actualStateIntIndex=allStates.indexOf(actualState);
System.out.println("the actual state for " + stepString + " is " + actualStateIntIndex);
if ((actualState.isFinal==true) && (stepString.length()==0))
{
System.out.println("THE STRING " + string + " IS ACCEPTED AT STATE " + actualStateIntIndex );
}
else if (stepString.length()==0 && (actualState.isFinal==false)){
System.out.println("THE STRING " + string + " IS REJECTED AT STATE " + actualStateIntIndex);
}
}
}
}
If the automaton is a DFA, then one can use the Accessing String to ID the field.
An accessing String is any string that could be used to reach the state from the start state. One will have to build the string while building the DFA, however, it won't add more time complexity. (Yes, one then needs to hashcode/equal the string)
Or actually, ID the states by an increasing serial number/string should work for all automaton. Then hashcode/equal based on the ID.
Go for the 2nd one, easier and works better than 1, unless you want to take care of the duplicated states.
Yes, you need the hashcode and equals for a user defined type to work with hash.