Hi have a question,why i do not get value output for FutureValue,do i use in the wrong place in Main method calculateFutureValue() ?

package sd4.dobs.ui;

import java.util.Scanner;

public class Console {

    private static Scanner sc = new Scanner(System.in);

    public static void displayLine() {
        System.out.println();
    }

    public static void displayLine(String s) {
        System.out.println(s);
    }

    public static String getString(String prompt) {
        System.out.print(prompt);
        String s = sc.nextLine();
        return s;
    }

    public static int getInt(String prompt) {
        int i = 0;
        while (true) {
            System.out.print(prompt);
            try {
                i = Integer.parseInt(sc.nextLine());
                break;
            } catch (NumberFormatException e) {
                System.out.println("Error! Invalid integer. Try again.");
            }
        }
        return i;
    }

    public static double getDouble(String prompt) {
        double d = 0;
        while (true) {
            System.out.print(prompt);
            try {
                d = Double.parseDouble(sc.nextLine());
                break;
            } catch (NumberFormatException e) {
                System.out.println("Error! Invalid decimal. Try again.");
            }
        }
        return d;
    }
}

----------------------------------------------------------------------------------
package sd4.dobs.model;

public class Investment {
    private double monthlyInvestment;

    public double getMonthlyInvestment() {
        return monthlyInvestment;
    }

    public void setMonthlyInvestment(double monthlyInvestment) {
        this.monthlyInvestment = monthlyInvestment;
    }

    public double getYearlyInterestRate() {
        return yearlyInterestRate;
    }

    public void setYearlyInterestRate(double yearlyInterestRate) {
        this.yearlyInterestRate = yearlyInterestRate;
    }

    public int getYears() {
        return years;
    }

    public void setYears(int years) {
        this.years = years;
    }
    private double yearlyInterestRate;
    private int years;

    public Investment(double monthlyInvestment, double yearlyInterestRate, int years) {
        this.monthlyInvestment = monthlyInvestment;
        this.yearlyInterestRate = yearlyInterestRate;
        this.years = years;
    }

    public Investment() {
        this.monthlyInvestment=0;
        this.yearlyInterestRate=0;
        this.years=0;
    }
    public double calculateFutureValue()
    {
        double monthlyInterestRate = yearlyInterestRate/12/100;
        int months = years *12;
        double futureValue =0;
        for(int i =1;i<=months;i++)
        {
           futureValue += monthlyInterestRate;
           double monthlyInterestAmount = futureValue * monthlyInterestRate;
           futureValue += monthlyInterestAmount;

        }
        return futureValue;
    }

    @Override
    public String toString() {
        return "Inv/Mo "  + monthlyInvestment + " Rate " + yearlyInterestRate + " Years " + years + " Future value "+ calculateFutureValue();
    }

}
-------------------------------------------------------------------------------------
package sd4.dobs.ui;

import java.text.NumberFormat;
import java.util.ArrayList;
import sd4.dobs.model.Investment;

public class Main {

    public static void main(String[] args) {

        ArrayList<Investment>investmentList = new ArrayList<>();
        Investment inv = new Investment();
          double futurevalue =  inv.calculateFutureValue();
        // displayLine a welcome message
        double monthlyInvestment=0;
         double yearlyInterestRate =0;
         int years =0;
        Console.displayLine("Welcome to the Future Value Calculator");
        Console.displayLine();
        String choice = "y";

        while (choice.equalsIgnoreCase("y")) {

            // get input from user
             monthlyInvestment
                    = Console.getDouble("Enter monthly investment:   ");
            yearlyInterestRate
                    = Console.getDouble("Enter yearly interest rate: ");
             years
                    = Console.getInt("Enter number of years:      ");

            // see if the user wants to continue
            choice = Console.getString("Continue? (y/n): ");
            Console.displayLine();
        }
         investmentList.add(new Investment(monthlyInvestment,yearlyInterestRate,years));

        for(Investment in : investmentList)
        {

            System.out.println(in + " " + futurevalue);

        }

        Console.displayLine("Bye!");
    }

}

Recommended Answers

All 16 Replies

Try these three files:

1st:

import java.util.Scanner;

public class Console {

    private static Scanner sc = new Scanner(System.in);

    public static void displayLine() {
        System.out.println();
    }

    public static void displayLine(String s) {
        System.out.println(s);
    }

    public static String getString(String prompt) {
        System.out.print(prompt);
        String s = sc.nextLine();
        return s;
    }

