0

When I call shortestJobFirst method it doesn't print anything, so I think I passed it as reference to the firstComeFirstServe method, not value, so it deletes all the nodes. I want to keep my LinkedList jobOrder for 4 tasks. I had tried to use subList() but it won't be allowed me to remove any node, so I think that just for view only. Is there any easy way to fix this? Maybe I Should just create 4 LinkedList? Please get me a hint thank you very much.

txt file:

Job1
5
Job2
2
Job3
7
Job4
4
Job5
3
Job6
8

Below is my code

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Scanner;


public class Main {

    public static String filePath;


    public static void main(String[] args) throws Exception {

        LinkedList<Job> jobOrder = new LinkedList<Job>();

        System.out.println("Please enter input txt file path");
        System.out.println("Example: C:/Users/d/OneDrive/Desktop/Job.txt \n" );
        @SuppressWarnings("resource")

        //Create scanner to scan path for txt file
        Scanner input = new Scanner(System.in);
        //For user input
        System.out.print(">> " );
        filePath = input.nextLine();

        //Read input txt file
        fileReader(jobOrder,  filePath );

        //Call first come first serve algorithm
        firstComeFirstServe(jobOrder );
        //Shortest job first algorithm
        shortestJobFirst (jobOrder);

    }

    //My FCFS method
    public static void firstComeFirstServe(LinkedList<Job> jList )
    {
        int startTime = 0;
        int endTime = 0;

        System.out.println("(a) First Come First Service ");
        System.out.println("Job#" + " | " + " Start time" + " | " + " End Time" +" \t   |  " + "Job Completion ");

        while( !jList.isEmpty())
        {

            endTime = endTime + jList.getFirst().getId();

            System.out.println( jList.getFirst().getName() + " | \t" + startTime + " \t   |  " 
                    + endTime +" \t   |  "  + jList.getFirst().getName() + " completed @ " + endTime);

            startTime = endTime;

            jList.remove();
        }
        System.out.println(" ");
    }

    //My SJF method
    public static void shortestJobFirst (LinkedList<Job> jList )
    {

        Collections.sort(jList, new ascendingComparator());

        int startTime = 0;
        int endTime = 0;

        System.out.println("(b) Shortest Job First ");
        System.out.println("Job#" + " | " + " Start time" + " | " + " End Time" +" \t   |  " + "Job Completion ");

        while( !jList.isEmpty())
        {       
            endTime = endTime + jList.getFirst().getId();

            System.out.println( jList.getFirst().getName() + " | \t" + startTime + " \t   |  " 
                    + endTime +" \t   |  "  + jList.getFirst().getName() + " completed @ " + endTime);

            startTime = endTime;

            jList.remove();
        }
        System.out.println(" ");
    }


    //This method will read txt file and copy it to LinkedList
    public static void fileReader(LinkedList<Job> jList, String path ) throws Exception 
    {         
        //Scan txt file 
        Scanner sc = new Scanner(new BufferedReader(new FileReader(path)));
        String tempName = "";
        int tempLength = 0;
        int lineCount = 0;

        //Read while the scan still has next integers 
        while(sc.hasNextLine()) 
        {       
            lineCount = lineCount + 1;

            if (lineCount % 2 != 0)
            {
                tempName = sc.next();
            }
            else
            {
                tempLength = sc.nextInt();
                jList.add( new Job(tempName, tempLength) );
            }

        }
        sc.close();
    }

}


////

import java.util.Comparator;

class Job{

    private String jobNum;
    private int jobLength;

    public Job(String jobNum, int jobLength){
        this.jobLength = jobLength;
        this.jobNum = jobNum;
    }

    //Change this for display later
    public String toString(){
        return "[" + this.jobNum + "=>" + this.jobLength + "]";
    }

    public int getId(){
        return this.jobLength;
    }

    public String getName(){
        return this.jobNum;
    }
}


class ascendingComparator implements Comparator<Job>{

