0

So for part of my assignment I have to pull information from a file outside of Java. I have already gotten that part done. The problem is that I am not sure how to actually put the strings from the files into a variable or loop that will work for the next part. In the following code I need to replace the part of the code that have that says Item = Tomato... with singular lines from the outfile. I am not sure how to do this. My major concern would be making sure it was not hardcoded for each line, I am guessing it will involve looping through each line in some way or form. Any help would be great.

How I originally added the items in hardcoded, as opposed to what I want to do which is input them from an outfile:

    list.add(new Item("Ketchup", 1.00, 10, 2.00, itemType.FOOD));
    list.add(new Item("Mayo", 2.00, 20, 3.0, itemType.FOOD));
    list.add(new Item("Bleach", 3.00, 30, 4.00, itemType.CLEANING));
    list.add(new Item("Lysol", 4.00, 40, 5.00, itemType.CLEANING));

Code

    Scanner s = new Scanner(new File("inventory.out"));

    ArrayList<String> inventoryList = new ArrayList<String>();

    while (s.hasNext()){
        inventoryList.add(s.next());
    }
    s.close();

    System.out.println(inventoryList);

    String item = "Tomato,30,1.25,6.50";// input String like the one you would read from a file

    String delims = "[,]"; //delimiter - a comma is used to separate your tokens (name, qty,cost, price)

    String[] tokens = item.split(delims); // split it into tokens and place in a 2D array.

    for (int i=0; i < 4; i++) {
        System.out.println(tokens[i]); // print the tokens.
    }

    String name = tokens[0]; System.out.println(name);

    int qty = Integer.parseInt(tokens[1]);System.out.println(qty);

    double cost = Double.parseDouble(tokens[2]);System.out.println(cost); 

Console output right now:

[Ketchup,1.00,10,2.00,itemType.FOOD, Mayo,2.00,20,3.00,itemType.FOOD, Bleach,3.00,30,4.00,itemType.CLEANING, Lysol,4.00,40,5.00,itemType.CLEANING]

Contents of the outfile:

Ketchup,1.00,10,2.00,itemType.FOOD
Mayo,2.00,20,3.00,itemType.FOOD
Bleach,3.00,30,4.00,itemType.CLEANING
Lysol,4.00,40,5.00,itemType.CLEANING

3 Answers 3

1

You need to have a clear strategy.

Your input consists of lines, which in turn consist of fields. You are (presumably) aiming to process the data as "records". You can do it a couple of ways:

  1. Use the scanner to read lines, and split / scan / tokenize each line into record fields.
  2. Scan the entire input stream as a sequence of tokens or values, and reassemble the records on the fly.

Either approach will work. But you need to decide which approach you are going to take ... and stick to that approach.

