I tried printStackTrace and I have coverted everything to static (I think)... however, lines 17 and line 38 are the problem... because of this error:
You picked up: Pickaxe
java.lang.NullPointerException
at item.addInv(item.java:38)
at item.main(item.java:17)
Description: Can be used to mine with.
Press any key to continue . . .
Line 17: anItem.addInv(1);
Line 38: arr.add("Dan");
And here is my code:
import java.io.*;
import java.util.*;
import javax.swing.*;
public class item
{
public static int attack, defense;
public static ArrayList<String> arr;
public static String name, desc, typeOf, attackAdd, defenseAdd, canSell, canEat,earnedCoins,canEquip;
String stats[];
public static void main(String args[])
{
item anItem = new item();
ArrayList<String> arr = new ArrayList<String>();
anItem.addInv(1);
}
public static void addInv(int e) {
String iname = getItem(1)[0];
String idesc = getItem(1)[1];
int itypeOf = Integer.parseInt(getItem(1)[2]);
int iattackAdd = Integer.parseInt(getItem(1)[3]);
int idefenseAdd = Integer.parseInt(getItem(1)[4]);
boolean icanSell = Boolean.parseBoolean(getItem(1)[5]);
boolean icanEat = Boolean.parseBoolean(getItem(1)[6]);
int iearnedCoins = Integer.parseInt(getItem(1)[7]);
attack = attack + iattackAdd;
defense = defense + idefenseAdd;
System.out.println("You picked up: " + iname);
try {
arr.add("Dan");
} catch(NullPointerException ex) {
ex.printStackTrace();
}
System.out.println("Description: " + idesc);
}
public static String[] getItem(int e) {
String[] stats = new String[7];
String name = "Null";
String desc = "None";
String typeOf = "0";
String attackAdd = "0";
String defenseAdd = "0";
String canSell = "true";
String canEat = "false";
String earnedCoins = "0";
if (e == 1) {
name = "Pickaxe";
desc = "Can be used to mine with.";
typeOf = "2";
attackAdd = "2";
earnedCoins = "5";
}
return new String[] { name, desc, typeOf, attackAdd, defenseAdd, canSell, canEat, earnedCoins};
}
}
As you can see, it's those lines and I don't know what to do... :\
When you call the add() method on arr, it's not been initialized yet, hence, the NullPointerException.
Since you'll probably use the ArrayList in other methods as well, you should have that initialized in the constructor; ie:
public item() {
arr = new ArrayList<String>();
}
Variable arr is not initialized.
Variable arr in main() is not the same arr in function addInv()
Just initialize it in addInv to fix it.
String canEat = "false"; Why are you converting to and from strings?
You seem to have muddled an item class an inventory class.
Perhaps an Enum would be better:
public enum InventoryItem
{
PICKAXE("Pickaxe", "Can be used to mine with", ItemType.Tool,
5, 2, 0)
EPIC_PICKAXE("Super mega awesome Pickaxe", "Can be used to mine with, but epically", ItemType.Tool,
1000000, 100, 0)
public static enum ItemType {
TOOL,
WEAPON
}
public final String name, description;
public final ItemType type;
public final boolean canSell, canEat, canEquip;
public final int earnedCoins, attackAdd, defenseAdd;
private InventoryItem(String name, String description, ItemType type
int earnedCoins, int attackAdd, int defenseAdd,
boolean canSell, boolean canEat, boolean canEquip)
{
this.name = name;
this.description = description;
this.type = type
this.canSell = canSell;
this.canEat = canEat;
this.canEquip = canEquip;
this.earnedCoins = earnedCoins;
}
private InventoryItem(String name, String description, ItemType type
int earnedCoins, int attackAdd, int defenseAdd)
{
this(name, description, type,
earnedCoins, attackAdd, defenseAdd,
true, false, true);
}
}
Then you can just have List<InventoryItem> inventory = new ArrayList<InventoryItem>() within your player's class, and directly interface with that.
A few tips (one that does directly solve the problem):
1) wherever possible declare variables as private, or at most protected. I personally never use the "default" which is package level access (anything in the same package can see it).
2) Only use public for immutable values. An immutable value is something that cannot be changed (all members are final is the best way to ensure that, or no method modifies any values after the object is constructed and the variables are all private).
3) whenever possible always declare variables to be final (class variables, instance variables, parameters, local variables).
The one tip that directly helps you here is #3. Since you never assigned a value to "arr" it is null. If you declared it as final the compiler would force you do actually assign it a value, if you do not the code won't compile.
Doing that little thing will save you hours of time as you start programming. In my case I did something similar, not exactly the same (really I violated #2 sort of in a round about way) and it cost me about a week. I have been programming in Java for over 15 years now... if I can waste a week because of something like this think of how much time you can waste :-)
Related
I'm trying to optimize a section of my code which requires an object array with constructor parameters in it. Is there a way to add that to the arguments of a method?
I have an array of objects called SongList in that array there are objects from the Song Class with constructor parameters:
songs[] songList = new songs[1];
songList[0] = new songs("Danger Zone", "danger zone.mp3", "Kenny Loggins", 3.33);
I also have a method that searches the array based on the category and the search query:
//Method
public static songs[] search(songs SearchCategory , String Quarry){}
//Calling of method
search = AudioPlayer.search("aName", "Kenny Loggins");
Songs class:
public class songs {
String sName;
String fPath;
String aName;
double sLength;
public songs(String songName,
String filePath,
String Artist,
double songLength) {
sName = songName;
fPath = filePath;
aName = Artist;
sLength = songLength;
}
}
Is there a way I could make the first argument of the code accept a constructor parameter like Name? This would allow me to cut down the overall length of my code as I wouldn't need to use a switch statement.
Search method:
public static songs[] search(String SearchCategory , String Quarry){
//Returned array value
songs[] ReturnedResult = new songs[0];
// Method only list
List<songs> SearchResult = new ArrayList<songs>();
switch (SearchCategory) {
case "aName":
//for loop looks through all objects with the SearchCategory and places any found values into the list
for (songs songs : AudioListing) {
if (songs.aName.equals(Quarry)) {
SearchResult.add(songs);
}
}
case "sName":
for (songs songs : AudioListing) {
if (songs.sName.equals(Quarry)) {
SearchResult.add(songs);
}
}
case "fPath":
for (songs songs : AudioListing) {
if (songs.fPath.equals(Quarry)) {
SearchResult.add(songs);
}
}
case "sLength":
//Since the given quarry is a string and the length is a double the quarry is converted
double QuarryDoubleTypeC = Double.parseDouble(Quarry);
for (songs songs : AudioListing) {
if (songs.sLength == QuarryDoubleTypeC) {
SearchResult.add(songs);
}
}
}
// Conversion of list to array for ease of use
ReturnedResult = SearchResult.toArray(ReturnedResult);
return ReturnedResult;
}
There is a concept of reflection in Java that you can use here.
You can use the SearchCategory to get the field value from the object
Then you can use it to compare with Quarry
The working code is as below
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Songs {
String sName;
String fPath;
String aName;
double sLength;
static Songs[] AudioListing = new Songs[1];
static {
AudioListing[0] = new Songs("Danger Zone", "danger zone.mp3", "Kenny Loggins", 3.33);
}
public Songs(String songName, String filePath, String Artist, double songLength) {
sName = songName;
fPath = filePath;
aName = Artist;
sLength = songLength;
}
public static Songs[] search(String SearchCategory, String Quarry) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
// Returned array value
Songs[] ReturnedResult = new Songs[0];
// Method only list
List<Songs> SearchResult = new ArrayList<Songs>();
for (Songs song : AudioListing) {
Field field = Songs.class.getDeclaredField(SearchCategory);
String fieldValue = (String) field.get(song);
if (fieldValue.equals(Quarry)) {
SearchResult.add(song);
}
}
// Conversion of list to array for ease of use
ReturnedResult = SearchResult.toArray(ReturnedResult);
return ReturnedResult;
}
#Override
public String toString() {
return "Songs [sName=" + sName + ", fPath=" + fPath + ", aName=" + aName + ", sLength=" + sLength + "]";
}
public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
//Calling of method
Songs[] results = Songs.search("aName", "Kenny Loggins");
System.out.println(Arrays.toString(results));
}
}
This explains how it can be achieved you can further enhance your code after further exploring in this direction.
This is an excellent opportunity to leverage higher-order functions.
In Java, these are realized via Functional Interfaces.
You can reference the methods -- or fields -- from your Song class (which should be capitalized and singular, not songs) itself via Songs::aName. Furthermore, if you are trying to find a value, leveraging Predicate<Song> is an excellent idea.
Also, using Collections instead of arrays is advisable.
In short, your code could easily look like this:
class AudioPlayer {
List<Song> audioListings = new ArrayList<>();
public void add(Song song) { audioListings.add(song); }
public List<Song> search(Predicate<Song> predicate) {
return audioListings.stream()
.find(predicate)
.collect(Collectors.toList());
}
}
You would then use it like this:
AudioPlayer player = new AudioPlayer();
// fill with songs
player.add(new Song("Danger Zone", "danger zone.mp3", "Kenny Loggins", 3.33));
// find song with a specific aName
var songs = player.search(song => song.aName.equals("Kenny Loggins"));
The added benefit is that you can search for very complex things by constructing more complex predicates:
// find song with specific aName AND shorter then a given length
Predicate<Song> query =
song => song.aName.equals("Kenny Loggins")
.and(song => song.sLength <= 3.5);
var songs = player.search(query);
I would advise against using reflection for this. Reflection comes with a whole range of problems and it simply isn't needed. The approach I have outlined above is far more idiomatic Java since Java 8, scales better, is easier to read, less error-prone and overall cleaner.
What you're looking for is a bit advanced; it's the interface Function<Song, String>. This will allow you to provide some transformation that selects a string value for your Song object, particularly in this case such options as Song::getSName. This is how it would be done with streams (and collections):
songList.stream()
.filter(song -> quarry.equals(function.apply(song)))
.findAll();
However, I strongly recommend that you become more familiar with the basics of Java before diving into more complicated logic, especially standards about naming (classes should be capitalized; variables should not), collections (lists are usually preferred over arrays), static vs. instance members, and interfaces.
This question already has answers here:
Java : Best way to pass int by reference
(7 answers)
Closed 5 years ago.
I have a program which is meant to be a client/server game question game. I've made it as far as accounting various cases of the client/server sending a termination command for the end of the game.
Now, my issue is that I have a set of primitive int points, attempts, correct which are read by the client from the server in a String as below:
N.B. I do know that Java functions pass parameters by value, not reference, and that assigning the value inside of the function will not change the value of the original.
int points = accepted = correct = 0;
String inbound = check (inbound, points, accepted, correct);
System.out.println(points); // Displays value of 0, when expecting > 0
private static String check (String str, int points, int attempts, int correct) {
// Expect Q QuestionString
if (str.substring(0,1).equals("Q")) {
//System.out.println("This is the question.");
return str.substring(2, str.length());
}
String[] input = str.split(" ");
// Expect EX # # #
if (input[0].contains("EX")) {
points = Integer.parseInt(input[1]);
attempts = Integer.parseInt(input[2]);
correct = Integer.parseInt(input[3]);
return "EX";
}
// Expected strings: Correct..., Incorrect.
return str;
}
I am unsure how to workaround this issue without jeopardizing encapsulation or hindering other concepts.
Create a wrapper class to contain those three integer parameters then simply pass an instance of that wrapper to the check method and then modify its contents within the method.
example:
public class Wrapper
{
private int points;
private int attempts;
private int correct;
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
public int getAttempts() {
return attempts;
}
public void setAttempts(int attempts) {
this.attempts = attempts;
}
public int getCorrect() {
return correct;
}
public void setCorrect(int correct) {
this.correct = correct;
}
}
thus the first part of your code will become:
Wrapper wrapper = new Wrapper();
String inbound = check (inbound, wrapper);
System.out.println(wrapper.getPoints());
and your check method becomes:
private static String check (String str, Wrapper wrapper) {
...
...
if (input[0].contains("EX")) {
wrapper.setPoints(Integer.parseInt(input[1]));
wrapper.setAttempts(Integer.parseInt(input[2]));
wrapper.setCorrect(Integer.parseInt(input[3]));
return "EX";
}
...
...
}
I'd like to point out that I'm very new to Java, which is why I may be making stupid mistakes.
I have a class called "Characters", which consists of 4 variables and multiple methods. All variables are private, so from what I've read, I need to use methods to do anything to them.
One of the methods is supposed to return one of the variables in string form, however I keep getting an error from both eclipse and when I run it. "This method must return a result of type "String". The error occurs on the first line of the method:
public String displayStats(String option) {
switch (option) {
case "charName":
System.out.println(charName);
return charName;
case "charHealth":
System.out.println(charHealth);
String charHealth2 = Integer.toString(charHealth);
return charHealth2;
case "charMana":
System.out.println(charMana);
String charMana2 = Integer.toString(charMana);
return charMana2;
case "charStamina":
System.out.println(charStamina);
String charStamina2 = Integer.toString(charStamina);
return charStamina2;
default:
System.out.println("Error on default");}
}
}
The full class:
package basics;
public class Characters {
private String charName = "";
private int charHealth = 0;
private int charMana = 0;
private int charStamina = 0;
public void summoner(Characters player) {
player.charName = "Summoner";
player.charHealth = 80;
player.charMana = 150;
player.charStamina = 50;}
public void sentinel(Characters player) {
player.charName = "Sentinel";
player.charHealth = 200;
player.charMana = 50;
player.charStamina = 100;}
public void beserker(Characters player) {
player.charName = "Beserker";
player.charHealth = 100;
player.charMana = 0;
player.charStamina = 200;}
public void mage(Characters player) {
player.charName = "Mage";
player.charHealth = 80;
player.charMana = 200;
player.charStamina = 20;}
public String displayStats(String option) {
switch (option) {
case "charName":
System.out.println(charName);
return charName;
case "charHealth":
System.out.println(charHealth);
String charHealth2 = Integer.toString(charHealth);
return charHealth2;
case "charMana":
System.out.println(charMana);
String charMana2 = Integer.toString(charMana);
return charMana2;
case "charStamina":
System.out.println(charStamina);
String charStamina2 = Integer.toString(charStamina);
return charStamina2;
default:
System.out.println("Error on default");}
}
}
You aren't returning anything in the default case of your switch statement, which means that there is a possibility (however small) that the method won't know what to return.
In the displayStats function you don't return a String in all paths of your code.
This is because the default doesn't return at all.
Maybe you wanted to write:
default:
return "Error on default";
Two problems: charName is a string, but charHealth, charMana, and charStamina are ints. Thus, your displayStats function isn't always returning a string.
Also, your default option in your switch statement should return a string as well.
It would be better to create an accessor function for each variable:
public String getCharName() {
return charName;
}
public int getCharHealth() {
return charHealth;
}
etc.
The method displayStats must always return a String or throw an exception. Since the code implies that the default case is an error, then throw an exception. At this point rather than create a new class of exception, just throw an IllegalArgumentException -- new IllegalArgumentException(option). When printed out it will state the type of exception and the value of the invalid option.
I am having issues with objects and classes.
I had to define two classes:
Course: a course has a code, an name and a number of credits
Teacher: a teacher has a first name and last name. He can be asked his full name.
So far so good, I got no issue with them, but I have to do next assignment which I was trying to do in the last 2 days and I could not find a proper answer:
Extend the code of the class teacher. A teacher also has a list of courses he can teach. Add an array of Courses to the code. Also add a function addCourse(Course aCourse) to the code. Courses can also be removed from teachers.
I could do everyting in my way but no clue on how to create the addCourse(Course aCourse) method.
Find below my coding, but it must be according to the method described:
public class Course {
private String courseCode;
private String courseName;
private String numberOfCredits;
public Course(String courseCode, String courseName, String numberOfCredits) {
super();
this.courseCode = courseCode;
this.courseName = courseName;
this.numberOfCredits = numberOfCredits;
}
public void print() {
System.out.println(courseCode + "\t" + courseName + "\t" + numberOfCredits);
}
public static void main(String[] args) {
Course[] courseArray = new Course[4];
System.out.println("Code" + "\t" + "Name" + "\t" + "Credits");
courseArray[0] = new Course("001", "Hist", "3");
courseArray[1] = new Course("002", "Phy", "3");
courseArray[2] = new Course("003", "Math", "3");
courseArray[3] = new Course("004", "Log", "3");
for (int i = 0; i < courseArray.length; i++) {
courseArray[i].print();
}
}
}
Arrays are fixed length collections of objects, so you'll need to decide how big your array should be. Let's call the length of your array MAX_COURSES. A more advanced solution might resize the array when required, but I get the impression this is beyond the scope of your course.
So you need to define the Course[] array as a field of your Teacher class. The syntax of array declarations is quite easy to research, so I won't put that in here. Just make sure your array length is equal to MAX_COURSES.
Now, to add courses to the array, you need to know where to put them. To keep track of the next free position of the array, the easiest thing to do is to declare a field in your class:
private int numCourses = 0;
Now, when you add a new course, insert the course into the index specified by numCourses. Make sure you increment numCourses after you've added the course.
Finally, you ought to test to see if your array is full before you agree to insert a new course into the array, i.e. check if numCourses is smaller than MAX_COURSES. If it's not, you need to throw an exception.
I would recommend using a collection (such as a List) rather than an array. The code would look something like:
public class Teacher {
private final String firstName;
private final String lastName;
private final List<Course> courses = new ArrayList<Course>();
public Teacher(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public void addCourse(Course course) {
courses.add(course);
}
}
Based on that example, you should be able to add the removeCourse method yourself, and any other method you need to operate on the list of courses.
If you want to return the list as an array, you could always convert it, e.g:
public Course[] getCourses() {
return courses.toArray(new Course[courses.size()]);
}
If you really need to use an array for the data structure based on your assignment, something you can try when adding and removing courses, is to construct a list from the array of courses, add or remove a course from that list, the convert the list back to an array of courses.
There's really 3 options here.
Option 1
If you're allowed to use List constructs:
private List<Course> courses = new ArrayList<Course>();
public void addCourse(Course aCourse)
{
if (aCourse == null)
{
return;
}
courses.add(aCourse);
}
Option 2
The uses arrays, but it doesn't scale. Assume that a teacher can only have a maximum of X courses, in my example 10:
// Yes, I stole Duncan's variable names
private final int MAX_COURSES = 10;
private int numCourses = 0;
private Course[] courses = new Course[MAX_COURSES];
public void addCourse(Course aCourse) {
if (aCourse == null)
{
return;
}
if (numCourses >= courses.length)
{
return;
}
courses[numCourses] = aCourse;
numCourses++;
}
Option 3
This is identical to the previous item, but is a bit smarter in that it can resize the array... by creating a new one using the static method Arrays.copyOf
// Yes, I stole Duncan's variable names
private final int MAX_COURSES = 10;
private int numCourses = 0;
private Course[] courses = new Course[MAX_COURSES];
public void addCourse(Course aCourse) {
if (aCourse == null)
{
return;
}
if (numCourses >= courses.length)
{
int size = courses.length * 2;
courses = Arrays.copyOf(courses, size);
}
courses[numCourses] = aCourse;
numCourses++;
}
This question already has answers here:
How to return multiple objects from a Java method?
(25 answers)
Closed 7 years ago.
I am using a simulator to play craps and I am trying to return two values from the same method (or rather I would like to).
When I wrote my return statement I simply tried putting "&" which compiled and runs properly; but I have no way of accessing the second returned value.
public static int crapsGame(){
int myPoint;
int gameStatus = rollagain;
int d1,d2;
int rolls=1;
d1 = rollDice();
d2 = rollDice();
switch ( d1+d2 ) {
case 7:
case 11:
gameStatus = win;
break;
case 2:
case 3:
case 12:
gameStatus = loss;
break;
default:
myPoint = d1+d2;
do {
d1=rollDice();
d2=rollDice();
rolls++;
if ( d1+d2 == myPoint )
gameStatus = win;
else if ( d1+d2 == 7 )
gameStatus = loss;
} while (gameStatus == rollagain);
} // end of switch
return gameStatus & rolls;
}
When I return the value as:
gameStatus=crapsGame();
It appropriately sets the varaible to win or lose but if I try something as simple as following that statement with:
rolls=crapsGame();
It is assigned the same value as gamestatus...a 0 or a 1 (win or lose).
Any way that I can access the second returned value? Or is there a completely different way to go about it?
Create your own value holder object to hold both values, then return it.
return new ValueHolder(gameStatus, rolls);
It's possible to return an array with multiple values, but that's cryptic and it does nothing for readability. It's much easier to understand what this means...
valueHolder.getGameStatus()
than what this means.
intArray[0]
returning gameStatus & rolls means "return the bitwise and of gameStatus and rolls" which probably is not what you want
you have some options here:
return an array
create a class that represents the response with a property for each value and return an instance
use one of the many java collections to return the values (probably lists or maps)
You can return an array of values or a Collection of values.
Is it possible to return more than one value from a method in Java?
No it is not. Java allows only one value to be returned. This restriction is hard-wired into the language.
However, there are a few approaches to deal with this restriction:
Write a light-weight "holder" class with fields for the multiple values you want to return, and create and return an instance of that class.
Return a Map containing the values. The problem with this (and the next) approach is that you are straying into an area that requires runtime type checking ... and that can lead to fragility.
Return an array containing the values. The array has to have a base type that will accommodate the types of all of the values.
If this is a method on an object, then add some fields on the same object and methods that allow the caller to pick up "auxiliary results" from the last call. (For example, the JDBC ResultSet class does this to allow a client to determine if the value just retrieved was a NULL.) The problem is that this makes the class non-reentrant at the instance level.
(You could even return extra results in statics, but it is a really bad idea. It makes the class non-reentrant across all instances, not to mention all of the other badnesses associated with misused statics.)
Of these, the first option is the cleanest. If you are worried about the overhead of creating holder instances, etc, you could consider reusing the instances; e.g. have the caller pass an existing "holder" to the called method into which the results should be placed.
The best practice for an OOP approach is to return an Object. An object that contains all the values you want.
Example:
class Main {
public static void main(String[] args) {
MyResponse response = requestResponse();
System.out.println( response.toString() );
}
private static MyResponse requestResponse() {
return new MyResponse( "this is first arg", "this is second arg" );
}
}
class MyResponse {
private String x, y;
public MyResponse( String x, String y ) {
this.x = x;
this.y = y;
}
#Override
public String toString() {
return "x: " + x + "\t y: " + y;
}
}
If you want an even more scalable approach then you have to use JSON responses. (let me know if you want an example with JSON too)
You can following ways to do this:
Use a Container class, for example
public class GameStatusAndRolls {
String gameStatus;
String rolls;
... // constructor and getter/setter
}
public static GameStatusAndRolls crapsGame(String gameStatus, String rolls) {
return new GameStatusAndRolls(gameStatus, rolls);
}
public static void main(String[] args) {
...
GameStatusAndRolls gameStatusAndRolls = crapsGame(gameStatus, rolls);
gameStatusAndRolls.getGameStatus();
Use List or an array, for example
public static List<Integer> crapsGame(String gameStatus, String rolls) {
return Arrays.asList(gameStatus, rolls);
}
private static final int GAME_STATUS = 0;
private static final int ROOLS = 0;
public static void main(String[] args) {
...
List<Integer> list = crapsGame(gameStatus, rolls);
... list.get(0)...list.get(GAME_STATUS);
... list.get(1)...list.get(ROOLS);
or
public static String[] crapsGame(String gameStatus, String rolls) {
return new String[] {gameStatus, rolls};
}
private static final int GAME_STATUS = 0;
private static final int ROOLS = 0;
public static void main(String[] args) {
...
String[] array = crapsGame(gameStatus, rolls);
... array[0]...array[GAME_STATUS];
... array[1]...array[ROOLS];
Use Map, for example
public static Map<String, String> crapsGame(String gameStatus, String rolls) {
Map<String, String> result = new HashMap<>(2);
result.put("gameStatus", gameStatus);
result.put("rolls", rolls);
return result;
}
public static void main(String[] args) {
...
Map map = crapsGame(gameStatus, rolls);
... map.get("gameStatus")...map.get("rolls");