I have a list of longitude and longitude points in an xml file that is used throughout my application. I find my self repeating this code to get points often and think there must be a better way?
String[] mTempArray = getResources().getStringArray(R.array.stations);
int len = mTempArray.length;
mStationArray = new ArrayList<Station>();
for(int i = 0; i < len; i++){
Station s = new Station();
String[] fields = mTempArray[i].split("[\t ]");
s.setValuesFromArray(fields);
Log.i("ADD STATION", ""+s);
mStationArray.add(s);
}
XML is in the format of:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="stations">
<item>
<name>Station name</name>
<longitude>1111111</longitude>
<latitude>11111</latitude>
<code>1</code>
</item>
And another (possible) problem is that to get just one station I have to get all of them and pull the one I want from the array. Is this going to be considerably slower? Can I make this array consistent throughout the app? (But keeping the separate Intent methodology)
I had the same thought as MilkJug, to use a utility method to create the stations, but I want to offer a slightly different approach: Move as much of the construction logic as possible into the Station class constructor. To keep the example simple, I'm moving the utility method into the Station class as well.
This provides an overall cleaner design, as outside of the Station class itself, your code should never have to deal with a Station object whose construction/initialization steps haven't been fully completed.
(kgiannakakis's suggestion to use a database may be a better way to go if you have a lot of Station objects.)
public class Station {
private static List<Station> sStationArray = null;
/**
* Construct a Station from a specially-encoded String. The String
* must have all the necessary values for the Station, separated by tabs.
*/
public Station(String fieldString) {
String[] fields = fieldString.split("[\t ]");
// For safety, setValuesFromArray() should be declared 'final'.
// Better yet, you could just move its body into this constructor.
setValuesFromArray(fields);
// I'm assuming 'mName' is the name field for the Station
Log.i("Station", this.mName);
}
public static Station getStationArray(Context ctx) {
if (sStationArray == null) {
// (Please don't use the prefix 'm' for non-member variables!)
final String[] tempArray =
ctx.getResources().getStringArray(R.array.stations);
final int len = tempArray.length;
// Passing the length into the ArrayList constructor (if it's
// known, or can be guessed at) can be a very simple yet
// effective optimization. In this case the performance boost
// will almost certainly **not** be meaningful, but it's
// helpful to be aware of it.
sStationArray = new ArrayList<Station>(len);
for (int i = 0; i < len; i++) {
Station s = new Station(tempArray[i]);
sStationArray.add(s);
}
}
return sStationArray;
}
}
Why not create a utility method that takes a context as a parameter and returns the station resources? For example:
public class StatUtil {
private static List<Station> mStationArray = null;
public static Station getStation(Context ctx) {
if (mStationArray == null) {
String[] mTempArray = getResources().getStringArray(R.array.stations);
int len = mTempArray.length;
mStationArray = new ArrayList<Station>();
for(int i = 0; i < len; i++){
Station s = new Station();
String[] fields = mTempArray[i].split("[\t ]");
s.setValuesFromArray(fields);
Log.i("ADD STATION", ""+s);
mStationArray.add(s);
}
}
return mStationArray;
}
}
and call it from your code with:
stationArray = StatUtil.getStation(this);
Repeatedly fetching the stations will be slower than caching them, but not significantly slower unless you are fetching them in a loop. Doing as above will prevent multiple copies from being fetched.
I could propose two solutions:
You could create a Singleton class that initializes once, reads the data from the XML and stores the stations in a List or a Map. Use a Map if you want to quickly find a station based on its name. The Singleton class will provide methods for retrieving all stations or just one of them.
Create a database table and store the information there. You may need more code, but the advantage will be that you will be able to run more advanced queries.
Related
ArrayList<Integer> companiesId = new ArrayList<>();
int numberOfCompanies = 10; // Just for example
...
float profit;
Scanner input = new Scanner(System.in);
for(int i = 0; i < numberOfCompanies; i++) {
int companyId = input.nextInt();
if (!companiesId.contains(companyId)) {
companiesId.add(companyId);
}
if (companiesId.get(i) == 1) {
profit = 1000;
} else if (companiesId.get(i) == 2) {
profit = 2000;
}
}
Now I want to print all the companyIds from the ArrayList with the profit entered for each id, but I don't know how to do it with the ArrayList.
It should be:
1 1000
2 2000
...
You cannot do what you ask because part of the information you need to print (profit) is lost. What you need to do first is to create a class that holds a company ID and the profits. With the new version of Java, you can create a record that will hold such information. A Java Record is nothing more than a POJO that is identified with that new keyword (record) and does not require you to create all the boilerplate code. Your record class will look something like this:
public record CompanyRecord(int companyID, float profit) {
}
You don't even need to override toString(). That is, unless you want to print the contents of the record in a different way than the default. Then, you will need to create a list of CompanyRecord objects:
ArrayList<CompanyRecord> companies = new ArrayList<>();
Then, you can do whatever you need. For example, I created this simple demo that create a list of 10 company records and uses the loop counter to set the company ID and as a multiplier for the profits. Lastly, it prints out the record to the console.
public class CompanyRecordDemo {
public static void main(String[] args) {
ArrayList<CompanyRecord> companies = new ArrayList<>();
float profit = 1000.0f;
for (int i = 1; i <= 10; i++) {
CompanyRecord rec = new CompanyRecord(i, profit * i);
companies.add(rec);
System.out.println(rec);
}
// do whatever you need with the list...
}
}
The output of this small program is:
CompanyRecord[companyID=1, profit=1000.0]
CompanyRecord[companyID=2, profit=2000.0]
CompanyRecord[companyID=3, profit=3000.0]
CompanyRecord[companyID=4, profit=4000.0]
CompanyRecord[companyID=5, profit=5000.0]
CompanyRecord[companyID=6, profit=6000.0]
CompanyRecord[companyID=7, profit=7000.0]
CompanyRecord[companyID=8, profit=8000.0]
CompanyRecord[companyID=9, profit=9000.0]
CompanyRecord[companyID=10, profit=10000.0]
This is probably the simplest way to accomplish what you need. You will need to use Java 14 or later to make use of Java Records, but I recommend you use the latest version.
UPDATE: One important thing to note is that Java records are immutable. So, they have no setters (mutator methods). You will have to set the values through the constructor and values cannot be changed afterwards. You can access (get) the property values by calling a method that has the same name as the field. For example, the getter method for profit is profit(). For example rec.profit().
I'm trying to figure out how to get a undo function for a small maze game. First I worked out a way to do this by checking what the last direction was and just going back in the opposite direction. But this code was getting way too long since I also had to track back possible item pickups or hidden walls etc.
Background info on the code: I use a String[][] to store the maze as this was the easiest. I use an Arraylist<String[][]> to store all the strings.
After each step the player takes I save the String[][] array to the arraylist. When the player say undo I look at the second last String[][] in the arraylist and want to set the String[][] back to this. But the currentPos never seems to get updated. I'm not sure where the problem lies.
if (direction.equals("north")) {
if (currentPos[i - 1][j].equals("---")) {
continue;
} else {
currentPos[i][j] = " ";
currentPos[i - 2][j] = "P";
break;
}
}
if (direction.equals("undo")) {
currentPos = history.get(history.size()-2);
history.remove(history.size()-1);
break;
}
Without understanding the way you are setting history, I've made the assumption from your question that you are simply adding the current map to the history list. If you aren't careful, you will be simply adding the same Object, populating the history with multiply Object references to the current map state. This would have the effect you are observing with the state not changing, because you the history only contains a reference to the most recent map (Not storing any actual history).
To obtain the value from an Object, you typically need to clone the object (invoking the clone() method). However, cloning a 2-dimensional array is somewhat problematic. Invoking the clone() method on a 2-dimensional array "shallow" clones the object, essentially only cloning the first dimension while leaving the second as a reference to the same object (The reason for this is that the first 1-dimension of the array holds a reference to the second 1-dimension). Changing the value on a shallow copied object will change the value of the original and vice-versa, not what you want if you want to keep the Objects distinct.
To create two distinct objects, you will need to perform a "deep" clone, which can be easily implemented in a helper method. The below code illustrates the importance of ensuring you fully clone the object before storing it in the history list.
public static void main (String args[]) throws Exception {
ArrayList<String[][]> list = new ArrayList<>();
String[][] shallowClonedMap = new String[1][1];
String[][] deepClonedMap = new String[1][1];
shallowClonedMap[0][0] = "Old";
deepClonedMap[0][0] = "Old";
list.add(shallowClonedMap.clone());
list.add(deepClone(deepClonedMap));
shallowClonedMap[0][0] = "New";
deepClonedMap[0][0] = "New";
list.add(shallowClonedMap.clone());
list.add(deepClone(deepClonedMap));
for (String[][] item : list) {
System.out.print(item[0][0]);
}
}
public static String[][] deepClone(String[][] arry) {
if (arry == null) {
return null;
}
String[][] clone = new String[arry.length][];
for (int i = 0; i < arry.length; i++) {
clone[i] = arry[i].clone();
}
return clone;
}
The output for executing this code is : NewOldNewNew whereas the "intended" output is "OldOldNewNew". From this you can see the shallowClonedMap was updated to "New" even after being cloned and added to the list.
I am creating a game in java. I am using an array of Armor's for equipment
The issue, is that whenever I change 1 variable in my array, the other objects are also affected. This looks like a pointer issue but, all of the objects have been initialized as separate and called as new.
private Armor[] equip = new Armor[3];
public Inventory()
{
for(int i = 0; i<3;i++)
equip[i] = new Armor();
equip[0] = new Armor("head","You don't have head equipment","head",0,10,0,0);
equip[1] = new Armor("tunic","A simple farmers tunic","chest",0,10,0,0);
equip[2] = new Armor("baggy pants","Basic pants woven from rough cloth","legs",0,10,0,0);
System.out.println(armorDes(0));
System.out.println(armorDes(1));
System.out.println(armorDes(2));
}
All of the print lines output
baggy pants
0 armor
10 evasion bonus
Basic pants woven from rough cloth
instead of their own stats.
This was tested with a debugger and all of the objects are declared to different locations in data. Is this a java issue are am I just stupid?
Code is unclear above
private Armor[] equip = new Armor[3];
public Inventory()
{
for(int i = 0; i<3;i++)
equip[i] = new Armor();// Why creating object using default constructor here? no use
equip[0] = new Armor("head","You don't have head equipment","head",0,10,0,0);
equip[1] = new Armor("tunic","A simple farmers tunic","chest",0,10,0,0);
equip[2] = new Armor("baggy pants","Basic pants woven from rough cloth","legs",0,10,0,0);
// Use toString() method in Armour class to see the values present in variables.
//Also be sure all variables are instance variables
System.out.println(equip[0]);
System.out.println(equip[1]);
System.out.println(equip[2]);
//System.out.println(armorDes(0));
//System.out.println(armorDes(1));
//System.out.println(armorDes(2));
}
The code is :
package classes;
public class Test {
private static double mutationRate = 0.5;
public static void main(String[] args) {
Population pop = new Population();
pop.initialise();
Population po = new Population();
po.getIndividusList().add(pop.getFittest());
po.getIndividusList().add(mutate(pop.getIndividusList().get(1)));
}
private static Chromosom mutate(Chromosom l) { // changer les couples d'interventions des parcs)
// loop through genes
Chromosom ch = new Chromosom();
for (int i = 0; i < l.size(); i++)
ch.put(i, l.get(i));
for (int i = 0; i < ch.size(); i++) {
double alea = Math.random() * 13;
int moisIntervention1 = (int) alea;
Intervention interv1 = new Intervention(1, moisIntervention1);
ch.get(i).modInterventions(ch.get(i).intervention2(interv1));
}
return ch;
}
}
The problem is that I did not change the instance pop but when I change the other instance po, pop changes too.
java pass by value.
when you call this mutate(pop.getIndividusList().get(1))
you are sending pop's instance, so it will get change.
Supose pop.getIndividusList().get(1) return String varibale do this way
String var=pop.getIndividusList().get(1);
then call mutate(var)
I'm unsure about whether I understood the problem, but I think that you mean that when you alter the items in Population po, the items in Population pop mirror those changes.
That is, indeed, the expected behavior of your code: to populate po, you are adding items from pop - (pop.getFittest, pop.getList.get(1) ).
But the individuals are, I believe, instances of objects, so add/remove and similar operations work with references to the objects, and not with copies of them. Therefore, as you have 2 references to the same obj, any change is mirrored.
IF you want to create a copy, you should add to po a new object with the same state, either by creating a constructor that takes another instance as parameter, implementing a copy method, or something similar.
It should be something like this:
Population po = new Population();
Individual fittest = pop.getFittest();
Individual poCopy = new Individual();
//ADD CODE HERE TO COPY ALL THE FIELDS FROM fittest TO poCopy
//....
po.getIndividusList().add(poCopy);
I don't know if this is right, so I need your comments guys. I have an array of employee names. It will be displayed on the console, then will prompt if the user wants to insert another name. The name should be added on the end of the array(index 4) and will display again the array but with the new name already added. How do I do that? Btw, here's my code. And I'm stuck. I don't even know if writing the null there is valid.
public static void list() {
String[] employees = new String[5];
employees[0] = "egay";
employees[1] = "ciara";
employees[2] = "alura";
employees[3] = "flora";
employees[4] = null;
for(int i = 0; i < employees.length; i++) {
System.out.println(employees[i]);
}
}
public static void toDo() {
Scanner input = new Scanner(System.in);
System.out.println("What do you want to do?");
System.out.println("1 Insert");
int choice = input.nextInt();
if(choice == 1) {
System.out.print("Enter name: ");
String name = input.nextLine();
You can't, basically.
Arrays have a fixed size when they've been constructed. You could create a new array with the required size, copy all the existing elements into it, then the new element... or you could use a List<String> implementation instead, such as ArrayList<String>. I'd strongly advise the latter approach.
I suggest you read the collections tutorial to learn more about the various collections available in Java.
Also note that you've currently just got a local variable in the list method. You'll probably want a field instead. Ideally an instance field (e.g. in a class called Company or something similar) - but if you're just experimenting, you could use a static field at the moment. Static fields represent global state and are generally a bad idea for mutable values, but it looks like at the moment all your methods are static too...
Arrays are fixed in size. Once you declare you can not modify it's size.
Use Collection java.util.List or java.util.Set. Example ArrayList which is dynamic grow-able and backed by array.
If you really have to use arrays then you will have to increase the size of the array by using an intermediate copy.
String[] array = new String[employees.length + 1];
System.arraycopy(employees, 0, array, 0, employees.length);
array[employees.length] = newName;
employees = array;
However, the best way would be to use a List implementation.
It depends on whether the user can enter more than 4 employee names. If they can then using ArrayList is the better choice. Also the employees variable needs to be a static property of your class since being used in a static method.
private static String[] employees = new String[5];
static {
employees[0] = "egay";
employees[1] = "ciara";
employees[2] = "alura";
employees[3] = "flora";
employees[4] = null;
}
public static void list() {
for(int i = 0; i < employees.length; i++) {
System.out.println(employees[i]);
}
}
public static void addEmployeeName(String name, int index) {
employees[index] = name;
}
Here you are using static array which is fixed at the time of creation.I think you should use
java.util.Arraylist which will provide you facility of dynamic array.