Here's the situation :
I have 3 objects all named **List and I have a method with a String parameter;
gameList = new StringBuffer();
appsList = new StringBuffer();
movieList = new StringBuffer();
public void fetchData(String category) {
URL url = null;
BufferedReader input;
gameList.delete(0, gameList.length());
Is there a way to do something like the following :
public void fetchData(String category) {
URL url = null;
BufferedReader input;
"category"List.delete(0, gameList.length());
, so I can choose which of the lists to be used based on the String parameter?
I suggest you create a HashMap<String, StringBuffer> and use that:
map = new HashMap<String, StringBuffer>();
map.put("game", new StringBuffer());
map.put("apps", new StringBuffer());
map.put("movie", new StringBuffer());
...
public void fetchData(String category) {
StringBuffer buffer = map.get(category);
if (buffer == null) {
// No such category. Throw an exception?
} else {
// Do whatever you need to
}
}
If the lists are fields of your object - yes, using reflection:
Field field = getClass().getDeclaredField(category + "List");
List result = field.get();
But generally you should avoid reflection. And if your objects are fixed - i.e. they don't change, simply use an if-clause.
The logically simplest way taking your question as given would just be:
StringBuffer which;
if (category.equals("game"))
which=gameList;
else if (category.equals("apps"))
which=appList;
else if (category.equals("movie"))
which=movieList;
else
... some kind of error handling ...
which.delete();
As Jon Skeet noted, if the list is big or dynamic you probably want to use a map rather than an if/else/if.
That said, I'd encourage you to use integer constant or an enum rather than a String. Like:
enum ListType {GAME, APP, MOVIE};
void deleteList(ListType category)
{
if (category==GAME)
... etc ...
In this simple example, if this is all you'd ever do with it, it wouldn't matter much. But I'm working on a system now that uses String tokens for this sort of thing all over the place, and it creates a lot of problems.
Suppose you call the function and by mistake you pass in "app" instead of "apps", or "Game" instead of "game". Or maybe you're thinking you added handling for "song" yesterday but in fact you went to lunch instead. This will successfully compile, and you won't have any clue that there's a problem until run-time. If the program does not throw an error on an invalid value but instead takes some default action, you could have a bug that's difficult to track down. But with an enum, if you mis-spell the name or try to use one that isn't defined, the compiler will immediately alert you to the error.
Suppose that some functions take special action for some of these options but not others. Like you find yourself writing
if (category.equals("app"))
getSpaceRequirements();
and that sort of thing. Then someone reading the program sees a reference to "app" here, a reference to "game" 20 lines later, etc. It could be difficult to determine what all the possible values are. Any given function might not explicitly reference them all. But with an enum, they're all neatly in one place.
You could use a switch statement
StringBuffer buffer = null;
switch (category) {
case "game": buffer = gameList;
case "apps": buffer = appsList;
case "movie": buffer = movieList;
default: return;
}
Related
I have a LogAnalyzer class that looks at a web server log, creates LogEntry objects and puts those objects into HashMaps for analyzing.
My LogAnalyzer class has these fields:
private int totalVisits;
private int uniqueVisits;
private ArrayList<LogEntry> records;
private HashMap<String, ArrayList<LogEntry>> uniqueIPs; //<address, log entries>
private HashMap<String, ArrayList<LogEntry>> dailyRecords; // <date, log entries>
My constructor looks like this:
public LogAnalyzer() {
records = new ArrayList<>();
dailyRecords = new HashMap<>();
uniqueIPs = new HashMap<>();
}
And then I have this method:
public void initializeRecords(String path){
readFile(path); //reads the web log file and fills out the records and dailyRecords fields
getUniqueIPs(); //fills out the uniqueIPs HashMap field.
uniqueVisits = uniqueIPs.size(); //fills out the uniqueVisits field
totalVisits = records.size(); //fills out the totalVisits field
}
So my question:
I have read (but don't really understand) it's "bad" to call methods inside the constructor. However it seems like the constructor is pointless here, since it is actually the initializeRecords that is doing all of the meaningful work of "creating" the object.
I don't have the background in Java or programming to understand the explanations I've found so far. There is a lot of talk of overriding things, and I think that's what I'm not clear on. I'm wondering why I should keep my constructor and this method seperated, in simple terms that a beginner can understand.
**EDIT: ** Here's the code for readFile():
public void readFile(String filename) {
FileResource fr = new FileResource(filename);
for (String line : fr.lines()){
LogEntry le = WebLogParser.parseEntry(line);
String date = le.getAccessTime().toString().substring(4, 10);
if (dailyRecords.keySet().contains(date)){
dailyRecords.get(date).add(le);
}
else{
ArrayList<LogEntry> entries = new ArrayList<>();
entries.add(le);
dailyRecords.put(date, entries);
}
records.add(le);
}
Keeping the two methods allows you more flexibility in the use of your code. You can instantiate your LogAnalyzer without knowing the path to your log. I would rename initializeRecords to processRecords which IMO is more descriptive of what you are doing there.
We should create the object first and then call methods on it. If your readFile method were to throw an Exception because it can't read the file for example. I would find it very odd to get that exception when I am constructing the object. The point of the constructor is to provide an object that can be used to do something.
It's not a good practice to call methods from within constructor, because Java always calls the most derived method, which means we could call a method on a half-initialized object.
To answer your question,
public LogAnalyzer() {
records = new ArrayList<>();
dailyRecords = new HashMap<>();
uniqueIPs = new HashMap<>();
}
What the above part exactly does is, it gives the variables, records, dailyRecods and uniqueIPs a physical address in the memory stack.
When we write something like private ArrayList<LogEntry> records; in the class, at this time only a reference is generated, but actual initialization happens only when records = new ArrayList<>(); this line gets executed.
Hope this clarifies your doubt!!!
As you can see in readFile() it uses the following instruction
dailyRecords.keySet().contains(date)
without initializing dailyRecords prior to it. So if you do not initialize dailyRecords either while declaring it or in constructor you will face NullPointerException.
In your case instead of using constructor for initialization you can use declaration part like this
private HashMap<String, ArrayList<LogEntry>> dailyRecords = new HashMap<>();
I want to make an OreBase class so that i don't make a new class for every new ore because they should pretty much do the exact same thing: 1. exist, 2. drop the appropriate item that is named before the underscore of the ore name (ruby_ore -> ruby). To return a ruby for a ruby_ore i need to return ModItems.RUBY, i can get the string "RUBY" from "ruby_ore", but i don't know how to properly add it after "ModItems.". Is this possible?
If that isn't possible, is it maybe possible to put "ModItems." and the item string ex. "RUBY" in a single string ex. "ModItems.RUBY" and run that string as code?
#Override
public Item getItemDropped(IBlockState state, Random rand, int fortune) {
int a = ore_name.indexOf('_'); //ex. ore_name = ruby_ore
String b = ore_name.substring(0,a); //ex. ruby
String c = b.toUpperCase();//ex. RUBY
return ModItems.b;//i want this to do ex. ModItems.RUBY
}
So if the ore_name is ex. biotite_ore the function should return ModItems.BIOTITE, for pyroxine_ore it should return ModItems.PYROXINE, etc.
There are at least 3 ways of doing this. Take your pick.
1. Make ModItems an Enum containing an Item object:
int a = ore_name.indexOf('_');
String b = ore_name.substring(0,a);
String c = b.toUpperCase();
return ModItems.valueOf(c).getItem();
Pros: Simple, no need to update a map if a new item is added
Cons: Throws an exception if the ModItem doesn't exist
2. Making a Map<String, ModItem> (preferred):
return oreMap.get(ore_name);
Pros: Simple, easy to implement
Cons: You have to update your map every time you add an item and get returns null for unknown ores
3. Reflection:
int a = ore_name.indexOf('_');
String b = ore_name.substring(0,a);
String c = b.toUpperCase();
return ModItems.class.getDeclaredField(c).get(null);
Pros: No need to update a map for every new item
Cons: Overkill, throws ugly checked exceptions, and is generally frowned upon unless absolutely necessary.
Im trying to return an arraylist from the method getNumbers (which contains strings)
public ArrayList<String> getNumbers(){
return (numeros);
}
Then by using a searcher im trying to compare between a variable m (which contains the desired info to look for) and the returned list.
public class NumberSearcher {
Reader reader = new KeyboardReader();
public NumberSearcher(ArrayList<Contacto> contactos){
String m = reader.read();
for(int i = 0; i<contactos.size();i++){
if(contactos.get(i).getPhoneNumbers().contains(m)){
contactos.get(i).display();
}
}
}
}
I have succeded in creating a searcher using this very same style but only when using methods that return String alone.
The problem is its not working. If there there would be a match it should display the contact information but it seem it isnt "comparing" properly because nothing happens.
It's difficult to understand what you're asking here. Your getNumbers method doesn't get called from the second code block, so I don't see where that is relating to anything. It's also unclear what you mean the problem is. Can you try to give us a more detailed description of what is going wrong?
Anyways, I'll try to give you some general advice here, but without knowing the issue it's hard to say how much this will help.
Firstly, it is almost always recommended to have your method's return type as the List interface, rather than a specific implementation (ArrayList, etc). You can specify a return type from within the method but this way they client doesn't need to know what the underlying data structure is, and you are also flexible to future data structure changes.
public List<String> getNumbers(){
return (numeros);
}
Secondly, I would probably change the name 'getNumbers' to something slightly more precise - if I see a 'getNumbers' method I expect it to return some numeric entities, not a list of strings. If they are phone numbers then explicity call it 'getPhoneNumbers'.
Though I'm not entirely sure I understand what you asking, I think this may solve your issues:
for(int i = 0; i < contactos.size(); i++) {
Contacto next = contactos.get(i);
if(next.getEmails().contains(m)) {
next.display();
}
}
And as an afterthought, is there any specific reason you're only checking string containment? I would suggest that you check case-insensitive equality unless you really do want to find out if the string just contains the element.
Is this what you are looking for?
public class EmailSearcher {
Reader reader = new KeyboardReader();
public EmailSearcher(ArrayList<Contacto> contactos){
while(reader.read() != 'keyThatTerminates') {
String m = reader.read();
for(int i = 0; i<contactos.size();i++){
var row = contactos.get(i);
if(row.getEmails().contains(m)){
row.display();
}
}
}
}
}
I'm stuck on this program I'm making for school. Here's my code:
public static void experiencePointFileWriter() throws IOException{
File writeFileResults = new File("User Highscore.txt");
BufferedWriter bw;
bw = new BufferedWriter(new FileWriter(writeFileResults, true));
bw.append(userName + ": " + experiencePoints);
bw.newLine();
bw.flush();
bw.close();
FileReader fileReader = new FileReader(writeFileResults);
char[] a = new char[50];
fileReader.read(a); // reads the content to the array
for (char c : a)
System.out.print(c); // prints the characters one by one
fileReader.close();
}
The dilemma I'm facing is how can I sort new scores with the scores in writeFileResults by the numerical value of int experiencePoints? If you're wondering about the variables userName is assigned by a textfield.getText method, and an event happens when you press one of 36 buttons which launches a math.Random statement with one of 24 possible outcomes. They all add different integer numbers to experiencePoints.
Well, I don't want to do your homework, and this does seem introductory so I'd like to give you some hints.
First, there's a few things missing:
We don't have some of the variables you've given us, so there is no type associated with oldScores
There is no reference to userName or experiencePoints outside this method call
If you can add this information, it would make this process easier. I could infer things, but then I might be wrong, or worse yet, have you learn nothing because I did your assignment for you. ;)
EDIT:
So, based on extra information, you're data file is holding an "array" of usernames and experience values. Thus, the best way (read: best design, not shortest) would be to load these into custom objects then write a comparator function (read: implement the abstract class Comparator).
Thus, in pseudo-Java, you'd have:
Declare your data type:
private static class UserScore {
private final String name;
private final double experience;
// ... fill in the rest, it's just a data struct
}
In your reader, when you read the values, split each line to get the values, and create a new List<UserScore> object which contains all of the values read from the file (I'll let you figure this part out)
After you have your list, you can use Collections#sort to sort the list to be the correct order, here would be an example of this:
// assuming we have our list, userList
Collections.sort(userList, new Comparator<UserScore>() {
public int compare(UserScore left, UserScore right) {
return (int)(left.getExperience() - right.getExperience()); // check the docs to see why this makes sense for the compare function
}
}
// userList is now sorted based on the experience points
Re-write your file, as you see fit. You now have a sorted list.
basically am trying to make java command prompt. Suppose user enters as input from the user:
new x java.util.ArrayList
here x is the object name and java.util.ArrayList is the class. So this script inputed by the user means create an object of class java.util.ArrayList.
Now suppose that user enter:
new x java.util.ArrayList int:5
means create an object x of the java.util.ArrayList and make its size 5. Like this i want that everytime i input something related to object creation as input i should be able to create class its object and its method based on the input that the user does. Am new to java and reflection so kindly help! here is the code i thought so far using my mind:
public static void token_classification() throws ClassNotFoundException
{
my_hash = new HashMap();
Keep_Obj_Info = new HashMap();
if(expression_keeper[0].equalsIgnoreCase("new"))
{
my_hash.put("Object", expression_keeper[1]);
Class Obj= Class.forName(expression_keeper[2]);
Keep_Obj_Info.put("Modifier", Obj.getModifiers());
Keep_Obj_Info.put("Package",Obj.getPackage());
////????
Constructor[] constructors = Obj.getConstructors();
}
else
if(expression_keeper[0].equalsIgnoreCase("call"))
{
}
else
if(expression_keeper[0].equalsIgnoreCase("print"))
{
}
else
{
System.out.println("Invalid Script!");
}
}
ExpressionKeeper is basically a String array that keeps the user input in tokenized form. Meaning anything next to a white space to a new location.
Well for Object creation in java; the constructor and it's arguments are required.
you can have a generic framework which will accept input from command prompt and interpret them means find out the data type of the input ex : number/string/char/boolean etc..
Also your framework should know the argument index for example say a constructor has 2 parameter and one is string and another is int. and say first parameter is int and 2nd parameter is String and while passing the parameter from the command line the user first pass string and then int in that scenario your program should be smart enough to properly arrange them in order. So many such things you need to take care of....Now coming to the example which you have mentioned for ArrayList you can write a program as follows : (I have just given you a pseudocode you can implement your own way)
{
int howManyParametersFromCommandLine = getnoParameterCount; //it will maintain no.of parameters passed from command line
String[] parametersFromCommandLine = getParametersFromcommandLine(); // Ex : {1,"ABC",new Double(80.0d)};
List<Class> parameterTypesList = parseParameters(parametersFromCommandLine); //This will identify type of each of the parameter
Class clazz = Class.forName("youClassName");
Constructor[] cons = clazz.getConstructors();
for(Constructor c : cons)
{
Class[] parameterTypes = c.getParameterTypes();
if(parameterTypes.length == howManyParametersFromCommandLine)
{
//try to match the parameter type in parameterTypesList with parameterTypes if this matches then
boolean typeMatchingAndSequecneSucess = matchParameters(parameterTypes,parameterTypesList);
if(typeMatchingAndSequecneSucess)
{
if(c.isAccessible())
{
Object[] initargs = parseAndRetActualParamValue(parametersFromCommandLine);
return c.newInstance(initargs);
}
}
}
}
}
Hope this will help you !!
You may want to use the Interpreter design pattern. It is used just for that.
The Interpreter is a bit complex, but will ensure you code interpretation works right. Also, it gives you a easy inclusion of new commands.
Take a look at here: http://en.wikipedia.org/wiki/Interpreter_pattern
Hope I could help.