(If you just start writing or copying code without a clear strategy, you are liable to end up with a mess, or code that you don't understand, or both.)

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the reply. And I believe the first approach is what I am trying to do. I edited my original post to show how I was originally hard coding items in in the first place to better show what I mean.
If you trying to do it the first way, then you have coded it incorrectly. Your first loop needs to read lines not tokens, and the list needs to hold lines not individual tokens. Look at the javadoc for Scanner.readLine
0

Try removing String item = "Tomato,30,1.25,6.50"; and replacing all the 'item's after that with inventoryList.get(thepositionatwhichyouwanttogetanitemfrom);

4 Comments

What would be my options in regard to what the position in which i want to get the item from
That would be which line in the file the item came from. And do upvote and accept my answer if you think this helps.
I still do not get how this really works. Thank for your help by the way
.get is an ArrayList function. I suggest learning what ArrayLists are before continuing. And do upvote and accept my answer if you think this helps.
0

Implementation

public static void main(String[] args) throws IOException {
    Path path = Paths.getPath("inventory.out");
    List<Item> items = readItems(path);
    for (Item item : items) {
        System.out.printf("Item (name='%s', capacity=%d,  cost=%f, price=%f)\n",
            item.getName(), item.getCapacity(), item.getCost(), item.getPrice());
    }
}
public class Item {
    private final String name;
    private final int quantity;
    private final double cost;
    private final double price;

    public Item (String name, int capacity, double cost, double price) {
        this.name = name;
        this.capacity = capacity;
        this.cost = cost;
        this.price = price;
    }

    // Getters omitted.
}

public class ItemUtils {
    /**
     * Read all lines from a file and maps them to items.
     *
     * @param path the path to the file, non-null
     * @return the list of items read from the file
     * @throws IOException if an I/O error occurs reading from the file or a malformed or unmappable byte sequence is read
     * @throws CustomRuntimeException if a line can't be mapped to an item
     */
    public static List<Item> readItems(Path path) throws IOException {
        Objects.requireNonNull(path);

        return Files.readAllLines(path, StandardCharsets.UTF_8)
            .stream()
            .map(ItemUtils::mapStringToItem)
            .collect(Collectors.toList());

    }

    /**
     * Maps a string to an item.
     *
     * @param str the string to map, non-null
     * @return the mapped item
     * @throws CustomRuntimeException if the string can't be mapped to an item
     */
    private static Item mapStringToItem(String str) {
        String[] tokens = str.split(",");

        if (tokens.length != 4) {
            String msg = String.format("Invalid item: 4 tokens expected, %d tokens found", tokens.length);
            throw new CustomRuntimeException(msg);
        }

        try {
            String name = tokens[0];
            int quantity = Integer.parseInt(tokens[1]);
            double cost = Double.parseDouble(tokens[2]);
            double price = Double.parseDouble(tokens[3]);
            return new Item(name, quantity, cost, price);
        } catch (NumberFormatException e) {
            throw new CustomRuntimeException("Invalid item: Type conversion failed", e);
        }
    }

    private ItemUtils() {
        // Utility class, prevent instantiation.
    }
}

/**
 * A custom runtime exception. Should be renamed to a more specific name.
 */
public class CustomRuntimeException extends RuntimeException {
    public CustomRuntimeException(String msg) {
       super(msg);
    }

    public CustomRuntimeException(String msg, Throwable e) {
        super(msg, e);
    }

Explanation

The readLines method uses Files.readAllLines(...) to read all lines into a list of strings, where each string corresponds to a single line. Then I process the strings of this list with the Java 8 Stream API, the list class provides a stream() method returning a Stream<String>:

If you want to perform some actions on a collections object for example: filtering, sorting or manipulating each element on that object based on some condition, you can use the java 8 stream feature to complete your requirement easily with less code.

Here you can find a more practical explanation of streams.

The stream's map(...) method takes the method reference of mapStringToItem as its argument. When you look at mapStringToItem's signature you see it takes a single string as an argument and returns an Item object. So you can read the .map(...) invocation as "map each line from the file to an item using the method mapStringToItem". Then I collect all items from the stream and put them into a new list with the collect(...) method.

Lets have a look at the mapStringToItem method, which is using your approach of splitting the items values: First we split the line at each , returning an array of strings. Currently the item class consists of 4 attributes which should be read: The name, the capacity, the cost and the price. So we check if the string array has the appropriate length, if not this implementation throws an exception. If we have 4 strings (splittet by ,) we can start parsing the string values to the appriate data types, throwing an exception if the type conversion fails. Last but not least we return an item with the parsed values.

Comments

Note that I would advice against using floating point variables to store money values. Have a look at Joda-Money.

It might be worth to search for libraries which handle the serialization of your data classes for you. If you don't mind changing your format to JSON jackson-databind or similar libraries can be a solution.

18 Comments

Thank you for the lengthy and well thought out reply. I am a little confused however. Is this something that I would want to put into a new class entirely of its own, or multiple new ones. I guess i am just a little confused about the actual implementation of the of the code. Thanks again for all of your help.
I think i am figuring it out a bit
Update: Still pretty confused getting a lot of errors
@Victor Alam My intention was to split my code into classes with single responsibilities to make the code more robust. If you change for example your strategy of saving your items (e.g. JSON format, database, ...) you only have to look into the ItemUtils class (probably a bad name, doesn't describe the classes intend).
@Victor Alam The code leaves out some details. You need to implement the Item's constructor and getters as well as the CustomRuntimeException. Does that help you?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.