    public static int getInt(String prompt) {
        int i = 0;
        while (true) {
            System.out.print(prompt);
            try {
                i = Integer.parseInt(sc.nextLine());
                break;
            } catch (NumberFormatException e) {
                System.out.println("Error! Invalid integer. Try again.");
            }
        }
        return i;
    }

    public static double getDouble(String prompt) {
        double d = 0;
        while (true) {
            System.out.print(prompt);
            try {
                d = Double.parseDouble(sc.nextLine());
                break;
            } catch (NumberFormatException e) {
                System.out.println("Error! Invalid decimal. Try again.");
            }
        }
        return d;
    }
}

2nd:

public class Investment {
    private double monthlyInvestment;
    private double yearlyInterestRate;
    private int years;

    // default ctor...
    public Investment() {
        this.monthlyInvestment = 0.0;
        this.yearlyInterestRate = 0.0;
        this.years = 0;
    }
    // passed in values ctor...
    public Investment(double monthlyInvestment, double yearlyInterestRate, int years) {
        this.monthlyInvestment = monthlyInvestment;
        this.yearlyInterestRate = yearlyInterestRate;
        this.years = years;
    }

    public double getMonthlyInvestment() {
        return monthlyInvestment;
    }

    public void setMonthlyInvestment(double monthlyInvestment) {
        this.monthlyInvestment = monthlyInvestment;
    }

    public double getYearlyInterestRate() {
        return yearlyInterestRate;
    }

    public void setYearlyInterestRate(double yearlyInterestRate) {
        this.yearlyInterestRate = yearlyInterestRate;
    }

    public int getYears() {
        return years;
    }

    public void setYears(int years) {
        this.years = years;
    }

    public double calculateFutureValue()
    {
        double monthlyInterestRate = yearlyInterestRate/12.0/100.0;
        int months = years * 12;
        double futureValue = 0.0;
        for( int i = 1;i <= months; i++ ) {
           futureValue = (futureValue+monthlyInvestment) * (1+monthlyInterestRate);
        }
        return futureValue;
    }

    @Override
    public String toString() {
        return String.format( "Inv/Mo: monthlyInvestment(%8.2f), " +
                              "yearlyInterestRate(%5.2f%%), Years(%3d)" + 
                              "\n        Future value($%,10.2f)", 
                              monthlyInvestment,
                              yearlyInterestRate, years,
                              calculateFutureValue() );
    }

}

3rd:

import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {

        ArrayList< Investment > investmentList = new ArrayList <> ();

        // displayLine a welcome message //

        Console.displayLine("Welcome to the Future Value Calculator");
        Console.displayLine();

        String choice = "Y";// defaults to 'YES' loop again //

        while( ! choice.equalsIgnoreCase("N") ) { // defaults to 'YES' loop again //

            Investment inv = new Investment(); // get empty new investment obj.

            // get input from user
            inv.setMonthlyInvestment( Console.getDouble("Enter monthly investment   : "));
            inv.setYearlyInterestRate(Console.getDouble("Enter yearly interest rate : "));
            inv.setYears(                Console.getInt("Enter number of years      : "));

            investmentList.add( inv ); // Ok ... add this new obj. to the list ...

            // see if the user wants to continue
            choice = Console.getString("Continue (y/n) ? ");
            Console.displayLine();
        }

        // ok ... now show all info, including future values ...
        for(Investment obj: investmentList)
        {
            // note that calling the toString method here,
            // forces the calculation of eavj future value //

            Console.displayLine( obj.toString() );
            Console.displayLine(); 
        }

        Console.displayLine("Bye!");
    }

}

why not explaining what (you think) went wrong before providing copy-ready solutions?

This code includes a copy of a "Console" class that has popped up a couple of times recently. Maybe the work of David W. ? It's obviously intended as a replacement for the dreaded Scanner class, so I'm all in favour of that!

