首页 > 解决方案 > 我对课堂上的吸气剂和回报感到困惑?

问题描述

我一直在自学编码、getter 和返回值,以及如何在主程序中调用它们。为了试一试,我尝试编写一个程序来计算长途电话的成本,但是当我运行它时它就崩溃了,我知道它与课程有关。

公平的警告,我计算上午/下午的时间有点奇怪,但我尽力了。

我认为这必须与调用我的主要代码中的计算有关——特别是 String weekday = call1.calculateweekday(); 和 int 时间 = call1.calculatetime(); ,但我对编程很陌生,而且我刚刚开始学习这些术语和用法,所以我不知道是什么。我只知道,当我在主程序周围移动这两行时,它会在那时中断。

package practice;

import java.util.Scanner;

class Call {
    String weekdayinput;
    String weekday;
    int hour;
    String ampm;
    int time;

    int calculatetime() {

        if (ampm.equals("pm") || ampm.equals("PM") || ampm.equals("Pm")) {

            time = hour + 1200;
        } else if (ampm.equals("am") || ampm.equals("AM") || ampm.equals("Am")) {

            time = hour;

        }

        else {
            System.out.println("You entered something either time or AM/PM incorrectly.");
        }

        return time;
    }

    String calculateweekday() {

        if (weekdayinput.equals("mo") || weekdayinput.equals("Mo") || weekdayinput.equals("MO")) {

            weekday = "Monday";
        }

        else if (weekdayinput.equals("tu") || weekdayinput.equals("Tu") || weekdayinput.equals("TU")) {

            weekday = "Tuesday";
        }

        else if (weekdayinput.equals("we") || weekdayinput.equals("We") || weekdayinput.equals("WE")) {

            weekday = "Wednesday";
        }

        else if (weekdayinput.equals("th") || weekdayinput.equals("Th") || weekdayinput.equals("TH")) {

            weekday = "Thursday";
        }

        else if (weekdayinput.equals("fr") || weekdayinput.equals("Fr") || weekdayinput.equals("FR")) {

            weekday = "Friday";
        }

        else if (weekdayinput.equals("sa") || weekdayinput.equals("Sa") || weekdayinput.equals("SA")) {

            weekday = "Saturday";
        }

        else if (weekdayinput.equals("su") || weekdayinput.equals("Su") || weekdayinput.equals("SU")) {

            weekday = "Sunday";
        }

        else {
            System.out.println("You entered your weekday incorrectly.");
        }

        return weekday;
    }

}

public class GettersandREturns {
    public static void main(String args[]) {

        Scanner input = new Scanner(System.in);
        Call call1 = new Call();

        String weekday = call1.calculateweekday();
        int time = call1.calculatetime();

        System.out.println("To calculate the cost per minute of your long-distance call, we'll need some information.");
        System.out.println(
                "What hour are you planning on making the call. Minutes aren't necessary. Please only enter the hour number. (ex. 8)");
        call1.hour = input.nextInt();
        input.hasNextLine();
        System.out.println("Is the call taking place AM or PM?");
        call1.ampm = input.nextLine();
        input.hasNextLine();
        System.out.println("And what day of the week is that? Please enter weekday with only first two letters. (ex. Fr");
        call1.weekdayinput = input.nextLine();



        if (time >= 8 && time <= 11 && !weekday.equals("Saturday") && !weekday.equals("Sunday")
                || time >= 1212 && time <= 1206 && !weekday.equals("Saturday") && !weekday.equals("Sunday"))

        {
            System.out.println("Your call will charge $4.50 a minute.");
        }

        else if (time == 12 && !weekday.equals("Saturday") && !weekday.equals("Sunday")
                || time >= 1 && time < 8 && !weekday.equals("Saturday") && !weekday.equals("Sunday")
                || time > 1206 && time <= 1211 && !weekday.equals("Saturday") && !weekday.equals("Sunday")) {

            System.out.println("Your call will charge $4.00 a minute.");

        }

        else if (weekday.equals("Saturday") || weekday.equals("Sunday")){

            System.out.println("Your call will charge $2.25 a minute.");
        }

        else {
            System.out.println("You must have entered something wrong!");
        }

    }
}

因此,想法是在周一至周五上午 8:00 到下午 6:00 之间拨打的任何电话都按每分钟 4.50 的费率计费。周一至周五上午 8:00 之前或下午 6:00 之后开始的任何呼叫均按每分钟 4.00 的费率计费。最后,周六或周日拨打的任何电话均按每分钟 2.25 元的费率收费。

