So basically I have a class with a constructor, especifically saying, a constructor for states. I can only create a new State if in the constructor I have a city type region(State has 2 constructors, both accept name and Region).
The code looks like this:
public State(String Name, int Population, Region Capital) throws IllegalArgumentException {
super(Name, Population);
if(!(Capital.getRegionType() == RegionType.CITY)){
System.out.println("ERROR");
throw new java.lang.IllegalArgumentException();
}
this.Capital = Capital;
}
The type of the region is defined using a Enum class. The problem is when I create a new function in the test class(main class)
Region3 = new Region("BedRock", 23423,RegionType.VILLAGE); //
try{
State s2 = new State("Khemed", Region3); // This should not be possible because Region3 is a VILLAGE instead of a CITY
}catch(IllegalArgumentException e){
}
s2.addRegion(Region2);//Doesn´t work - Error
s2.addRegion(Region1);//Doesn´t work - Error
That's basically my problem, the 2 last lines gives me a error saying I haven´t intialized the variable s2.
I tried running the code without "try and catch" to see if the if statement I have in the constructor would work but it doesn´t.
The method "add" is a method defined in the super class of state (Contry) which simply allows to add States to it.
Hope you can help because I can´t see how I can solve this.
ADDED (Requested to answer my question)
Class Region:
public class Region {
private String name;
private int population;
private RegionType regionType;
public Region(String name, int population, RegionType regionType){
this.name = name;
this.population = population;
this.regionType = regionType;
}
//get Region Type
public RegionType getRegionType(){
return regionType;
}
Enum with Region Type:
public enum RegionType {
CITY,
VILLAGE,
TOWN,
}
Your variable s2 is only defined in your try/catch block, try to put the 2 lines in the try/catch block.
But the best approach here is to avoid catching the exception IllegalArgumentException.
Region3 = new Region("BedRock", 23423,RegionType.VILLAGE); //
try{
State s2 = new State("Khemed", Region3);
s2.addRegion(Region2);
s2.addRegion(Region1);
}catch(IllegalArgumentException e){
}
First of all you must put 2 lines in to try/catch block. And your "State" constructor has 3 paramethers. But you are using another constructor(2 params):
State s2 = new State("Khemed", Region3); // 2 params
public State(String Name, int Population, Region Capital)// 3 params
Use with population param like this in try block:
Region3 = new Region("BedRock", 23423,RegionType.VILLAGE); //
try{
State s2 = new State("Khemed", 123,Region3);
s2.addRegion(Region2);
s2.addRegion(Region1);
}catch(IllegalArgumentException e){
}
In the second code block, s2 only has scope within the try block. Instead, declare s2 outside of the try.
Edit: That's what I get for posting too quickly. s2 statements should be in the try.
Region3 = new Region("BedRock", 23423,RegionType.VILLAGE);
State s2 = null;
try{
s2 = new State("Khemed", Region3);
s2.addRegion(Region2);
s2.addRegion(Region1);
}catch(EmptyStackException e){ //You should log this or something
}
Related
I'm working on a program for my Java class where I'm using a file of objects (clothing items) that represents inventory for a store. Each Retail_Item has four attributes: int itemNumber, String description, int numInInventory, and double price.
What I'm trying to figure out is how to read in each line from the file and turn each line into an object. My first thought was to create a while loop with vars like currentItemNumber, currentDescription, etc. So I tried this:
while (file.hasNextLine()) {
currentItemNumber = file.nextInt();
currentDescription = file.next
} // end while
But I got stuck there because every other time I've read in a String to a Scanner, I've always used nextLine. Can't use that here though, because each line contains multiple attributes of the object, not a String within a line. Is there a way to do this in the structure I'm trying to use, or should I be doing this a different way? I know I've seen and done some things where I parsed a String into separate pieces which I've seen people refer to as "tokens." Would people recommend reading each line in and then parsing it into separate tokens, then assigning each token to its appropriate attribute? Then I guess I'd have to cast those tokens into the appropriate object, since I think reading the whole line in and then parsing it would make each piece a String.
Here's a sample of what's in the text file (which can't be changed in any way, per the professor's instructions):
1000 Pants 10 19.99
2000 Jeans 2 25.95
3000 Shirt 12 12.50
Thanks in advance for your sage wisdom if you've got it.
The following code fulfills your requirement as stated in your question, namely how to create an instance of class RetailItem from a line of text from your text file. I presume it uses things that you may not have learned yet, like class Paths and try-with-resources. This is just used to scan through your file.
First, class RetailItem contains the members you described in your question. Next, I wrote a constructor for class RetailItem that creates a new instance and initializes the instance members. Then I wrote a toString() method that displays the contents of a RetailItem object in "human readable" form. Finally a main() method that reads your text file (which I named "clothes.txt"), line by line - using a Scanner. For each line read, the code splits it using a delimiter which consists of at least one whitespace character. (I presume you haven't yet learned about regular expressions in java.) Then I convert the elements of the String array returned by method split() into appropriate data types that are required by the RetailItem constructor. Then I call the constructor, thus creating an instance of class RetailItem (as you requested) and I print the created instance.
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Scanner;
public class RetailItem {
private static final int FIELDS = 4;
private int itemNumber;
private String description;
private int numInInventory;
private double price;
public RetailItem(int itemNumber, String description, int numInInventory, double price) {
this.itemNumber = itemNumber;
this.description = description;
this.numInInventory = numInInventory;
this.price = price;
}
#Override // java.lang.Object
public String toString() {
return String.format("%4d %-5s %2d %2.2f", itemNumber, description, numInInventory, price);
}
public static void main(String[] args) {
try (Scanner file = new Scanner(Paths.get("clothes.txt"))) {
while (file.hasNextLine()) {
String record = file.nextLine();
String[] fields = record.split("\\s+");
if (fields.length == FIELDS) {
int itemNumber = Integer.parseInt(fields[0]);
String description = fields[1];
int numInInventory = Integer.parseInt(fields[2]);
double price = Double.parseDouble(fields[3]);
RetailItem item = new RetailItem(itemNumber, description, numInInventory, price);
System.out.println(item);
}
}
}
catch (IOException xIo) {
xIo.printStackTrace();
}
}
}
I think the way that I would do is, like you said, parse each line into separate strings and then assign each piece to instance variables of the object you are building.
I have done something like this before, maybe it can be helpful.
Scanner fileScan;
File babyNameFile = new File("yob2015.txt");
try {
fileScan = new Scanner(babyNameFile);
} catch (FileNotFoundException e) {
System.out.println("File does not exist");
return;
}
String currentLine;
int numberOfGirlsNames = 0;
while (fileScan.hasNextLine()) {
String[] values;
currentLine = fileScan.nextLine();
values = currentLine.split(",");
if (values[1].equals("F")) {
numberOfGirlsNames = numberOfGirlsNames+1;
}
}
System.out.println("Number of female names was "+numberOfGirlsNames);
I have a fleet. fleet.java
Each fleet has a set of ships. ship.java
Each ship has a set of crewmembers. crewmember.java
Within Main I am adding Ships to the fleet and Crewmembers to the ships, read in from a roster of both.
From the first file I add a new ship to an arraylist.
From the second file I add a new crewmember to an arraylist.
this.addships(ship)
this.shipname.addcrewmember(crewmember)
How do I change the shipname in the above statement based on the token from the input file?
public void loadStarships( String filename ) {
File file = new File( filename );
Scanner scan;
try {
scan = new Scanner( file );
while( scan.hasNextLine() ) {
String line = scan.nextLine();
String[] tokens = line.split(",");
Starship star = null;
star = new Starship( tokens[0], tokens[1], tokens[2]);
this.addStarship( star );
}
scan.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void loadCrew( String filename ) {
File file = new File( filename );
Scanner scan;
try {
scan = new Scanner( file );
while( scan.hasNextLine() ) {
String line = scan.nextLine();
String[] tokens = line.split(",");
CrewMember member = null;
member = new CrewMember( tokens[0], tokens[1], tokens[2], tokens[4]);
this.tokens[3].addCrewMember( member );
}
scan.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Starship( String name, String registry, String level) {
this.name = name;
this.registry = registry;
this.level = level;
this.crewmembers = new ArrayList<CrewMember>();
}
//adds new crew members
public void addCrewMember( CrewMember crewmembers ) {
this.crewmembers.add( crewmembers );
this.numberOfCrewMembers++;
}
public CrewMember( String name, String position, String rank, String species ) {
this.name = name;
this.position = position;
this.rank = rank;
this.species = species;
}
//set the fleet name and the maximum number of starships
public Fleet(String name) {
this.name = name;
this.starships = new ArrayList<Starship>();
}
The first rule of software design is "use the correct data structure for the job." As it stands, you're saving instances of ship to an ArrayList, which only allows you to retrieve elements by index.
Although you didn't provide the sample data requested, it's easy enough to infer that token[3] is the name of the ship to which the crew member belongs, so you need to figure out how to retrieve an object by name.
Luckily, Java provides you with the HashMap, which stores key-value pairs. You can use the ship's name as a key. When you pass that key to the HashMap, it'll return the value associated with that key -- in your case, the instance of ship that you need.
1) Make sure your class imports java.util.HashMap;
2) Declare your HashMap. Instead of:
ArrayList<Starship> ships = new ArrayList<Starship>();
use:
HashMap<String, Starship> = new HashMap<String, Starship>();
In this situation, a String representing the name of the ship is the key. The instance of ship with that name is the value.
3) When adding a new ship, you're going to have to update your addStarship() method to take a String arg in addition to the Starship arg it already takes:
public void addStarship(String name, Starship ship)
4) In the body of addStarship() you have to add the ship using the put() method:
ships.put(name, ship);
Remember, here, ships is the instance of HashMap that you're using to store your ships. name is a String representing the name of the ship, and ship is the ship object.
5) When you're trying to retrieve the ship, you use the get() method:
ships.get(name);
In your case, the code might look like this:
ships.get(tokens[3].addCrewMember(member));
Keep in mind that with HashMap, you can no longer retrieve values by index like you could with ArrayList. HashMap is by definition, and unordered collection, meaning the first element of the structure may or may not be the the first object you added, and even if you accessed an object at the first position, there's no guarantee that it'll still be in that slot if you try to access it later -- its position in the HashMap may have changed, so you'll typically only be retrieving values using the key.
Please make sure you read the official documentation that I linked, above.
So I'm creating a logging program where a user enters the KM's and it saves it etc.
I take in four variables - start KM, end KM, start and end location. I'm new to java so I'm just wondering if anyone can confirm if theres a better way to do this. This is my code so far, I want to save it to an array of sorts (to a list??) so I can access each object i.e. the startKM, but they need to be on the same line, as in object 1 of array etc. and then write to file,
What I was thinking of doing was saving that linked list to a file, and adding a ; in the toString method and when reading the file in just breaking it at the ; Is there a better way to do this?? Thanks guys. the data is assigned from whatever the user enters in the text fields.
double startKM;
double endKM;
String startLocation;
String endLocation;
startKM = Double.parseDouble(txtStartKM.getText());
endKM = Double.parseDouble(txtEndKM.getText());
startLocation = txtStartLocation.getText();
endLocation = txtEndLocation.getText();
details.startKM = startKM;
details.endKM = endKM;
details.startLocation = startLocation;
details.endLocation = endLocation;
//List<DrivingDetails> detailsList = new ArrayList<DrivingDetails>();
List detailsList = new ArrayList();
detailsList.add(details);
System.out.println("LinkedList contains = \t " + detailsList.toString());
edit: I have another class (DrivingDetails) which holds the following variables:
public class DrivingDetails {
double startKM;
double endKM;
String startLocation;
String endLocation;
}
Your DrivingDetails class violates the principle of encapsulation for object oriented classes. I would add setters and getters for all properties. Also, you could create a contstructor that handles initialization for you.
public class DrivingDetails {
private double startKM;
private double endKM;
private String startLocation;
private String endLocation;
public DrivingDetails(double startKM, double endKM, String startLocation, String endLocation) {
this.startKM = startKM;
this.endKM = endKM;
this.startLocation = startLocation;
this.endLocation = endLocation;
}
public double getStartKM() {
return startKM;
}
public void setStartKM(double startKM) {
this.startKM = startKM;
}
// rest of the methods left for you ...
}
Your resulting code would then look like:
double startKM;
double endKM;
try {
startKM = Double.parseDouble(txtStartKM.getText());
endKM = Double.parseDouble(txtEndKM.getText());
} catch (NumberFormatException e | NullPointerException e) {
// the line above assumes java 7
// recover
}
DrivingDetails details = new DrivingDetails(startKM, endKM,
txtStartLocation.getText(),
txtEndLocation.getText());
List<DrivingDetails> detailsList = new ArrayList<DrivingDetails>();
detailsList.add(details);
Hope that helps!
public class Packages
{
private ArrayList shipmentList = new ArrayList();
private double totalWeight;
public Packages(String shiplist) throws IOException
{
Scanner scanFile = new Scanner(new File(shiplist));
scanFile.useDelimiter("\n");
while(scanFile.hasNext() == true){
String pack = scanFile.next();
Scanner splitter = new Scanner(pack);
splitter.useDelimiter(" ");
int id = splitter.nextInt();
double weight = splitter.nextDouble();
String state = splitter.next();
shipmentList.add(new Packet(id, weight, state));
}
this.totalWeight = 0;
}
public String toString()
{String allShipments ="";
for(int i =0;i<shipmentList.size();i++)
allShipments += shipmentList.get(i) + "\n";
return allShipments;
}
//needs work. Cannot find method isLight() from class packet, yet toString() fires fine.
public void displayLightPackages()
{
for (int i=0;i<shipmentList.size();i++){
Packet thisShipment = shipmentList.get(i);
if(thisShipment.isLight() == true){
System.out.println("Package: "+ shipmentList.get(i).toString()+" Is light.");
}else{
System.out.print("");
}
}
}
Method displayLightPackages() is giving me errors. here is the packet class:
public class Packet
{
// instance variables - replace the example below with your own
private int idNumber;
private double weight;
private String state;
public Packet(int idNumber, double weight, String state)
{
this.idNumber= idNumber;
this.weight = weight;
this.state = state;
}
public boolean isHeavy()
{
return (weight>10);
}
public boolean isLight()
{
return (weight<10);
}
public String toString()
{
return "ID: "+idNumber+" WEIGHT: "+weight+" STATE: "+state;
}
}
Method toString fires fine on a call from the main method, however, I cannot access any of the other methods from the Packet class. The constructor works when adding packets to the Arraylist containing all packets. I tried defining a packet in the displayLightPackages with
Packet thisShipment = shipmentList.get(i);
but I get an incompatible type error. When just using the code
shipmentList.get(i).isLight()
in the displayLightPackages method, I get an error where the compiler cannot find the symbol isLight. I suspect the error has something to do with the dataType in the arraylist, but other than that, i'm at a loss at this point.
Thank you
Your ArrayList isn't typed, so everything coming from it is an Object. Conversely, Object doesn't have an isLight() method, hence the "cannot find symbol" error.
To solve this, either type your ArrayList...
private ArrayList<Packet> shipmentList = new ArrayList<>();
... or cast to Packet when you use get:
((Packet)shipmentList.get(i)).isLight()
Of the two options, typing the ArrayList is simpler and safer, since you don't have to remember to cast every time you're getting a value from it.
Change
private ArrayList shipmentList = new ArrayList();
to
private ArrayList<Packet> shipmentList = new ArrayList<Packet>();
Compiler does not know that shipmentList holds Packets. In fact, compiler know that shipmentList is a list of an Objects. So you are able to do shipmentList.get(i).toString(), because toString() is method from Object class. But you can't invoke isLight() method on object because it doesn't exists in Object context. You must explictly say that shipmentList is type of ArrayList<Packet>, or cast element to Packet: Packet thisShipment = (Packet) shipmentList.get(i);
I am taking in an array of methods and I want to chain them together to modify an object that I am working in.
For example I start with
"getStuff().get(1).get(3).setMoreStuff().put(stuff,6)"
I split it into an array called methods, and clean up the parameters inside each method and I try to modify this.
Object res = this;
String[] methods = targetString.split("\\.(?=\\D)");
for (String m : methods){
List<Object> params = new ArrayList<Object>();
List<Object> params = new ArrayList<Object>();
for (String p : m.split("\\(|,|\\)")) {
try {
if (p.indexOf(".") != -1){
double tempD = Double.parseDouble(p);
params.add(tempD);
} else {
int tempP = Integer.parseInt(p);
params.add(tempP);
}
} catch (Exception ex) { //not a number
params.add(p);
}
}
switch (params.size()) {
case 1:
res = res.getClass().getMethod(
params.get(0)
).invoke(res);
break;
case 2:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass()
).invoke(res, params.get(1));
break;
case 3:
res = res.getClass().getMethod(
params.get(0),
params.get(1).getClass(),
params.get(2).getClass()
).invoke(res, params.get(1), params.get(2));
break;
}
in the end I notice that res has been modified the way that I expect. All the getters and setters are called correctly. But of course the underlying object "this" refers to has not been changed!
I guess I'm just calling the getters and setters of the copy I made in the first line!
now I can't just use
this.getClass().getMethod(...).invoke(...)
because I need to call the same getMethod on the object returned by this call.
To clarify:
Object res = this;
creates a "pointer" to this. So that when I call
res.getStuff().setStuff(foo)
this will also be modified.
but it seem that when I call
res = res.getStuff();
res = res.setStuff();
like I do in my loop,
this does not modify the underlying object this refers to?
Edit: Included more code as per request.
Edit2: added anther example, to clarify my problem.
Edit3: tried to add more code, its a bit hard to add a working program without including every class
Your general approach should be fine (although your approach to parameter conversion is somewhat ugly) - it's the specifics that are presumably causing you problems. Here's a short but complete program demonstrating calling methods and then seeing the difference afterwards:
import java.lang.reflect.*;
class Person {
private String name = "default";
public String getName() {
return name;
}
// Obviously this would normally take a parameter
public void setName() {
name = "name has been set";
}
}
class Test {
private Person person = new Person();
public Person getPerson() {
return person;
}
// Note that we're only declaring throws Exception for convenience
// here - diagnostic code only, *not* production code!
public void callMethods(String... methodNames) throws Exception {
Object res = this;
for (String methodName : methodNames) {
Method method = res.getClass().getMethod(methodName);
res = method.invoke(res);
}
}
public static void main(String[] args) throws Exception {
Test test = new Test();
test.callMethods("getPerson", "setName");
System.out.println(test.getPerson().getName());
}
}
The output is "name has been set" just as I'd expect. So see if you can simplify your code bit by bit, removing extra dependencies etc until you've got something similarly short but complete, but which doesn't work. I suspect you'll actually find the problem as you go.
Object does not change reference, its VALUE changes. So if you will call this.get("some key"), you will get value that the same value that you put using reflection.
Right?