  public int compare(Job Job1, Job Job2) {        
      return Job1.getId() - Job2.getId();
  }    
}
Amit kumar
  • 2,169
  • 10
  • 25
  • 36
AlanS2000
  • 47
  • 3
  • 2
    While the terminology of "value" and "reference" gets confusing in Java, basically you can't and you have to manually copy the list. It's the only way. Your suggestion to keep four lists may work as well. – markspace Jun 12 '20 at 04:00

2 Answers2

3

I think you are used to C++ or C. In Java, if it is a primitive type it always passes by value, and if it is an object it always passes by reference. However, you can use Object's clone method. Note that some objects don't implement clone, but LinkedList does so you are fine.

firstComeFirstServe((LinkedList<Job>) jobOrder.clone());
Higigig
  • 1,175
  • 1
  • 13
  • 25
  • I think that only copies the list, though, not its elements (which are still references to the same objects that are also in the original list). –  Jun 12 '20 at 05:27
  • The clone() actually works!! thank you!! – AlanS2000 Jun 12 '20 at 07:31
1

Defensive copying

You are passing a reference to the same list object when calling each of your two methods. Then each of your methods are modifying that list. So of course the first method’s changes to the list are visible in the second method.

If you do not want this behavior, send a copy of the list to each method. This way both methods are free to add or drop elements to the list without such changes being visible in the other method. This known as making a defensive copy.

You can copy a collection simply by passing it to the constructor of another collection.

In the following example code, we end up with three collection objects. Each collection object has a bunch of references pointing to the very same Job objects. Each Job object has three references pointing to it.

List<Job> jobs = … from database, etc.
List<Job> jobsForReport = new ArrayList<>( jobs ) ;     // Copy of the first list.
List<Job> jobsForAnalysis = new LinkedList<>( jobs ) ;  // Another copy. 

illustration of 3 collection objects each pointing to the same four element objects

Pass these lists separately.

firstComeFirstServe( jobsForReport );
shortestJobFirst( jobsForAnalysis );

Each of those methods could of course make their own copy of the passed list. But generally a called method receiving a modifiable list should be free to do with the list whatever it desires. A called method should not be concerned with the situational details of the calling code. If the calling code does not want the passed list changed by the called method, the calling code should pass a non-modifiable collection.

Tip: To make sure your orignal list remains unchanged, make an nonmodifiable copy of the list when first produced. In Java 10 and later, use List.copyOf.

List<Job> jobs = List.copyOf( list-produced-from-somewhere ) ;

Implementations

By the way… Your particular uses of List may be inappropriate. Java offers many collection classes, some that might be better for each of your purposes.

For FIFO (first in, first out) use a Queue or Deque implementation. The LinkedList class implements both, so you might want to refer to your list object as such: Deque<Job> jobs2 = new LinkedList<>( jobs );. And you might want to study other implementations to find one best suited to your needs.

For shortest-job-first, use a SortedSet. Or for Queue behavior, perhaps PriorityQueue is a better fit.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Thanks for your answer!! but the reason I use LinkedList is that someone here said java LinkedList is already a queue since it has all the functions. I am not sure if that is true but here is link I found. https://stackoverflow.com/questions/38591371/java-linkedlist-class-as-stack-and-queues#:~:text=Queue,the%20end%20of%20this%20list. – AlanS2000 Jun 12 '20 at 07:34
  • @AlanS2000 Using a `LinkedList` is consistent with my approach here of defensive copying. Pass your original `List` object to the constructor of `LinkedList`, yielding a copy. Pass that copy to your called method. I show exactly this in the code in my Answer. See variable named `jobsForAnalysis`. – Basil Bourque Jun 12 '20 at 15:05
  • @AlanS2000 I see now that your comment may have been directed at the bottom section of my answer. I have revamped that section for clarity, and added more explanation, and added your correct point that `LinkedList` does indeed implement both `Queue` and `Deque`. – Basil Bourque Jun 12 '20 at 15:24