What is a good java data structure for storing nested items (like cities in states)?
I'm just getting started in Java and am looking for advice on a good way to store nested sets of data. For example, I'm interested in storing city population data that can be accessed by looking up the city in a given state. (Note: eventually, other data will be stored with each city as well, this is just the first attempt at getting started.)
The current approach I'm using is to have a StateList Object which contains a HashMap that stores State Objects via a string key (i.e. HashMap<String, State>). Each State Object contains its own HashMap of City Objects keyed off the city name (i.e. HashMap<String, City>).
A cut down version of what I've come up with looks like this:
// TestPopulation.java
public class TestPopulation {
public static void main(String [] args) {
// build the stateList Object
StateList sl = new StateList();
开发者_JAVA百科
// get a test state
State stateAl = sl.getState("AL");
// make sure it's there.
if(stateAl != null) {
// add a city
stateAl.addCity("Abbeville");
// now grab the city
City cityAbbevilleAl = stateAl.getCity("Abbeville");
cityAbbevilleAl.setPopulation(2987);
System.out.print("The city has a pop of: ");
System.out.println(Integer.toString(cityAbbevilleAl.getPopulation()));
}
// otherwise, print an error
else {
System.out.println("That was an invalid state");
}
}
}
// StateList.java
import java.util.*;
public class StateList {
// define hash map to hold the states
private HashMap<String, State> theStates = new HashMap<String, State>();
// setup constructor that loads the states
public StateList() {
String[] stateCodes = {"AL","AK","AZ","AR","CA","CO"}; // etc...
for (String s : stateCodes) {
State newState = new State(s);
theStates.put(s, newState);
}
}
// define method for getting a state
public State getState(String stateCode) {
if(theStates.containsKey(stateCode)) {
return theStates.get(stateCode);
}
else {
return null;
}
}
}
// State.java
import java.util.*;
public class State {
// Setup the state code
String stateCode;
// HashMap for cities
HashMap<String, City> cities = new HashMap<String, City>();
// define the constructor
public State(String newStateCode) {
System.out.println("Creating State: " + newStateCode);
stateCode = newStateCode;
}
// define the method for adding a city
public void addCity(String newCityName) {
City newCityObj = new City(newCityName);
cities.put(newCityName, newCityObj);
}
// define the method for getting a city
public City getCity(String cityName) {
if(cities.containsKey(cityName)) {
return cities.get(cityName);
}
else {
return null;
}
}
}
// City.java
public class City {
// Define the instance vars
String cityName;
int cityPop;
// setup the constructor
public City(String newCityName) {
cityName = newCityName;
System.out.println("Created City: " + newCityName);
}
public void setPopulation(int newPop) {
cityPop = newPop;
}
public int getPopulation() {
return cityPop;
}
}
This is working for me, but I'm wondering if there are gotchas that I haven't run into, or if there are alternate/better ways to do the same thing.
(P.S. I know that I need to add some more error checking in, but right now, I'm focused on trying to figure out a good data structure.)
(NOTE: Edited to change setPop() and getPop() to setPopulation() and getPopulation() respectively to avoid confucsion)
If you really need these kinds of aggregation (StaleList that have States, States that have Cities), then this is the correct way to implement. It may not be the most straightforward, but it is the most object oriented approach. So, for the cost of minimalism, you sure get cohesion, coupling, maintainability and all those fancy software engineering adjectives. For small projects, these characteristics should not be enforced. But for big software projects they make sense and avoid really bad code (but do not guarantee really good code).
You can also use some third-party libraries (like the one from Pangea answer) to help keeping the code simple.
See:
1: http://en.wikipedia.org/wiki/Cohesion_(computer_science)
2: http://en.wikipedia.org/wiki/Coupling_(computer_science)
3: http://en.wikipedia.org/wiki/Maintainability
Checkout the Multimap data structure from guava collections. This is not the complete answer to your solution but will simplify to certain level. But the beauty is that now you can use MapMaker to cache your "population queries" against the city.
Multimap<String, City> stateToCities = ArrayListMultimap.create();
stateToCities.put("GA",new City("Atlanta",100000));
stateToCities.put("GA",new City("Cumming",50000));
I would consider using one class to manage a list States
containing member variables of City and population in two-dimensional arrays.
Other thoughts:
cityAbbevilleAl
is not checked against null
.
At first, I misread getPop
as a pop method and not population.
Spell out "population". Key strokes are cheap. You've already confused one responser here; it's likely that others won't get it at first, either.
Can population be negative? If not, I'd check that in your contract for setPopulation().
精彩评论