2

How do you pass a command line argument of a string to java main method that would call a specific method in another class?

I need to be able to pass 'java Statdriver mean' would call the mean method or 'java Statdriver std' would call the standard deviation method or passing no arguments would result in a call to mean method via the terminal.

Doing it my way does not seem to work. My problem I believe lies with the if, else if, else loop.

Here is my code:

public class StatDriver
{

   public static void main(String[] args)
   {
      Scanner input = new Scanner(System.in);

      double total;
      double mean;
      double standardDeviation;
      double average;


      total = 0;

      args[0] = "mean";
      args[1] = "std";

      ArrayList<Double> data = new ArrayList<Double>();

      while(input.hasNextDouble())
      {
         data.add(input.nextDouble());
      }

      if(args.equals(args[0]))
      {
         mean = Stats.mean(data);
         System.out.println("Mean: " + mean);
      }

      else if(args.equals(args[1]))
      {
         standardDeviation = Stats.stdDev(data);
         System.out.println("StdDev: " + standardDeviation);
      }

      else
      {
         mean = Stats.mean(data);
         System.out.println("Mean: " + mean);
      }




     // mean = Stats.mean(data);
    //standardDeviation = Stats.stdDev(data);


    //System.out.println("Mean: " + mean);
    // System.out.println(" StdDev: " + standardDeviation);



   }  

}
Andronicus
  • 25,419
  • 17
  • 47
  • 88
  • The other way would be through Reflection but I'm not sure you want to go down that path – Bálint Mar 11 '19 at 05:00
  • 1
    Possible duplicate of [How to call a method by name (String) in Java?](https://stackoverflow.com/questions/18718217/how-to-call-a-method-by-name-string-in-java) – Bálint Mar 11 '19 at 05:02
  • @James we cam employ runtime polymorphism for this problem, check my answer. – Fullstack Guy Mar 11 '19 at 05:36

5 Answers5

1

You're overwriting args variable. This should be like that:

public class StatDriver
{

   public static void main(String[] args)
   {
      Scanner input = new Scanner(System.in);

      double total;
      double mean;
      double standardDeviation;
      double average;


      total = 0;

      String[] possibleArgs = new String[2];
      possibleArgs[0] = "mean";
      possibleArgs[1] = "std";

      ArrayList<Double> data = new ArrayList<Double>();

      while(input.hasNextDouble())
      {
         data.add(input.nextDouble());
      }

      if(possibleArgs[0].equals(args[0]))
      {
         mean = Stats.mean(data);
         System.out.println("Mean: " + mean);
      }

      else if(possibleArgs[1].equals(args[1]))
      {
         standardDeviation = Stats.stdDev(data);
         System.out.println("StdDev: " + standardDeviation);
      }

      else
      {
         mean = Stats.mean(data);
         System.out.println("Mean: " + mean);
      }

   }  

}
Andronicus
  • 25,419
  • 17
  • 47
  • 88
1

How about using an interface and having a method in it with the same override signature as the methods of the Stat class:

interface StatsOperation{
       double compute(List<Double> data);
}

While Stat class will be as follows:

class Stats{
        public static double mean(List<Double> data){
            System.out.println("mean invoked");
            //compute mean 
        }
        public static double stdDev(List<Double> data){
            System.out.println("stddev invoked");
           //compute std dev
        }
 }

Now in the main method you can use a Map to hold the method references of the Stats class (assuming you are using Java-8):

public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        Map<String, StatsOperation> lookup = new HashMap<>();
        lookup.put("mean", Stats::mean); //"mean" corresponds to Stats::mean implementation
        lookup.put("stddev", Stats::stdDev); //"stddev" corresponds to Stats::mean implementation
        ArrayList<Double> data = new ArrayList<Double>();
        while(input.hasNextDouble())
        {
            data.add(input.nextDouble());
            if(data.size() == 5) break; //breaking after 5 elements
        }
        StatsOperation operation = args.length > 0 && lookup.get(args[0]) != null ? lookup.get(args[0]) : lookup.get("mean"); //by default calling mean if nothing is sent in args array
        double result = operation.compute(data);
        System.out.println("Output " + result);
        // other business logic below
 }

So depending on the value you pass in the args array, we would invoke that operation by fetching the implementation from the Map. This employs runtime polymorphism to decide which method gets called at runtime.

Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
1

The command line arguments are the words which are specified after “java classname” on the command line. So, if you execute this:

java Statdriver mean

…your main method will be given an args array of length one, containing "mean" as an element.

If you execute this:

java Statdriver std

…your main method will be given an args array of length one, containing "std" as an element.

In all of those cases, args has a length of one. You should only be checking args[0]. There is no args[1], and attempting to access it will throw an exception.

As Andronicus pointed out, you are trying to assign values to args, which you should not do. In fact, you don’t need to change args at all.

Just check whether args[0] is equal to each meaningful String value:

  if (args[0].equals("mean"))
  {
     mean = Stats.mean(data);
     System.out.println("Mean: " + mean);
  }

  else if (args[0].equals("std"))
  {
     standardDeviation = Stats.stdDev(data);
     System.out.println("StdDev: " + standardDeviation);
  }

  else
  {
     mean = Stats.mean(data);
     System.out.println("Mean: " + mean);
  }

It helps to think about what you actually want to check. Good code reads like natural thinking or speaking: “If the first argument is "mean" then calculate the mean, otherwise if the first argument is "std" then calculate the standard deviation” and so on.

VGR
  • 40,506
  • 4
  • 48
  • 63
-1

Solution is simple & easy when Java Reflection Feature is used. Here is the code

    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Scanner;

    public class StatDriver {

        public static void main(String[] args)
        {
            Scanner input = new Scanner(System.in);
            ArrayList<Double> data = new ArrayList<Double>();

            while(input.hasNextDouble()) {
                data.add(input.nextDouble());
            }

            int length = args.length;

            if(length == 0) {
                double mean = Stats.mean(data);  // By default , mean method is called
        System.out.println(" Result (Mean) :"+mean);
    }
    else if(length > 0) {
        String methodName = args[0];

        try {
            Method method = Stats.class.getMethod(methodName, ArrayList.class);
            method.setAccessible(true);
            Object result = method.invoke(null , data);
            System.out.println("Result of the method :"+methodName+" is "+result);
                }
                catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Stats{

        public static double mean(ArrayList aList) {
            double result = 0.0D;
            //Logic here
            return result;
        }

        public static double stdDev(ArrayList aList) {
            double result = 0.0D;
            //Logic here
            return result;
        }
    }
Ramesh Subramanian
  • 944
  • 1
  • 12
  • 28
  • Reflection is usually the worst way to do things. It is slow, it cannot be checked by the compiler, it is error prone, and `setAccessible` violates encapsulation rules which are strictly enforced starting in Java 9 and later. – VGR Nov 07 '22 at 14:38
-2
public class StatDriver
{

   public static void main(String[] args)
   {
      Scanner input = new Scanner(System.in);

      double total;
      double mean;
      double standardDeviation;
      double average;


      total = 0;

      ArrayList<Double> data = new ArrayList<Double>();

      while(input.hasNextDouble())
      {
         data.add(input.nextDouble());
      }

      if(args[0].equals("mean"))
      {
         mean = Stats.mean(data);
         System.out.println("Mean: " + mean);
      }

      else if(args[1].equals("std"))
      {
         standardDeviation = Stats.stdDev(data);
         System.out.println("StdDev: " + standardDeviation);
      }

      else
      {
         mean = Stats.mean(data);
         System.out.println("Mean: " + mean);
      }

   }  

}
Hasee Amarathunga
  • 1,901
  • 12
  • 17