• Track.java

  • §
    package MusicLandscape.entities;
  • §

    (This import is only there for Objects.equals, but is actually not necessary. It will be thrown out in one of the next versions of this class.)

    import java.util.Objects;
  • §

    The Track class is a composition of multiple other types: int for the duration and year of release, String for the title, and our custom type Artist for the writer and performer fields.

    Track::getString is the most difficult part of this exercise.

    /**
     * represents a piece of music that has been released on some kind of media (CD, vinyl, video, ...)
     *
     * @author Jonas Altrock (ew20b126@technikum-wien.at)
     * @version 1
     * @since ExcerciseSheet01
     */
    public class Track {
        /**
         * the duration of this track in seconds the duration is a non-negative number, duration 0 (zero) represents unknown duration
         */
        private int duration = 0;
  • §

    Again, the important thing here is to implement the invariants given to us by the documentation: that some fields can never be null.

        /**
         * the artist who performs this track the performer cannot be null
         */
        private Artist performer = new Artist();
    
        /**
         * the title of this track.
         */
        private String title;
    
        /**
         * the artist who wrote this track the writer cannot be null
         */
        private Artist writer = new Artist();
    
        /**
         * the year in which the Track was or will be produced valid years are between 1900-2999
         */
        private int year = 0;
    
        /**
         * gets the duration of this track
         *
         * @return the duration
         */
        public int getDuration() {
            return duration;
        }
    
        /**
         * returns the performer of this track
         *
         * @return the performer
         */
        public Artist getPerformer() {
            return performer;
        }
    
        /**
         * gets the title of this track. if the title is not known (null) "unknown title" is returned (without quotes)
         *
         * @return the title
         */
        public String getTitle() {
            if (title == null || title.isBlank()) {
                return "unknown title";
            }
            return title;
        }
    
        /**
         * returns the writer of this track
         *
         * @return the writer
         */
        public Artist getWriter() {
            return writer;
        }
    
        /**
         * gets the production year of this track
         *
         * @return the year
         */
        public int getYear() {
            return year;
        }
    
        /**
         * sets the duration a negative value is ignored, the object remains unchanged
         *
         * @param duration - the duration to set
         */
        public void setDuration(int duration) {
            if (duration < 0) {
                return;
            }
            this.duration = duration;
        }
    
        /**
         * sets the performer of this track null arguments are ignored
         *
         * @param performer - the performer to set
         */
        public void setPerformer(Artist performer) {
            if (performer == null) {
                return;
            }
            this.performer = performer;
        }
    
        /**
         * sets the title of this track.
         *
         * @param title - the title to set
         */
        public void setTitle(String title) {
            this.title = title;
        }
    
        /**
         * sets the the writer of this track null arguments are ignored
         *
         * @param writer - the writer to set
         */
        public void setWriter(Artist writer) {
            if (writer == null) {
                return;
            }
            this.writer = writer;
        }
    
        /**
         * sets the production year of this track valid years are between 1900 and 2999 other values are ignored, the object remains unchanged
         *
         * @param year - the year to set
         */
        public void setYear(int year) {
            if (year < 1900 || year > 2999) {
                return;
            }
            this.year = year;
        }
    
        /**
         * this getter is used to check if the writer of this Track is known.
         *
         * @return true if the writer of this track is known (and has a name), false otherwise.
         */
        public boolean writerIsKnown() {
            return isKnown(writer);
        }
  • §

    This is a small helper function I wrote to make the checks for unknown artists in getString() simpler to read.

        /**
         * Check whether an artist is known.
         * @param artist the artist to check
         * @return whether the artist is known or not
         */
        protected boolean isKnown(Artist artist) {
            return artist != null && artist.getName() != null && !artist.getName().isBlank();
        }
  • §

    getString()

    This method is the most complex thing we are asked to implement.

        /**
         * returns a formatted String containing all information of this track. the String representation is (without quotes):
         * <p>
         * "title by writer performed by performer (min:sec)"
         * <p>
         * where
         * - title stands for the title (exactly 10 chars wide) if not set, return unknown
         * - writer stands for the writer name (exactly 10 chars wide, right justified)
         * - performer stands for the performer name (exactly 10 chars wide, right justified)
         * - min is the duration's amount of full minutes (at least two digits, leading zeros)
         * - sec is the duration's remaining amount of seconds (at least two digits, leading zeros)
         *
         * @return a String representation of this track
         */
        public String getString() {
            String title = Objects.equals(getTitle(), "unknown title") ? "unknown" : this.title;
            String writer = isKnown(getWriter()) ? getWriter().getName() : "unknown";
            String performer = isKnown(getPerformer()) ? getPerformer().getName() : "unknown";
  • §

    The .substring() can actually be done directly with a %-code for String.format, but I didn’t know that yet when I did ES01.

            title = String.format("%10s", title).substring(0, 10);
            writer = String.format("%10s", writer).substring(0, 10);
            performer = String.format("%10s", performer).substring(0, 10);
  • §

    There is a bug hidden here, what if the duration was more than 100 minutes long? Say 110 minutes exactly, then this would show 10 minutes.

            String minutes = String.format("%02d", (duration / 60) % 100);
            String seconds = String.format("%02d", duration % 60);
  • §

    Instead of doing variables and concatenating them with +, one could use one String.format() here and pass in the various values.

            return title + " by " + writer + " performed by " + performer + " (" + minutes + ":" + seconds + ")";
        }
    }