但是当我运行这个程序时,我在 practice.Call.calculateweekday(GettersandREturns.java:32) 在 practice.GettersandREturns.main(GettersandREturns.java:82) 的线程“main”java.lang.NullPointerException 中出现异常

任何帮助将不胜感激。学习很难。

标签: javareturngetter

解决方案


进一步的想法

Wuttke的回答是正确的,应该被接受。这里还有一些无关紧要的想法。

通常最好将每个类保存在自己的 .java 文件中。

命名时要小心。描述性和具体性使您的代码更易于阅读、审查和修改。因此,将您的Scanner对象称为scanner而不是input.

您可以通过将文本输入全部转换为大写或小写来缩短一些逻辑。

你的代码time > 1206 && time <= 1211让我很困惑。我不明白你的意图。

将用户界面与业务逻辑分开。各种收费的日期和时间规则应单独分类。这使得当您的业务规则发生变化时,您可以在一个地方使用非常简单的短代码来阅读和编辑。最终,业务规则总是会发生变化。

在您的用户界面代码中执行所有数据输入验证,将其与您的业务逻辑代码分开。将已经验证的数据传递给业务逻辑(这里是确定定价的代码)。这个想法是专注于单一的责任。业务逻辑代码应该只负责了解日期和时间定价方案的工作,而不是与用户交互。同样,UI 代码不应该知道呼叫成本的基本细节,而应该只知道足以验证数据输入。

代替一系列if语句,使用Oracle 教程switch中所示的方法。

尽可能使用智能对象而不是哑字符串或整数。Java 提供了enum,因此请使用这七个预定义对象而不是笨拙的字符串。同样,我们有一个不带日期和不带时区的时间类。DayOfWeek LocalTime

Java 具有强大的本地化功能。所以不需要硬编码美元符号和星期几的名称。

Scanner使用完后,应关闭诸如 a 之类的资源。try-with-resources语法可以自动完成这项工作。

示例代码

这是一些示例代码。不适用于生产,未经测试。但是对于学习 Java 的人来说应该很有趣。

在实际工作中,我会:

  • 做更多的错误检查,比如检查扫描仪是否关闭。
  • 将每个解析部分(小时、AM/PM 和星期几)提取到子例程(命名为私有方法)中。
  • 将常规语句替换为Java 12 和 Java 13 中预览switch的新简化switch语句。
  • 在每次提示时为用户提供退出选项,例如q退出。
  • 使用单元测试来验证逻辑。

首先,业务逻辑部分。

package work.basil.example;

import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;

public class CallCostEstimator
{
    private Set < DayOfWeek > weekdays = EnumSet.of ( DayOfWeek.MONDAY , DayOfWeek.TUESDAY , DayOfWeek.WEDNESDAY , DayOfWeek.THURSDAY , DayOfWeek.FRIDAY );
    LocalTime daytimeStart = LocalTime.of ( 8 , 0 );
    LocalTime daytimeStop = LocalTime.of ( 18 , 0 );

    BigDecimal weekday_day_rate = new BigDecimal ( "4.5" );
    BigDecimal weekday_night_rate = new BigDecimal ( "4.0" );
    BigDecimal weekend_rate = new BigDecimal ( "2.25" );

    public BigDecimal estimate ( LocalTime localTime , DayOfWeek dayOfWeek )
    {
        Objects.requireNonNull ( localTime );
        Objects.requireNonNull ( dayOfWeek );

        boolean isWeekday = ( weekdays.contains ( dayOfWeek ) );
        boolean isDaytimeHours = ( ! localTime.isBefore ( this.daytimeStart ) ) && ( localTime.isBefore ( this.daytimeStop ) );

        // Determine price slot
        BigDecimal result = null;
        if ( ! isWeekday )
        {
            result = this.weekend_rate;   // In other cases we would make a copy before returning an object stored within this class. But `BigDecimal` is immutable, so not necessary.
        } else
        { // Else is weekday.
            if ( isDaytimeHours )
            {
                result = this.weekday_day_rate;
            } else
            {
                result = this.weekday_night_rate;
            }
        }
        if ( Objects.isNull ( result ) ) // Should not be possible if our cascade of `if` statements is complete and correct. Defensive programming requires that we check.
        {
            throw new IllegalStateException ( "Failed to find a price slot." );
        }
        return result;
    }


}

和用户界面部分。

package work.basil.example;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.time.DayOfWeek;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.format.TextStyle;
import java.util.*;

public class CallCostEstimateConsole
{
    public static void main ( String[] args )
    {
        CallCostEstimateConsole app = new CallCostEstimateConsole ();
        app.engageUser ();
    }


