How can I reference / define an array from another method in java? - java

I have some code that is similar to the following:
public class exampleClass {
public void main(){
defineVariable();
nextMethod();
}
void nextMethod(){
list[8] = "threw away";
}
void defineVariable(){
String[] list = {"trivial string","more trivial strings",
"just another trivial string","tr","a","sd",
"godzilla","ate","my","pony","and homework","trivial"};
}
}
And I cant access list in nextMethod.How can I fix this problem , it may seem trivial to make such a small array global but the actual arrays are in the hundreds (hence the fact I didnt c+p my actual code although if this is necessary I wont mind in the least).
Thanks very much and as a side note this is in Android although I doubt that that will effect the java code (am I wrong to assume this?).
Anyway thanks again! Ive been using StackOverflow alot lately and have only contributed a bit so from now on I will attempt to answer as many questions as I can.
Thanks,

Simply declare it in class.
public class exampleClass {
public void main()
{
nextMethod(defineVariable());
}
void nextMethod(String[] list)
{
list[8] = "threw away";
}
private String tab[] defineVariable()
{
String[] list= {"trivial string","more trivial strings","just another trivial string","tr","a","sd",
"godzilla","ate","my","pony","and homework","trivial"};
return list
}
}

If you let defineVariable be void and create a variable within its own scope, that variable just disappears into oblivion upon finished exection. Instead, have defineVariable return the list and then use this list as a parameter to the nextMethod() function.