Before it gets too widely copied & pasted it may be a good idea to fix it up a bit. For example: Why use a Scanner when all you are doing a readLine? Why not just read from the system Console object? (at least that's thread safe, and it supports password entry).
How can the user break out of the input methods? Why deliberately name your class the same as a basic system class? Any thoughts on everything being static? How about a one-line ownership/licence statement before too many students include it in homework that will otherwise be assumed to be all their own work and get themselves penalised?

If it is David W's code, then maybe it would be fun for him to start a thread to develop this class a bit further for the benefit of all learners? There are enough people here who can help ensure that the result is a really good example for beginners.

Have a question,but first thanks for the explanation of code.Question :
which option is a good practice Option1 in the while loop like this or like in your code : inv.........

while (!choice.equalsIgnoreCase("N")) {

            double monthlyInvestment  = Console.getDouble("Enter monthly investment:   ");
            double yearlyInterestRate  = Console.getDouble("Enter yearly interest rate: ");
            int year    = Console.getInt("Enter number of years:      ");
            investment = new Investment(monthlyInvestment, yearlyInterestRate, years);
            investmentArrayList.add(investment);
}

With no error handling there's nothing to chose, but if you can have unrecoverable errors in the input data then it's best not to create the object until/unless you have all the data.

With respect to a custom TakeIn class to aid valid student user input from the keyboard, i put together the following TakeInLine class awhile ago, that you may like to see and use instead, used below, in a rework of the OP's FutureValue problem:

1st file:

// TakeInLine.java //  // revised: 2016-09-26 //

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class TakeInLine
{
    // Create a BufferedReader using System.in ... //
    BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );

    String takeInLine( String msg )
    {
        System.out.print( msg );
        String line = null;
        try
        {
            line = br.readLine();
        }
        catch( IOException e )
        {
            System.err.println( e );
            System.err.println( "UNEXPECTED string input error." );
            line = ""; // default here to empty line ... //
        }
        return line;
    }

    char takeInChr( String msg )
    {   
        String line = takeInLine( msg );
        if( line.length() > 0 )
            return (char)line.charAt(0);
        // else ...
        return (char)0; 
    } 

    int takeInInt( String msg )
    {   
        int iVal = 0;
        boolean loop = true;
        while( loop )
        {
            String line = takeInLine( msg );
            try
            {
                iVal = Integer.parseInt( line );
                loop = false;
            }
            catch( NumberFormatException e )
            {
                System.err.println( "Error! " + e );
                System.err.println( "Only valid 'int' numbers are accepted, so try again." );
            };
        }
        return iVal;
    }

    long takeInLng( String msg )
    {   
        long longVal = 0;
        boolean loop = true;
        while( loop )
        {
            String line = takeInLine( msg );
            try
            {
                longVal = Long.parseLong( line );
                loop = false;
            }
            catch( NumberFormatException e )
            {
                System.err.println( "Error! " + e );
                System.err.println( "Only valid 'long' numbers are accepted, so try again." );
            }
        }
        return longVal;
    }

    double takeInDbl( String msg )
    {   
        double dVal = 0;
        boolean loop = true;
        while( loop )
        {
            String line = takeInLine( msg );
            try
            {
                dVal = Double.parseDouble( line );
                loop = false;
            }
            catch( NumberFormatException e )
            {
                System.err.println("Error! " + e);
                System.err.println("Only valid 'double' numbers are accepted, so try again.");
            }
        }
        return dVal;
    }

    // call as more('y') if yes is to be the default case ...
    // call as more('n') if no is to be the default case //

    boolean more( final char defaultChar ) // 'y' or 'n' tells 'defaultChar' ... //
    {
        char reply = takeInChr( "More (y/n) ? " );
        reply = Character.toLowerCase( reply );

        if( defaultChar == 'y' )
            return reply != 'n';
        // else ....
        return reply == 'y';
    }

    // this defaults to case: "yes more" 
    // unless 'n' or 'N' is entered as first char on line //
    boolean more()
    {
        return more( 'y' );
    }
}

2nd file:

public class Investment
{
    private static TakeInLine til = new TakeInLine();

    private double monthlyInvestment = 0.0;
    private double yearlyInterestRate = 0.0;
    private int years = 0;

    void takeInFields()
    {
        monthlyInvestment  = til.takeInDbl("Enter monthly investment   : ");
        yearlyInterestRate = til.takeInDbl("Enter yearly interest rate : ");
        years              = til.takeInInt("Enter number of years      : ");
    }

    public double getFutureValue()
    {
        double monthlyInterestRate = yearlyInterestRate/12.0/100.0;
        int months = years * 12;
        double futureValue = 0.0;
        for( int i = 1;i <= months; i++ )
        {
           futureValue = (futureValue+monthlyInvestment) * (1 + monthlyInterestRate);
        }
        return futureValue;
    }

    @Override
    public String toString()
    {
        return String.format( "Inv/Mo: monthlyInvestment(%8.2f), " +
                              "yearlyInterestRate(%5.2f%%), Years(%3d)" + 
                              "\n        Future value($%,10.2f)", 
                              monthlyInvestment, 
                              yearlyInterestRate, years,
                              getFutureValue() );
    }
}

3rd and last file:

import java.util.ArrayList;