    public void engageUser ( )
    {
        // Use try-with-resources syntax to auto-close the scanner.
        try (
                Scanner scanner = new Scanner ( System.in ) ;
        )
        {

            System.out.println ( "To calculate the cost per minute of your long-distance call, we'll need some information." );
            Integer hour = null;
            while ( Objects.isNull ( hour ) )
            {
                System.out.println ( "What hour are you planning on making the call?  Minutes aren't necessary. Please only enter the hour number, 1-12 for 12-hour clock. (ex. 8)" );
                try
                {
                    int input = scanner.nextInt ();
                    if ( ( input < 1 ) || ( input > 12 ) )
                    {
                        System.out.println ( "Hour must be from 1 to 12." );
                    } else
                    {
                        hour = input;
                    }
                } catch ( InputMismatchException e )
                {
                    System.out.println ( "Error: Enter a digits only, for a number from 1 to 12. " );
                }
            }

            String amPm = null;
            while ( Objects.isNull ( amPm ) )
            {
                System.out.println ( "Is the call taking place AM or PM? (type either AM or PM, or am or pm)" );
                String input = scanner.next ();
                input = input.toUpperCase ();
                if ( input.equals ( "AM" ) || ( input.equals ( "PM" ) ) )
                {
                    amPm = input;
                } else
                {
                    System.out.println ( "You typed something other than AM or PM." );
                    continue;
                }
                // Tweak inputs for 12-hour to 24-hour conversion.
                if ( amPm.equals ( "AM" ) && ( hour == 12 ) )
                {
                    hour = 0;
                }
            }
            // If 1 PM through 11 PM, add 12 hours for 24-hour time.
            hour = ( amPm.equals ( "PM" ) & ( hour < 12 ) ) ? ( hour + 12 ) : hour;  // Ternary statement. A compact alternative to an `if` statement.
            LocalTime localTime = LocalTime.of ( hour , 0 );

            DayOfWeek dayOfWeek = null;
            while ( Objects.isNull ( dayOfWeek ) )
            {
                System.out.println ( "And what day of the week is that? Please enter weekday with only first two letters. (ex. Fr)" );
                try
                {
                    String input = scanner.next ().toLowerCase ();
                    if ( input.isEmpty () )
                    {
                        System.out.println ( "You did not type any characters. " );
                        continue; // Break-out to continue on to the next loop.
                    }

                    // Parsing logic.
                    switch ( input )
                    {
                        case "mo":
                            dayOfWeek = DayOfWeek.MONDAY;
                            break;
                        case "tu":
                            dayOfWeek = DayOfWeek.TUESDAY;
                            break;
                        case "we":
                            dayOfWeek = DayOfWeek.WEDNESDAY;
                            break;
                        case "th":
                            dayOfWeek = DayOfWeek.THURSDAY;
                            break;
                        case "fr":
                            dayOfWeek = DayOfWeek.FRIDAY;
                            break;
                        case "sa":
                            dayOfWeek = DayOfWeek.SATURDAY;
                            break;
                        case "su":
                            dayOfWeek = DayOfWeek.SUNDAY;
                            break;
                        default:
                            String message = "You did not type a 2-letter day-of-week code as expected. (Mo, Tu, We, Th, Fr, Sa, Su)";
                            throw new IllegalStateException ( message );
                    }
                } catch ( InputMismatchException e )
                {
                    System.out.println ( "Error: Enter a digits only, for a number from 1 to 12. " );
                }
            }

            // Calculate result.
            CallCostEstimator estimator = new CallCostEstimator ();
            BigDecimal estimate = estimator.estimate ( localTime , dayOfWeek );

            // Report result.
            String output = NumberFormat.getInstance ( Locale.US ).getCurrencyInstance ().format ( estimate );
            DateTimeFormatter f = DateTimeFormatter.ofLocalizedTime ( FormatStyle.SHORT ).withLocale ( Locale.US );
            String dow = dayOfWeek.getDisplayName ( TextStyle.FULL , Locale.US );
            String message = "Your call at " + localTime.format ( f ) + " on " + dow + " will cost per minute: " + output;
            System.out.println ( message );

        }
    }
}

示例运行。

To calculate the cost per minute of your long-distance call, we'll need some information.
What hour are you planning on making the call?  Minutes aren't necessary. Please only enter the hour number, 1-12 for 12-hour clock. (ex. 8)
1
Is the call taking place AM or PM? (type either AM or PM, or am or pm)
am
And what day of the week is that? Please enter weekday with only first two letters. (ex. Fr)
mo
Your call at 1:00 AM on Monday will cost per minute: $4.00

推荐阅读