Search code examples
javaloopswriter

For loop to write data to file Java


I need to implement a method called saveWorksToFile according to the Javadoc in the code. The format of the output written to the file should be the following this pattern:

enter image description here

where ARTIST_NAME is the name of the artist, NUM_WORKS is the number of works of that artist, and WORK_1, WORK_2, etc. are the toString representations of each of that artist's works.

The last work should not have a line separator after it.

If an artist has no works, then the first three lines of the above format should be written, where the “-----” line has a line separator after it.

And this is the code I have:

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;

public class Artist {

    static class Work {
        String name; // e.g. "Mona Lisa"
        int yearCreated; // e.g. 1506
        String medium; // e.g. "Oil on poplar panel"

        public Work(String name, int yearCreated, String medium) {
            this.name = name;
            this.yearCreated = yearCreated;
            this.medium = medium;
        }

        public String getName() { return name; }
        public int getYearCreated() { return yearCreated; }
        public String getMedium() { return medium; }

        @Override
        public String toString() {
            return name + "|" + yearCreated + "|" + medium;
        }
    }

    private String name; // e.g. "Henri Matisse"
    private List<Work> works = new ArrayList<>();

    public Artist(String name) {
        this.name = name;
    }

    public void addWork(Work work) {
        this.works.add(work);
    }

    /**
     * Writes the toString representation of each of this artist's works to the
     * given writer. Also writes header lines containing the artist's name and
     * number of works.
     *
     * If an IOException occurs, the message "IOException occurred" should be
     * printed to System.out.
     *
     * @param writer writer to write this artist's works to
     */
    public void saveWorksToFile(Writer writer) {
        // write your code here
        try {
            BufferedWriter buffer = new BufferedWriter(writer);  
            buffer.write(this.name);            
            buffer.newLine();
            buffer.write("works: " + this.works.size());
            
            buffer.close();
        }
        catch (IOException e) {
            System.out.println("IOException occurred");
        }
    }
}

I got these errors:

=> org.junit.ComparisonFailure: The expected value is: Vincent van Gogh[newline]works: 0[newline]-----[newline] expected:<...nt van Gogh
=> org.junit.ComparisonFailure: The expected value is: Vincent van Gogh[newline]works: 0[newline]-----[newline] expected:<...nt van Gogh
=> org.junit.ComparisonFailure: The expected value is: Vincent van Gogh[newline]works: 0[newline]-----[newline] expected:<...nt van Gogh
=> org.junit.ComparisonFailure: The expected value is: Claude Monet[newline]works: 2[newline]-----[newline]Bridge over a Pond of Water Lilies|1899|Oil on canvas[newline]Impression, Sunrise|1872|Oil on canvas expected:<...laude Monet
=> org.junit.ComparisonFailure: The expected value is: Claude Monet[newline]works: 2[newline]-----[newline]Bridge over a Pond of Water Lilies|1899|Oil on canvas[newline]Impression, Sunrise|1872|Oil on canvas expected:<...laude Monet
=> org.junit.ComparisonFailure: The expected value is: Henry Matisse[newline]works: 1[newline]-----[newline]Woman with a Hat|1905|Oil on canvas expected:<...nry Matisse
=> org.junit.ComparisonFailure: The expected value is: Henry Matisse[newline]works: 1[newline]-----[newline]Woman with a Hat|1905|Oil on canvas expected:<...nry Matisse
=> org.junit.ComparisonFailure: The expected value is: Henry Matisse[newline]works: 1[newline]-----[newline]Woman with a Hat|1905|Oil on canvas expected:<...nry Matisse
=> org.junit.ComparisonFailure: The expected value is: Claude Monet[newline]works: 2[newline]-----[newline]Bridge over a Pond of Water Lilies|1899|Oil on canvas[newline]Impression, Sunrise|1872|Oil on canvas expected:<...laude Monet

I have difficulties on making a new line, I tried both \n and newLine() method but it doesn't work. And also showing the number of works on the list should be correct. And for the loop, I think I should use for loop in this case to loop over the art works.

Any hints/ help would be great, thank you!


Solution

  • Below is my code for method saveWorksToFile. It is the only part of the code in your question that I changed. (Notes after the code.)

    public void saveWorksToFile(Writer writer) {
        try {
            writer.write(this.name);
            writer.write(System.lineSeparator());
            writer.write("works: " + this.works.size());
            writer.write(System.lineSeparator());
            writer.write("---");
            writer.write(System.lineSeparator());
            boolean first = true;
            for (Work work : works) {
                if (first) {
                    first = false;
                }
                else {
                    writer.write(System.lineSeparator());
                }
                writer.write(work.toString());
            }
        }
        catch (IOException e) {
            System.out.println("IOException occurred");
        }
    }
    

    You are not meant to wrap the Writer parameter in a BufferedWriter. In general, for any method, you usually should not need to cast the parameter. Hence, in the above code, I use only the methods of class Writer. Also note that I do not close Writer since that should be left to the code that invoked method saveWorksToFile.

    In order to write a line separator, I call method lineSeparator of class java.lang.System.

    In order to print all the artist's works one per line, I use a loop.

    In order to ensure that the last entry in the artist's list of works is written without a line separator, the first work is written without a line separator and every subsequent work is written with a preceding line separator.

    Here is a method I wrote to test the above code. It uses class java.io.StringWriter which is a subclass of Writer since class Writer is abstract and has no public constructor. In general, you cannot instantiate an abstract class. You need to use a concrete subclass. I use StringWriter so as to be able to print its contents easily to the screen. You can use class java.io.FileWriter if you want to write to an actual file.

    /**
     * import java.io.StringWriter
     */
    public static void main(String[] args) {
        Artist artist = new Artist("Vincent van Gogh");
        StringWriter sw = new StringWriter();
        artist.saveWorksToFile(sw);
        System.out.print(sw);
        System.out.println();
        artist = new Artist("Claude Monet");
        Work work = new Work("Bridge over a Pond of Water Lilies", 1899, "Oil on canvas");
        artist.addWork(work);
        work = new Work("Impression, Sunrise", 1872, "Oil on canvas");
        artist.addWork(work);
        sw = new StringWriter();
        artist.saveWorksToFile(sw);
        System.out.print(sw);
        System.out.println();
        artist = new Artist("Henri Matisse");
        work = new Work("Woman with a Hat", 1905, "Oil on canvas");
        artist.addWork(work);
        sw = new StringWriter();
        artist.saveWorksToFile(sw);
        System.out.print(sw);
    }
    

    This is the output I got when I ran the above main method.

    Vincent van Gogh
    works: 0
    ---
    
    Claude Monet
    works: 2
    ---
    Bridge over a Pond of Water Lilies|1899|Oil on canvas
    Impression, Sunrise|1872|Oil on canvas
    Henry Matisse
    works: 1
    ---
    Woman with a Hat|1905|Oil on canvas