public class FutureValue
{
    static TakeInLine til = new TakeInLine();

    public static void main(String[] args)
    {
        ArrayList< Investment > investmentList = new ArrayList <> ();

        // displayLine a welcome message //
        System.out.println("Welcome to the Future Value Calculator\n");

        do
        {
            Investment inv = new Investment(); // get empty new investment obj.
            // get input from user //
            inv.takeInFields();
            // Ok ... add this new obj. to the list //
            investmentList.add( inv ); 

            System.out.println();
        }
        while( til.more() );

        System.out.println( "\nOk ... NOW showing all entered info, including future values:\n" );
        for(Investment invObj: investmentList)
        {
            // note that calling the toString method here,
            // forces the calculation of eavj future value //

            System.out.println( invObj.toString() );
            System.out.println(); 
        }

        System.out.println();
    }
}

A couple of quick suggestions:
FutureValue line 32 - the toString() is redundant because print and println do that to their arguments anyway
TakeInLine:
Lines 74 and 95 should be System.out - some users will have a default logging setup that redirects System.err to a log file.
You could have an alternative constructor that takes an InputStream as parameter so you can run test cases by placing all your answers in a file.
Finally - the loop constructs can be much simpler...

    int takeInInt( String msg )  {   
        while( true ) {
            try {
                return Integer.parseInt( takeInLine( msg ) );
            }
            catch( NumberFormatException e ) {
                System.err.println( "Error! " + e );
                System.out.println( "Only valid 'int' numbers are accepted, so try again." );
            }
        }
    }

ps: Although opinions differ on the merits of where to place your brackets, the Java norm is as above - see the Oracle Java tutorials, or the API source code.

Thank you James for your comments and suggestions:

FutureValue line 32 - the toString() is redundant because print and println do that to their arguments anyway

Good catch ... I missed updating that from some earlier 'test code' I was using,

TakeInLine: Lines 74 and 95 should be System.out - some users will have a default logging setup that redirects System.err to a log file

Great 'heads up'.

the loop constructs can be much simpler...

Yes I know ... and thanks for providing students with nice clean demo code that many may prefer to use in 'their version' ... my goal here was to show one old school preferred coding style where some stylists like to only exit at the bottom of a function ... neither would some like to jump out of a try ... catch struture.

{
   // block coding style to help coder see that the 'start' { and 'stop' } of block 
   // both have been coded //
}

I must confess to hanging on to my C and C++ block coding style ... as I begin to dable in Java :)

Good discussion...

some stylists like to only exit at the bottom of a function

This makes sense in a language that has manual resource mangement (eg C) because it makes it easier to be sure that all deallocations are done correctly. In Java there is no need for such a restriction. There are common cases where early returns are by far the obvious best choice - "guard clauses" spring to mind.

I have no idea why anyone would have a problem with exiting from inside a try clause - especially since finally was added to the language. Indeed the case we are discussing is a perfect example of a very common pattern

while (count < error_limit) {
   try {
       do something that may throw an E
      return the result
   } catch {
      diagnose and attempt a re-try
   }
}
return or throw an unrecoverable error

As for coding styles - yes, very much a matter of personal opinion. In practice most of us are employed by or are contracted to a organisation that has existing standards, so our opions are irrelevant! You will find that the vast majority of Java shops use some variant of the Sun/Oracle Java style, so I always use that when posting code that may be read by learners.

JC

Great points James for Java students to utilize :)

Also ... I meant to ask you to clarify more your suggestion above ... about and alt 'InputStream' constructor ... Perhaps you could give an example of it ... and it's use?

Also ...

I have been thinking about a simpler class for beginning students to use to handle console io, for begining student type io problems taking in numeric values via line input, (as in Python.)

You may like to see the demo below:

// this version: 2016-09-28 //

import java.util.Scanner;

public class Console {

    private static Scanner sc = new Scanner( System.in );

    public static String takeInLine( String prompt ) {
        System.out.print( prompt );
        return sc.nextLine();
    }

    public static int takeInInt( String prompt ) {
        while( true ) {
            try {
                return Integer.parseInt( takeInLine( prompt ) );
            } catch( NumberFormatException e ) {
                System.out.println( "Error! Invalid integer. Try again." );
            }
        }
    }

    public static long takeInLong(String prompt) {
        while( true ) {
            try {
                return Long.parseLong( takeInLine( prompt ) );
            } catch( NumberFormatException e ) {
                System.out.println( "Error! Invalid long. Try again." );
            }
        }
    }

