I am trying to create a generic menu over an arbitrary type T implementing a Menuable interface:
public interface Procedure {
void invoke();
}
public class Menu<T extends Menuable> implements Menuable {
List<T> items; //The items of the menu
List<String> itemsDisplay; //A list of String specifying how to display each of the above items
Procedure procedure; //A method to be performed on the elements of items
public Menu(List<T> items, List<String> itemsDisplay) {
this.items = items;
this.itemsDisplay = itemsDisplay;
}
//Returns a String display of the menu
//Each item is numbered and displayed as specified by the list itemsDisplay
public String menuDisplay() {
String s = "";
int i;
for (i = 1; i <= this.itemsDisplay.size(); i++) {
s = s + i + "\t" + this.itemsDisplay.get(i-1) + "\n";
}
return s;
}
...
}
The menu will be printed on a terminal, and when the user chooses an item, I would like the menu to be able to perform any instance method on this item. Basically, here is what I would like to do:
public Menu(List<T> items, List<String> itemsDisplay, Procedure procedure) {
this.items = items;
this.itemsDisplay = itemsDisplay;
Here I would like to assign a method to this.procedure for later use,
but without specifying on which object to use it yet.
}
public void waitForAction() throws IOException {
//Display the menu to the user
System.out.println(this.menuDisplay());
BufferedReader inputs = new BufferedReader(new InputStreamReader(System.in));
int choice = 0;
//Read inputs until the user enters a valid choice
while(!(1 <= choice && choice <= this.items.size())) {
try {
choice = Integer.parseInt(inputs.readLine());
} catch(NumberFormatException e) {
}
}
//The item selected is at index (choice - 1) in the list this.items
Here I would like to use my method on this.items.get(choice - 1).
}
I am new to the idea of using methods as variables / arguments and I don't know how to do that. I heard about lambda expressions and method references in Java, but from what I understood, when using them you have to specify the method you want to use and its instance / parameters at the same time, which is awkward. Am I missing something ?
So I have to create a pokedex program that displays the number of pokemon in the file while it also displays all the pokemon in the file. I added the file and everything in my other class here is the link to my GitHub which shows the other classes and the code for them. My main problem is writing the For Loop on displaying the count and result for all the pokemon. Here is what I have so far.
public class Pokedex implements PokedexInterface {
private Pokemon pokedex[] = new Pokemon[1000];
private int pokemonCount = 0;
#Override
public String toString()
{
// loop through pokedex
// add each item of the pokedex to the output variable
String output = new String();
for(Pokemon count : pokedex)
{
output += count;
}
return output;
}
public void addPokemon(Pokemon pokemon) {
}
}
Again here is the link to the whole program
#Override
public String toString() {
int pokemonCount = 0;
StringBuilder result = new StringBuilder();
for (Pokemon pokemon : pokedex) {
pokemonCount++;
result.append(pokemon.toString());
}
return new StringBuilder("Pokemon Count: ").append(pokemonCount).append("\n\n").append(result).toString();
A StringBuilder is the best option for adding many different strings together like you are doing with all the Pokemon. This code first finds how many pokemon there are. Then, it uses an enhanced for loop to add all the String representations of the Pokemon together into one string which is then returned along with the pokemon count.
I'm having an issue that has been giving me a an error saying java.lang.StackOverflowError: null. My program is sort of like a lottery, a random number is chosen, and based off the number, your item is chosen from a array. Now this works all handy and dandy, but when i try to insert the item received into an inventory. I get that error. Im pretty sure i set up my class wrong but i don't know how to construct an array in a separate class that receives data from another class, and returns the data back to the same class. Enough chit chatting, heres what my code looks like so far. (please dont mind the extra variables as this is a cropped portion of my code)
public class inventory {
private int inventorymain;
public String[] inventorymain() {
String[] inventorymain;
return inventorymain();
}
}
import java.util.Scanner;
import java.util.Random;
public class glue {
public static void main(String [] args) {
inventory inv = new inventory();
allskins a = new allskins();
Scanner s = new Scanner(System.in);
int selection = 0;
int invcount = -1;
Random rand = new Random();
do {
System.out.println(d.menue());
selection = s.nextInt();
if (selection == 1) {
invcount++;
int random = rand.nextInt(208);
System.out.println("You opend a: ");
System.out.println(a.allskins()[random]);
System.out.println("Your item has been put in your inventory, select inventroy from the menue to view all items.");
System.out.println("");
inv.inventorymain()[invcount] = (a.allskins()[random]);
}
}while (selection != 6);
}
}
Thank you
You're entering infinite recursive loop calling inventorymain()
public class inventory {
private int inventorymain;
public String[] inventorymain() {
String[] inventorymain;
return inventorymain(); // recursive call here without escape condition
}
}
It's better to keep the method name and variable name different to avoid such cases.
I have problem with my integer arrays, for example one. I have class with objects, and i have different class, where these objects are incremented after button click, but I got "null" values and NullPointerExpection. I had this all working, when i hade just, for example "int Money;", but my codes was 12000 lines, and i tried to make it easier to read, etc. But now with array they don't work. I got working this thing with For Loops , but how I understand, i can't make it with loops, because i want to later load these values from savefile.
CarMainClass (This one doesn't work) :
package Clicker;
public class MainHolder {
public Integer main[] = new Integer[8];
public MainHolder(){
}
public void MainMaker(int k){
}
public void MakeMain(){
MainMaker(0); // Money
MainMaker(0); // Money Clicks
MainMaker(0); // Boxes
MainMaker(0); // Boxes Clicks
MainMaker(1); // Boxes Level
MainMaker(1); // Player Level
MainMaker(1); // Garage Level
MainMaker(0); // Garage Slots
}
}
CarMainClass (That works, with for loop) :
package Clicker;
public class MainHolder {
public Integer main[];
public MainHolder(){
main = new Integer[8];
for(int i=0; i <8;i ++){
if(i ==4 || i ==5 || i ==6){
MainMaker(1,i);
}else{
MainMaker(0,i);
}
}
}
public void MainMaker(int k,int p){
main[p] = k;
}
public void MakeMain(){
}
}
And button :
//Money Button Click
if(ae.getSource() == jbtnMoney) {
CarMain.main[0] += 1;
MoneyLabel.setText("Money: " + CarMain.main[0]);
CarMain.main[1] += 1;
MoneyClicksLabel.setText("Money Clicks: " + CarMain.main[1]);
}
Application GUI when working : WorkingImage
Application GUI when dosn't work + error : NoWorkingImage
Is it a full code of CarMainClass? It seems that the method MainMaker doesn't contain any executable code so it doesn't do anything when you call it. The button click is ok.
The initialised array is empty - contains only null values and that is why it returns null - when you reference the value on the GUI.
You need to change it to this (I assume that each number describes object):
package Clicker;
public class MainHolder {
public Integer main[] = new Integer[8];
public MainHolder(){
MakeMain();
}
public void MainMaker(int k,int p){
main[p] = k;
}
public void MakeMain(){
MainMaker(0,0); // Money
MainMaker(0,1); // Money Clicks
MainMaker(0,2); // Boxes
MainMaker(0,3); // Boxes Clicks
MainMaker(1,4); // Boxes Level
MainMaker(1,5); // Player Level
MainMaker(1,6); // Garage Level
MainMaker(0,7); // Garage Slots
}
}
But your solution to use loops make actually more sense. Why you can't store it into a file? You should define the the integers which you use to describe the application as constants - final Integer money = 0 and so on.
You can store the values into a file and use the index to map the values to the corresponding values. Or store it as map.
Sorry if this is answered somewhere due to me missing something obvious, but I've been googling this for days now and it just doesn't seem to make any sense. I've got 3 years of experience in Javascript and am getting into Java now, so I'm not behind on the basic concepts of anything and such.
I'm using IntelliJ for this, but it fails to point out the problem. The communication (access rights and instantiations) between my classes is fine, the code syntax and variable types are as well, etc, so I really can't tell what it is.
I have a Data class, which just holds "read-only" data for the other classes to use.
public class Data {
// snip
public static int[][] specs = {
{6,1,6,40},
{5,2,5,30},
{5,3,4,40},
{4,4,3,60}
};
}
There's another class that has to read this data when it's initialized.
public class Soldier {
// snip
public int range;
public Soldier() {
int x = ...; // user input
range = Data.specs[x][1];
}
}
The specs array itself contains its data as defined (ie the array is not empty), x is valid as an index of the specs array (ie 0 <= x <= 3), its type is int and Test has read access to the specs array (all confirmed with debug output statements). And yet, when it tries to set the value of range (then and only then, at that exact point), I get the "Index out of bounds" error.
Can someone please tell me what's going wrong when trying to read the array? Or am I right in saying that this is really weird and I need to post the entire code?
Note: a small new test also shows that, if I change the code to first output a manually chosen value from the array and then set the value of range, the console prints the error statement (and exits the program) and follows it up by printing the manually picked value, but assigning the value and then asking to output range only throws the error... That makes absolutely no sense at all!
Edit: I've edited the code above. The class called Test is called Soldier in my code (I'm making a text-based game...). Below's the stack trace, if it's any good without the full code (which is way long). The basic structure of my program is this:
1) Boot contains the main method and instantiates a new Game
2) Game instantiates x Teams
3) each Team instantiates an Army
4) each Army instantiates x Soldiers
Each instance of the classes is set as an attribute of the instantiating class (public Army army; and an Army instantiation in the Team constructor, for example). It's essentially a cascade of constructors instantiating subsequent classes and assigning them as their attributes.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at Army.<init>(Army.java:13)
at Team.<init>(Team.java:19)
at Game.<init>(Game.java:22)
at Boot.main(Boot.java:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)5
Edit edit: here's the semi-full code (I'm leaving out the stuff that has absolutely nothing to do with it, including the imports). It's in no particular order and the classes are in separate .java files within the IntelliJ project. The game continues up to the point where a new Soldier asks for its type to be designated (the function performing the user input is working fine and validating the input as proven by a technically identical other part of the game).
public class Boot {
public static void main(String[] args) {
Object[] games = new Object[] {};
if (Lib.userConfirmPrompt("Start the game?") == true) {
do {
games[games.length] = new Game();
}
while (Lib.userConfirmPrompt("Do you want to play again?") == true);
}
System.exit(0);
}
}
public class Game {
public Object[] teams = new Object[] {};
public Game() {
for (int i = 0;i < settings.xbots + 1;i++) {
teams[teams.length] = new Team(this);
}
}
}
public class Team {
public Game game;
public Army army;
public Team(Game p) {
game = p;
army = new Army(this);
}
}
public class Army {
public Team team;
public static Object[] soldiers = new Object[] {};
public Army(Team p) {
team = p;
for (int i = 0;i < team.game.settings.xsoldiers;i++) {
soldiers[soldiers.length] = new Soldier(this);
}
}
}
public class Soldier {
private Army army;
public int sight;
public int range;
public int distance;
public int damage;
public Soldier(Army p) {
army = p;
int type = Lib.userTxtIntOptionsPrompt(Data.isoldiertypes);
// HERE is where it crashes, type is assigned and valid but the array access fails
sight = Data.isoldierspecs[type][0];
range = Data.isoldierspecs[type][1];
distance = Data.isoldierspecs[type][2];
damage = Data.isoldierspecs[type][3];
}
}
public class Data {
public static List isoldiertypes = Arrays.asList("Scout","Private","Machinegunner","Grenadier");
public static int[][] isoldierspecs = {
{6,1,6,40},
{5,2,5,30},
{5,3,4,40},
{4,4,3,60}
};
}
public class Lib {
private static Scanner input = new Scanner(System.in);
// output
// default: 1 query string to print
public static void outBase(String query) {
System.out.print(query);
}
public static void outStd(String query) {
outBase(query + "\n");
}
// end of output
// input
// default: 1 query string to print,
// query and input are in-line (exception: userConfirmPrompt prints query block-wise and default instruction in-line before input),
// keeps user hostage until valid input is given (exception: userPrompt returns blindly)
public static String userPrompt(String query) {
outBase(query);
return input.nextLine();
}
public static String userTxtPrompt(String query) {
String menuinput = null;
do {
if (menuinput != null) {
userHostage();
}
menuinput = userPrompt(query);
} while (menuinput.length() == 0);
return menuinput;
}
public static int userIntPrompt(String query) {
String menuinput = null;
do {
if (menuinput != null) {
userHostage();
}
menuinput = userTxtPrompt(query);
} while(menuinput.matches("^-?\\d+$") == false);
return new Integer(menuinput);
}
// end of input
// options input
// default: takes a List of options as argument,
// prints an enumerated list of these options string-wise,
// prompts for a numeral selection of the desired option and returns the number if valid
public static int userTxtIntOptionsPrompt(List options) {
int choice = 0;
Boolean chosen = false;
do {
if (chosen == true) {
userHostage();
} else {
chosen = true;
}
chosen = true;
for (int i = 0;i < options.size() - 2;i++) {
outStd((i + 1) + ") " + options.get(i) + ",");
}
outStd((options.size() - 1) + ") " + options.get(options.size() - 2) + "\nand " + options.size() + ") " + options.get(options.size() - 1) + ".");
choice = userIntPrompt("Enter the number of the option you'd like to select: ") - 1;
} while(choice < 0 || choice >= options.size());
return choice;
}
// end of options input
// miscellaneous
public static void userHostage() {
outStd("Invalid operation. Please try again.");
}
}
The problem is in your Army class:
public static Object[] soldiers = new Object[] {};
You initialize an empty (length == 0) array named soldiers, but later you access:
soldiers[soldiers.length] = new Soldier(this);
This causes the failure.
By definition, soldiers.length is out of the bound of the array (since the bound is from 0 to soldiers.length-1)
To overcome it - make sure you allocate enough space in the array soldiers or use a dynamic array (ArrayList) instead. You can append elements to an ArrayList using ArrayList.add(), and you don't need to know the expected size before filling it up.
The x should be greater than -1 and less than 4.
The stacktrace does not mention the Solder class, its in the conctructor of the Army class.
Any how, only knowing that the index should be within a range is not enough. As a programmer its your duty to validate the index before trying to access an element at that index.
if(index > 0 && index < array.length) {
//then only acess the element at index
Problem is the array soldiers is of size 0.
This line int x = ...; // user input implies that you are taking input in some fashion from the user and accessing the array with it. Are you checking this value to see that is in range (i.e., between 0 and 3)? If not, this may be why your testing works.
Edit: something like this might solve it for you:
public class Army {
public Team team;
public Vector<Soldier> soldiers;
public Army(Team p) {
soldiers = new Vector<Soldier>()
team = p;
for (int i = 0;i < team.game.settings.xsoldiers;i++) {
soldiers.add(new Soldier(this));
}
}
}
Judging by your other code, this sort of pattern will be useful in your Game object as well.