A neat way to store many variables is to group them into different objects.
That way variables that are related can be put into the same object and the number of variables in your main class is reduced to a managable number.
In the example below, I have made the variables public. If you prefer, you can create getters and setters instead.
public class Actions {
public String humans[] = { "sit", "stand", "eat", "walk", "run", "drive", ride" };
public String dogs[] = { "sit", "stand", "bark", "run" };
public String sharks[] = { "swim", "attack" };
}
public class Equipment {
public String armour[] = { "leather", "chainmail", "plate" };
public String weapon[] = { "sword", "axe", "dagger" };
}

Related

Invoke Java object constant using a variable

I'm very new to Java so it makes it hard for me to explain what I'm trying to do.
I have an abstract class that invokes several object constants like this:
public abstract class Enchantment implements Keyed {
/**
* Provides protection against environmental damage
*/
public static final Enchantment PROTECTION_ENVIRONMENTAL = new EnchantmentWrapper("protection");
In a different file I can access this perfectly fine with Enchantment value = Enchantment.PROTECTION_ENVIRONMENTAL;
However, I'm trying to use a string variable for this instead. Something like this:
String str = "PROTECTION_ENVIRONMENTAL";
Enchantment value = Enchantment.str;
Obviously that won't work. So I did a bunch of research and learned I need to use reflection for this. Using this source code's docs I figured I was looking for field data. So I tried both:
Field fld = Enchantment.class.getField("PROTECTION_ENVIRONMENTAL");
Field fld = Enchantment.class.getDeclaredField("PROTECTION_ENVIRONMENTAL");
But these returned me a NoSuchFieldException. As I was on it, I've tried both getMethod() and getDeclaredMethod() just as well equally with no luck.
I'm now at the point that these are probably "object constants"? I'm not sure how to call them. But I'm definitely at a loss on how to get this to work now and after everything I've tried myself, I figured it was time to ask for some help here.
That one comment is spot on: you absolutely do not use reflection here.
There are only two valid reasons to use reflection:
you are creating a framework that has to deal with classes it doesn't know about
you have for some other reason to deal with classes you don't know about at compile time
But your code perfectly knows about that Enchantment class, its capabilities, and so on. Therefore reflection is the wrong approach. You figured it yourself: it is damn hard to get right, and damn right to get it wrong in some subtle ways. And when you get it wrong, it always blows up at runtime. Reflection code compiling means nothing. It always waits for you to run it to throw up in your face.
So to answer your question by not answering it: use a Map. Like:
Map<String, Enchantment> enchantmentsByConstantName = new HashMap<>();
enchantmentsByConstantName.put("PROTECTION_ENVIRONMENTAL", PROTECTION_ENVIRONMENTAL);
Alternatively, these constants could go into an enum, as outlined in the other answer, but in a sightly different way:
enum EnchantmentHolder {
PROTECTION_ENVIRONMENTAL(new EnchantmentWrapper("protection")),
ANOTHER_ENCHANTMENT(...)
A_THIRD_ENCHANTMENT(...)
...;
private Enchantment enchantment;
private EnchantmentHolder(Enchantment enchantment) {
this.entchantment = entchantment;
}
public Enchantment getEntchantment() { return entchantment; }
You may want to look into enumerations if you know they're going to be constant values;
public enum Enchantment {
PROTECTION_ENVIRONMENTAL {
public void cast() {
// do enum-specific stuff here
}
},
ANOTHER_ENCHANTMENT {
public void cast() {
// do enum-specific stuff here
}
},
A_THIRD_ENCHANTMENT{
public void cast() {
// do enum-specific stuff here
}
};
public abstract void cast();
}
enums can be treated like classes and have methods and properties. You can also convert to and from strings Enchantment.valueOf("PROTECTION_ENVIRONMENTAL") but that's generally if you are reading from a configuration file - in code you'd reference the value directly.
Once you have the Field, you need to call Field.get(Object) with an instance (in this case the class). Something like,
Class<?> cls = Enchantment.class;
try {
Field f = cls.getField("PROTECTION_ENVIRONMENTAL");
System.out.println(f.get(cls));
} catch (Exception e) {
e.printStackTrace();
}
Since you want the Enchantment, you could then test that the instance you get is assignable to Enchantment. Something like,
Class<? extends Enchantment> cls = Enchantment.class;
try {
Field f = cls.getField("PROTECTION_ENVIRONMENTAL");
Object obj = f.get(cls);
if (cls.isAssignableFrom(obj.getClass())) {
Enchantment e = cls.cast(obj);
System.out.println(e);
}
} catch (Exception e) {
e.printStackTrace();
}
But the enum approach is better.

String input to specify which function to call [Java] [Best Practice]

The Application
I am writing an application that executes certain functions depending on user input.
E.g. if the user input were to be
"1 2 add" the output would be "3".
I aim to implement many such methods (div, modulo, etc.). As my Scanner recognizes a function name like "add" the function "add()" should be called.
My Way
My way to do this is to let a FunctionHandler class evaluate the input.
Main:
String inputCommand = sc.nextCommand();
functionHandler.handle(inputCommand);
Function Handler:
public class FunctionHandler {
public void handle (String functionName) {
if (functionName.equals("add")) {
add();
} else if (functionName.equals("div") {
div();
}
}
private void add() {
.......
}
....
}
The Problem with that
As I am adding more and more functions the if statement gets very large, and of course the FunctionHandler class too. Also, whenever I add a new function, I have to change code in two places: I have to define the function, and then add the else if clause in handle() to call the function. Which means two pieces of information that should be encapsulated are "stored" completely independent from each other.
I was wondering what the best practice was to solve this kind of situation?
My Ideas
I was thinking about using enums, but they don't seem to fit well in this case.
Another idea I had was creating an interface Function, and then a class for each function that implements Function. The interface would have two methods:
getName()
execute()
Then I could create an array (manually) of Functions in the FunctionHandler, through which I could loop to see if the command the user enters matches getName().
However, having a different class for each function is not very clean either, and it also does not get rid of the problem that for each function I am adding I have to do it in two places: the class and the array.
This question is only about finding out how to solve this problem cleanly. A pointer in the right direction would be appreciated!
Thanks a lot!
Another option would be to keep a Map of handlers. If you're using Java 8, they can even be method references.
// InputType and ResultType are types you define
Map<String, Function<InputType, ResultType>> operations = new HashMap<>();
operations.put("add", MathClass::add);
// ...
ResultType result = operations.get(userInput).apply(inputObject);
One downside to doing it this way is that your input and output types must be the same for all operations.
You could create a custom annotation for the various functions. Then you could employ your array idea, but have it use reflection to discover which functions have your new annotation and what their names are.
As background, take a look at http://www.oracle.com/technetwork/articles/hunter-meta-2-098036.html and http://www.oracle.com/technetwork/articles/hunter-meta-3-092019.html. They're a bit old, but seem to address the necessary ideas.
You can always use reflection if you want a short solution.
In your handle method you could do something like this:
Method m = this.getClass().getMethod(functionName, new Class[]{});
m.invoke(this, new Object[]{});
Assuming you do not have a lot of functions that you want to do this way, and do not want to expose yourself to the security risks caused by reflection, you could use a string switch, like this:
void handleFunction(String function) {
switch (function) {
case "foo":
foo();
break;
case "bar":
bar();
break;
default:
throw new IllegalArgumentException("Unknown function " + function);
break;
}
}
Starting Java 7, you can use Strings in a switch statement and the compiler will make something reasonable out of it
I would do something like this:
public class FunctionTest {
private static final Map<String, Runnable> FUNCTIONS = new HashMap<String, Runnable>() {{
put("add", () -> System.out.println("I'm adding something!"));
put("div", () -> System.out.println("I'm dividing something!"));
}};
public void handle(String functionName) {
if (!FUNCTIONS.containsKey(functionName)) {
throw new IllegalArgumentException("No function with this name: " + functionName);
}
FUNCTIONS.get(functionName).run();
}
}
You basically can use any functional interface in place of Runnable, I used it, because it matches your add() method. You can map the names of the functions to their actual executable instance, get them by name from the Map and execute them.
You could also create an enum with the desired executable blocks:
public class FunctionsAsEnumsTest {
private static enum MyFunction {
ADD {
#Override public void execute() {
System.out.println("I'm adding something");
}
},
DIV {
#Override public void execute() {
System.out.println("I'm dividing something");
}
};
public abstract void execute();
}
public void handle(String functionName) {
// #toUpperCase() might not be the best idea,
// you could name your enums as you would the methods.
MyFunction fn = MyFunction.valueOf(functionName.toUpperCase());
fn.execute();
}
}

JAVA cast Object with "unknown" type in type of another Object

Im new here and i want to start with my first not so easy to describe Questions. I think a piece of code can explain best.
public void erlaube(Geraet pGeraet){
for(Object g : mGeraetetypen){
if(pGeraet.getClass().equals(g.getClass())){
System.out.println("TRUE");
mErlaubt.add((g.getClass())pGeraet); // MY PROBLEM
}
//System.out.println(pGeraet.getClass());
//System.out.println(g.getClass());
}
}
A "Geraet" (Device) is an abstract Class and it can be a Sensor or an Actor f.ex. the class Temperaturesensor.
Geraetetypen (Devicetypes) is an ArrayList and contains all available Sensors and Actors.
The for- and if-block checks if the parameter Object is a type of an Object contained in the Devicetypes list f.ex. Temperaturesensor.
if it is, i want to add it as this datatype (Temperaturesensor) to the "mErlaubt" (mAllowed) ArrayList.
So it should do the same as This (cast):
mErlaubt.add( (Temperatursensor) pGeraet);
But i dont want to cast explicit with (Temperatursensor). I want to cast dynamic with the datatype i found from the Datatypelist that compares.
Maybe something like the line with the comment //MY PROBLEM, but this doesnt work.
I know this is hard and my description is not verry well, but i hope you understand what i try to do. Please help. If you dont understand something or have a Question please ask.. Thanks!
Referring to your code sample, I'd suggest to store the allowed classes instead of instances of the allowed classes. You could use this modified code:
public class Deviceplace {
Set<Class<? extends Geraet>> mErlaubt;
public Deviceplace(){
mErlaubt = new HashSet<>();
}
public void erlaube(Class<? extends Geraet> clazz) {
mErlaubt.add(clazz);
}
// Option 1: no subtypes of the allowed types
public boolean isErlaubt(Geraet pGeraet) {
return mErlaubt.contains(pGeraet.getClass());
}
public static void main(String[] args) {
Deviceplace place = new Deviceplace();
place.erlaube(Temperatursensor.class);
System.out.println(place.isErlaubt(new Windsensor()));
System.out.println(place.isErlaubt(new Temperatursensor()));
}
}
An alternative implementation of isErlaubt that also includes subtypes would be:
// Option 2: including subtypes of the allowed types
public boolean isErlaubt(Geraet pGeraet) {
for(Class<? extends Geraet> clazz : mErlaubt){
if (clazz.isAssignableFrom(pGeraet.getClass())) {
return true;
}
}
return false;
}
If your mErlaubt is an ArrayList of Geraet superclass, then you just have to use mErlaubt.add(pGeraet);
Your mErlaubt must then be defined like : List<Geraet> mErlaubt = new ArrayList<Geraet>();
You want to retrieve the class from a specific item of a list, and cast another object to this class? Apart from someClass.cast(someObject), there won't be any solutions. But as far as i can see, this whole code doesn't make any sense. You'll add a single object multiple times. And apart from that i'd say that's rather a job for Generics than casting.
I think that this change should work as pGeraet is of Class Geraet so casting a variable to the super class should work.
for(Object g : mGeraetetypen){
if(pGeraet.getClass().equals(g.getClass())){
System.out.println("TRUE");
mErlaubt.add((Geraet)pGeraet);
}
Thank you all! I want to share my verry simple solution to all. The class is a Deviceplace for Sensors/Actors on a houseautomation GUI. Each Deviceplace allows only a hand full of Sensor/Actors (f.ex. no Heating on a outside place)
public class Deviceplace {
ArrayList<Geraet> mErlaubt; //allowed devices
public Deviceplace(){
mErlaubt = new ArrayList<>();
}
public void erlaube(Geraet pGeraet){ //add allowed device
mErlaubt.add(pGeraet);
}
public boolean isErlaubt(Geraet pGeraet){ // check if device is allowed on this place
for(Geraet g : mErlaubt){
if(g.getClass().isInstance(pGeraet)){
return true;
}
}
return false;
}
public static void main(String[] args) {
Deviceplace place = new Deviceplace();
place.erlaube(new Temperatursensor()); // ad Temperaturesensor as allowed device
// now check if a device is allowed on this deviceplace
System.out.println(place.isErlaubt(new Windsensor())); // RETURNS false (Windsensor not allowed)
System.out.println(place.isErlaubt(new Temperatursensor())); // RETURNS true (Temperaturesensor allowed)
}
}

Java instantiate generic hashmap value

I have the following java code
public class QuestionBuilder {
private QuestionBuilder(){}
static HashMap<Long,Class<? extends Question>> questionIdMap;
static{
questionIdMap = new HashMap();
questionIdMap.put(1L, LicenseNumberQuestion.class);
questionIdMap.put(2L, USPQuestion.class);
}
static Question getQuestion(long questionId)
{
if(!questionIdMap.containsKey(questionId))
{
throw new BusinessProfileInputException("Add an id to question class map entry");
}
return questionIdMap.get(questionId).newInstance();
}
}
and I would like my getQuestion method to return me a new instance of the class that was specified as a value in the map as is intended via my code. Howerver the last line of code does not compile :
return questionIdMap.get(questionId).newInstance();
Am I thinking of this wrongly? i.e. is there a better way to approach this?
You just need to catch an exception:
try {
return questionIdMap.get(questionId).newInstance();
} catch(InstantiationException e) {
System.out.println("Constructor failed: );
e.printStackTrace();
return null;
}
This should compile fine.
I would do it like this:
public final class QuestionBuilder {
private QuestionBuilder(){}
public enum Type {
LICENSE_NUMBER {
#Override
Question getQuestion() { return new LicenseNumberQuestion(); }
},
USP {
#Override
Question getQuestion() { return new USPQuestion(); }
};
abstract Question getQuestion();
}
public static Question getQuestion(Type type) {
return type.getQuestion();
}
}
With your solution the user of the class has to write
Question question = QuestionBuilder.getQuestion(1);
This isn't great because it's not clear what "1" here means, and she is going to have to learn the meaning of a load of numbers. Also, if you pass in a number that doesn't mean anything, there's a problem (hence the need for a BusinessProfileInputException).
With the enum approach, the user of the class would write
Question question = QuestionBuilder.getQuestion(QuestionBuilder.Type.LICENSE_NUMBER);
Now this is obviously longer, but there are 3 major advantages. (1) The user of the class doesn't need to remember any abstract code numbers. In fact if the user is using a decent IDE, she should actually be presented with a meaningful list of choices as she types. (2) There is no longer the need for the BusinessProfileInputException because it is now impossible to pass something that doesn't mean anything (except null, but in this case a NullPointerException would be thrown anyway). (3) You no longer need reflection to create the new Question, so there is no need for the irritating try block.
But it's even better than this. You'll notice that since we've got rid of the Map, the class QuestionBuilder doesn't actually do anything at all. You could improve things further by getting rid of the class completely, and making the enum a top-level class with a simple name like TypeOfQuestion. Then all the user would have to type is
Question question = TypeOfQuestion.LICENSE_NUMBER.getQuestion();
enums in Java are absolutely brilliant. They are far superior to the counterparts in other languages. I strongly recommend learning about them.

Why cant I say variable.array in this case?

I don't see why I cant do this, without getting an error saying "Songs cannot be resolved or is not a field". I am a noob by the way, trying to learn this stuff :) Thanks in advance for you time, and please tell me if you need more information.
import java.util.ArrayList;
public class Band {
public String bandName;
public ArrayList<String> musician = new ArrayList<String>();
public ArrayList<String> songs = new ArrayList<String>();
// Constructor
public Band(String bandName) {
this.bandName = bandName;
}
public void getBandSongs(String bandName){
for (String s : bandName.songs) { <<<<<<<<<<<ERROR HERE
String rating = s.substring(0,1);
s = s.substring(1);
System.out.println("Rating: " + rating + " - Song name: " + s);
}
}
}
Sometimes the errors that the IDE gives you are misleading, but this one is quite clear.
So, let's analyse it:
"Songs cannot be resolved or is not a field"
So that should ring up an alarm. First thing you should do is look at the type that is your variable bandName.
public void getBandSongs(String bandName){
for (String s : bandName.songs) ...
It's a String! Of course you won't be able to access a field "songs" of a type String.
Maybe in your method signature you meant to have the following:
public void getBandSongs(Band band)
In that case, you should be able to access band.songs just fine.
Or you could have meant the following:
for (String s : this.songs)
That means you would be accessing the "songs" variable of the object instantiation of the class Band.
In summary:
The attributes that you define in your class:
public String bandName;
public ArrayList<String> musician = new ArrayList<String>();
public ArrayList<String> songs = new ArrayList<String>();
can be accessed through a variable that is of type of that class (in this case Band).
Hope this has made it a bit clear. Are you following any book in particular? I recommend the O'Reilly series. Good luck!
ps: I don't want to add too much since you are starting. But I advise you to read up on "encapsulation". That means that, unless strictly necessary, your should, by default, make your class's arguments private and let other classes access them through "getters" and "setters". Such that:
public class Band {
private String bandName;
private ArrayList<String> musician = new ArrayList<String>();
private ArrayList<String> songs = new ArrayList<String>();
public String getBandName(){
return this.bandName;
}
public void setBandName(String bandName){
this.bandName = bandName;
}
//And like that for the other two attributes. That way the classes that need access
// to these will either use a "get" method or a "set" method without directly
// accessing the attributes.
}
The work of creating getters and setters is so redundant that both Eclipse and Netbeans IDEs have a functionality that allows you to do these automatically.
songs is a part of Band, not bandName.
use this.songs instead (or just songs).
It should be noted though that public fields are against encapsulation (and thus OOP). Is this really what you want?
The major benefit of encapsulation (providing getters & setters for instance members) is to have a unified way of accessing your fields in a class. This allows you to, for example, add validation logic to your data.
private List<String> songs = new ArrayList<>();
public List<String> getSongs(){
return songs;
}
public List<String> setSongs(List<String> songlist) {
this.songs = songlist;
}
Now you can add validation to these methods. For example if you want to make sure you can only set the songlist if it has at least 5 songs in it:
public List<String> setSongs(List<String> songlist) {
if(songlist.size() > 5) {
this.songs = songlist;
}
}

Categories