    public static double takeInDouble(String prompt) {
        while( true ) {
            try {
                return Double.parseDouble(takeInLine( prompt ) );
            } catch( NumberFormatException e ) {
                System.out.println( "Error! Invalid decimal. Try again." );
            }
        }
    }

    // Call as: more( "Y" ); // to have default case of 'Yes more' //
    // Call as: more( "N" ); // to have default case of 'No more'  //
    public static boolean more( String defaultStr ) {
        String reply = takeInLine( "More (y/n) ? " );
        if( defaultStr.equalsIgnoreCase( "Y" ) ) {
            if( reply.equalsIgnoreCase( "N" ) ) {
                return false;
            } else {
                return true;
            }
        } else {
            if( reply.equalsIgnoreCase( "Y" ) ) {
                return true;
            } else {
                return false;
            }
        }
    }

    // defaults to 'Yes more' //
    public static boolean more() {
        return more( "Y" );
    }

    public static void println() {
        System.out.println();
    }

    public static void println( String s ) {
        System.out.println( s );
    }

    public static void print( String s ) {
        System.out.print( s );
    }

    public static void format( String formatStr, Object ... obj ) {
        System.out.format( formatStr, obj );
    }

}

A little test program file:

// this version: 2016-09-28 //

class ConsoleTest
{
    public static void main(String[] args)
    {
        do
        {
            String name   = Console.takeInLine(   "Enter this user name :  " );
            long  id      = Console.takeInLong(   "Enter ID (16 digits) :  " );
            int pin       = Console.takeInInt(    "Enter pin (8 digits) :  " );
            double amount = Console.takeInDouble( "Enter $ amount owing :  " );

            Console.println();

            Console.format( "%s, %d, %d owes: %,1.2f dollars. %n", name, id, pin, amount );
            Console.println();
            Console.println( "On to next client?" );
            Console.print( "Whenever you are ready, enter y or n, " );
            Console.println( "or just press the Enter key for 'y'." );
        }
        while( Console.more() );
    }
}

I meant to ask you to clarify more your suggestion above ... about and alt 'InputStream' constructor

public class SimpleInput { // like David  W's but my preferred names

     private BufferedReader br; // we will read all our input from here
     private boolean echoInput = false;

     public SimpleInput() {
         br = new BufferedReader( new InputStreamReader( System.in ) );
    }

    public SimpleInput(InputStream source) {
         br = new BufferedReader( new InputStreamReader( source ) );
         echoInput= true;
    }

    // with file input you could also echo input to System.out
    // as its processed to provide a trace - especially valuable
    // if the user's code suffers from  bugs.

public String getText(String prompt) throws IOException {
    System.out.print(prompt);
    String answer = br.readLine();
    if (answer == null) ... // e.o.f. - need to do something!
    if (echoInput) System.out.print(answer);
    return answer;
}

Although on second thoughts, for real beginners maybe this is better

    public SimpleInput(String inputFileName) {
         br = new BufferedReader( new FileReader( inputFileName ) );
         echoInput= true;
    }

and you could use RuntimeExceptions to avoid them having to deal with errors

 public String getText(String prompt) {
    System.out.print(prompt);
    String answer;
    try {
        answer = br.readLine();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    if (answer == null) {
        throw new RuntimeException("Unexpected end of input");
    }
    if (echoInput) System.out.print(answer);
    return answer;
}

You can enhance the numeric inputs to exit after repeated errors, and to ignore commas as thousands separators...

    public int getInt(String prompt) {
        int errorCount = 0;
        while (errorCount++ < 3) {
            try {
                String input = getText(prompt);;
                input = input.replaceAll("(\\d),(\\d\\d\\d)", "$1$2");
                return Integer.parseInt(input);
            } catch (NumberFormatException e) {
                System.out.println("Error! Invalid long. Try again.");
            }
        }
        throw new RuntimeException("Repeated invalid user input");
    }

Finally: We have totally hijacked this thread. :(
You should start a new thread about creating a better Scanner for beginners.
(Or I can start it if you prefer) JC

Yah ... sorry PulsarScript ... I think that JC suggested that ... (starting a new thread) ... way back :(

Thanks for your post that 'got the ball rolling'.

So asap I will start a new thread.

Shalom,
dwz

Ok,thanks for your attention.Would appreciate if you give me the link to your new thread of discussion about topic you wrote.Best Regards

Also would appreciate if you could have a look on one of my next question in topic i created JSP session.And once again thanks for showing modification of the code,which gives valuable knowledge .5 stars.Thanks

JSP Session/programming/software development

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.