Hi,

I am desperately hoping that someone can help me as I have got myself in a big mess. I have only started learning Java.
Essentially I have an assignment that included 2 stages. The first stage required us to include all the elements in one class
(I was able to do this successfully), however i ran into trouble in the second stage where we needed to use 2 classes.

Please note: I have chopped and changed so many things to find a solution (changed things from private to public, and auto created numerous
getters), so it is very much a work in progress. Please go easy on me!!!

My error is:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "RainGauge.displayDetails()" because "this.rainGauge" is null
at StageB.displayDetailsWithConsole(StageB.java:184)
at StageB.menuFunctions(StageB.java:114)
at StageB.menuChoices(StageB.java:82)
at StageB.setup(StageB.java:73)
at StageB.<init>(StageB.java:40)
at StageB.main(StageB.java:286)

import java.util.Random;
import java.util.Scanner;
 
public class StageB {
 
    Scanner kb = new Scanner(System.in);
 
    Random randomNumber = new Random();
 
    private char selection;
 
    private int currentNum;
 
    private int size;
 
    int startDayInput;
    int endDayInput;
    int thresholdInput;
 
    private int dailyRainfallInput;
 
private String rainGaugeLocationInput;
private float rainGaugeLatitudeInput;
private float rainGaugeLongitudeInput;
private int daysOfDataInput;
 
private int rainGaugeIdGenerate;
 
private int currentNumGaugesSelection;
 
private int maxNumGaugesSelection;
 
private RainGauge rainGauge;
//rainGauge = new RainGauge(rainGaugeLocationInput, rainGaugeLatitudeInput, rainGaugeLongitudeInput, daysOfDataInput);  
 
private Object rG;
 
    public StageB() {
setup();
rainGauge = new RainGauge(rainGaugeLocationInput, rainGaugeLatitudeInput, rainGaugeLongitudeInput, daysOfDataInput);
    }
public void setup() {
    if (rainGauge == null) {
        System.out.println("Do you want to create a [n]ew Rain Gauge or [d]isplay an existing one?");
        System.out.println("***Please enter the letter corresponding to your choice***");
        this.selection = kb.nextLine().toLowerCase().charAt(0);
 
        if (selection == 'n') {
            rainGaugeIdGenerate = randomNumber.nextInt(10000);
 
            System.out.println("Enter the site/location of the new Rain Gauge");
            rainGaugeLocationInput = kb.nextLine().toUpperCase();
 
            System.out.println("Enter the latitude of the site/location (in decimal degrees, 6 decimal places)");
            rainGaugeLatitudeInput = Float.parseFloat(kb.nextLine());
 
            System.out.println("Enter the longitude of the site/location (in decimal degrees, 6 decimal places)");
            rainGaugeLongitudeInput = Float.parseFloat(kb.nextLine());
 
            System.out.println("How many days of data do you want to enter for " + rainGaugeLocationInput + " rain gauge?");
            daysOfDataInput = Integer.parseInt(kb.nextLine());
 
            System.out.println("SUCCESS - NEW RAIN GAUGE ENTERED");
 
        } else if (selection == 'd') {
            rainGauge.displayDetails(); 
        } else
            System.out.println("INVALID CHOICE, PLEASE TRY AGAIN");
    }
 
 
    menuChoices();
}
 
    public void menuChoices() {
 
        userMenu();
 
        do {
            this.selection = kb.nextLine().toLowerCase().charAt(0);
            menuFunctions(selection);
        } while (selection != ' ');
        System.out.println("ERROR");
        this.selection = kb.nextLine().toLowerCase().charAt(0);
        menuFunctions(selection);
        // kb.close();
    }
 
    public void userMenu() {
 
        System.out.println("***Meteorological Monitoring Australia - Rain Gauge Menu***");
        System.out.println("===========================================================");
        System.out.println("***Please enter the letter corresponding to your choice***");
        System.out.println("Create/Update [R]ain Gauge");
        System.out.println("[D]isplay Rain Gauge Details");
        System.out.println("[A]dd Daily Rainfall Data");
        System.out.println("[P]rint Daily Rainfall Data");
        System.out.println("Display Rainfall [H]istogram");
        System.out.println("Display [M]aximum Rainfall");
        System.out.println("Determine if Rainfall is Below [T]hreshold");
        System.out.println("Display [S]tatistical Analysis");
        System.out.println("E[x]it");
 
    }
 
    public void menuFunctions(char selection) {
        switch (selection) {
 
        case 'r':
            createRainGauge();
            break;
        case 'd':
            displayDetailsWithConsole();
            break;
        case 'a':
            addRainfallDataWithConsole();
            break;
        case 'p':
            printRainfallDataWithConsole();
            break;
        case 'h':
            displayHistogramWithConsole();
            break;
        case 'm':
            displayMaximumRainfallWithConsole();
            break;
        case 't':
            belowThresholdWithConsole(startDayInput, endDayInput, thresholdInput);
            break;
        case 's':
            statisticalAnalysisWithConsole();
            break;
        case 'x':
            System.out.println("Thank you for using the 'Meteorological Monitoring Australia - Rain Gauge Program'");
            break;
        default:
            System.out.println("ERROR - PLEASE MAKE A VALID SELECTION");
            break;
        }
        System.out.println();
        userMenu();
    }
 
    private void createRainGauge() {
 
        //currentNumGaugesSelection = rainGauge.getCurrentNumGauges();
        //maxNumGaugesSelection = rainGauge.getMaxNumGauges();
 
        System.out.println("Do you want to create a [n]ew Rain Gauge or [d]isplay an existing one?");
        System.out.println("***Please enter the letter corresponding to your choice***");
        this.selection = kb.nextLine().toLowerCase().charAt(0);
 
        if (selection == 'n') {
            rainGaugeIdGenerate = randomNumber.nextInt(10000);
 
            System.out.println("Enter the site/location of the new Rain Gauge");
            rainGaugeLocationInput = kb.nextLine().toUpperCase();
 
            System.out.println("Enter the latitude of the site/location (in decimal degrees, 6 decimal places)");
            rainGaugeLatitudeInput = Float.parseFloat(kb.nextLine());
 
            System.out.println("Enter the longitude of the site/location (in decimal degrees, 6 decimal places)");
            rainGaugeLongitudeInput = Float.parseFloat(kb.nextLine());
 
            System.out.println("How many days of data do you want to enter for " + rainGaugeLocationInput + " rain gauge?");
            daysOfDataInput = Integer.parseInt(kb.nextLine());
 
            System.out.println("SUCCESS - NEW RAIN GAUGE ENTERED");
 
            boolean added = this.rainGauge.rainGaugeCreated(rainGaugeLocationInput, rainGaugeLatitudeInput, rainGaugeLongitudeInput,
                    daysOfDataInput);
            if (!added) {
                System.out.println("ERROR, COULD NOT ADD RAIN GAUGE");
 
        } else if (selection == 'd') {
            rainGauge.displayDetails(); 
        } else
            System.out.println("INVALID CHOICE, PLEASE TRY AGAIN");
    }
    }
 
     public void  displayDetailsWithConsole() {
            rainGauge.displayDetails(); 
        }
 
    public void statisticalAnalysisWithConsole() {
        rainGauge.statisticalAnalysis();    
    }
 
    public void belowThresholdWithConsole(int startDay, int endDay, int threshold) {
 
 
        System.out.println("***Determining if all days within specific timeframe have rainfall below threshold amount***");
        System.out.println("");
        System.out.println("In reference to the data stored above, please enter a day number to start the timeframe (day number ' ')");
        startDayInput = getIntegerInput();
        System.out.println("In reference to the data stored above, please enter a day number to end the timeframe (day number ' ')");
        endDayInput = getIntegerInput();
System.out.println("Please enter a threshold (in whole mm) to check the data against");
        thresholdInput = getIntegerInput();
        rainGauge.belowThreshold(startDayInput, endDayInput, thresholdInput);   
    }
 
    public void displayMaximumRainfallWithConsole() {
        rainGauge.displayMaximumRainfall(); 
    }
 
    public void displayHistogramWithConsole() {
        rainGauge.displayHistogram();   
    }
    public void printRainfallDataWithConsole() {
    rainGauge.printRainfallData();
}
    public void addRainfallDataWithConsole() {
        rainGauge.addRainfallData();    
    }
    public int getIntegerInput() {
        int userInput = Integer.parseInt(kb.nextLine());
        return userInput;
    }
 
 
    public String getRainGaugeLocationInput() {
        return rainGaugeLocationInput;
    }
 
    public float getRainGaugeLatitudeInput() {
        return rainGaugeLatitudeInput;
    }
 
    public float getRainGaugeLongitudeInput() {
        return rainGaugeLongitudeInput;
    }
 
    public int getDaysOfDataInput() {
        return daysOfDataInput;
    }
 
    public int getDailyRainfallInput() {
        return dailyRainfallInput;
    }
 
    public int getStartDayInput() {
        return startDayInput;
    }
 
    public int getEndDayInput() {
        return endDayInput;
    }
 
    public int getThresholdInput() {
        return thresholdInput;
    }
 
    public Random getRandomNumber() {
        return randomNumber;
    }
 
    public char getSelection() {
        return selection;
    }
 
    public int getCurrentNum() {
        return currentNum;
    }
 
    public int getSize() {
        return size;
    }
 
    public int getRainGaugeIdGenerate() {
        return rainGaugeIdGenerate;
    }
 
    public int getCurrentNumGaugesSelection() {
        return currentNumGaugesSelection;
    }
 
    public int getMaxNumGaugesSelection() {
        return maxNumGaugesSelection;
    }
 
 
    public static void main(String[] args) {
        StageB rainGaugeObject = new StageB();
    //rainGaugeObject.menuChoices();
 
 
    }
}

public class RainGauge {
 
    StageB stageBObject = new StageB();
 
    private int rainGaugeId;
    private String rainGaugeLocation;
    private float rainGaugeLatitude;
    private float rainGaugeLongitude;
    private int daysOfData;
 
    private int dailyRainfall;
 
    private char selection;
 
    int maxRainfall;
    int totalRainfall;
 
    int threshold;
    int startDay;
    int endDay;
 
    private int maxNumGauges = 3;
    private int currentNumGauges = 0;
 
    private int currentNumRainfall = 0;
 
    private RainGauge[] rG = new RainGauge[this.maxNumGauges];
    private int[] rD = new int[this.daysOfData];
 
    public RainGauge(String rainGaugeLocation, float rainGaugeLatitude, float rainGaugeLongitude, int daysOfData) {
        this.rainGaugeId = rainGaugeId;
        this.rainGaugeLocation = rainGaugeLocation;
        this.rainGaugeLatitude = rainGaugeLatitude;
        this.rainGaugeLongitude = rainGaugeLongitude;
        this.daysOfData = daysOfData;
 
    }
 
    public RainGauge(int dailyRainfall) {
        this.dailyRainfall = dailyRainfall;
    }
 
    public boolean rainGaugeCreated(String rainGaugeLocation, float rainGaugeLatitude, float rainGaugeLongitude,
            int daysOfData) {
 
        boolean added = false;
 
        rainGaugeLocation = stageBObject.getRainGaugeLocationInput();
        rainGaugeLatitude = stageBObject.getRainGaugeLatitudeInput();
        rainGaugeLongitude = stageBObject.getRainGaugeLongitudeInput();
        daysOfData = stageBObject.getDaysOfDataInput();
 
        if (this.currentNumGauges <= this.maxNumGauges) {
            this.rG[this.currentNumGauges] = new RainGauge(rainGaugeLocation, rainGaugeLatitude, rainGaugeLongitude,
                    daysOfData);
            this.currentNumGauges += 1;
            added = true;
        }
        return added;
    }
 
    public void addRainfallData() {
 
        int count = (daysOfData - 1);
        if (daysOfData != 0) {
            System.out.println("You have a maximum of " + daysOfData + " days of rainfall data to enter");
        } else {
            System.out.println("ERROR, PLEASE ADD A RAIN GAUGE FIRST");
            stageBObject.userMenu();
        }
        for (int currentNum = 0; currentNum < rD.length; currentNumRainfall++) {
 
            System.out.println("Enter the daily rainfall (in whole mm)");
            dailyRainfall = stageBObject.getDailyRainfallInput();
            this.rD[currentNumRainfall] = dailyRainfall;
            System.out.println("You have " + count + " days of data left to enter");
            count--;
        }
        if (currentNumRainfall > rD.length) {
            System.out.println("ERROR, YOU HAVE EXCEEDED THE MAXIMUM STORAGE LIMIT");
        }
 
        System.out.println("----------------------------------------------------");
        System.out.println("A summary of the data that you have entered");
        int j = 0;
        int day = 1;
        while (j < rD.length) {
            System.out.println("Day " + day + " " + rD[j] + "mm");
            j += 1;
            day++;
        }
    }
 
    public void printRainfallData() {
        System.out.println("----------------------------------------------------");
        System.out.println("A summary of the data that you have entered");
        int j = 0;
        int day = 1;
        while (j < rD.length) {
            System.out.println("Day " + day + " " + rD[j] + "mm");
            j += 1;
            day++;
        }
    }
 
    public void displayDetails() {
        if (rainGaugeId != 0 && !rainGaugeLocation.isBlank() && rainGaugeLatitude != 0 && rainGaugeLongitude != 0
                && daysOfData != 0) {
            System.out.println(
                    "-------------------------------------------------------------------------------------------------");
            String tableHeadingsFormat = "%-15s%-25s%-15s%-15s%-15s\n";
            String tableDataFormat = "%10d%23s%22.6f%15.6f%16d\n";
            System.out.printf(tableHeadingsFormat, "Site/Location ID #  |", "Site/Location Name  |", "Latitude   |",
                    "Longitude    |", "Number of days data |");
            System.out.printf(tableDataFormat, rainGaugeId, rainGaugeLocation, rainGaugeLatitude, rainGaugeLongitude,
                    daysOfData);
            System.out.println(
                    "-------------------------------------------------------------------------------------------------");
        } else
            System.out.println("THERE ARE NO RAIN GAUGE DETAILS TO DISPLAY, PLEASE CREATE A RAIN GAUGE FIRST");
    }
 
    public void statisticalAnalysis() {
 
        for (int i = 0; i < rD.length; i++) {
            totalRainfall += rD[i];
        }
 
        float daysOfDataAverage = this.daysOfData;
        float totalRainfallAverage = this.totalRainfall;
        float averageRainfall = (totalRainfallAverage / daysOfDataAverage);
        float averageRainfallDisplay = Math.round(averageRainfall);
 
        int belowAverage = 0;
        int equalAverage = 0;
        int aboveAverage = 0;
 
        for (int i = 0; i < rD.length; i++) {
            if (rD[i] < averageRainfall) {
                belowAverage += 1;
            } else if (rD[i] > averageRainfall) {
                aboveAverage += 1;
            } else {
                equalAverage += 1;
            }
 
        }
 
        System.out.println(
                "----------------------------------------------------------------------------------------------------------------------");
        String statisticsHeadingsFormat = "%-15s%-15s%-15s%-15s%-15s%-15s\n";
        String statisticsFormat = "%7d%14d%18.0f%20d%22d%24d\n";
        System.out.printf(statisticsHeadingsFormat, "Days of Data |", "Total (mm) |", "Daily Average (mm) |",
                "Days Below Average  |", "Days Equal to Average |", "Days Above Average |");
        System.out.printf(statisticsFormat, daysOfData, totalRainfall, averageRainfallDisplay, belowAverage,
                equalAverage, aboveAverage);
        System.out.println(
                "----------------------------------------------------------------------------------------------------------------------");
        System.out.println("");
    }
 
    public boolean belowThreshold(int startDay, int endDay, int threshold) {
 
        int totalBelow = 0;
 
        int startDayCalculation = stageBObject.getStartDayInput();
        startDay = (startDayCalculation - 1);
 
        int endDayCalculation = stageBObject.getEndDayInput();
        endDay = (endDayCalculation - 1);
 
        printRainfallData();
        System.out.println("");
 
        int timeframe = (endDay - startDay) + 1;
        int[] subArray = new int[timeframe];
        int n = 0;
        int thresholdDay = startDay + 1;
 
        for (int i = startDay; i <= endDay; i++) {
            System.out.println("Rainfall (mm) " + rD[i] + " on Day " + thresholdDay);
            subArray[n] = rD[i];
            n++;
            thresholdDay++;
        }
 
        System.out.println("");
        System.out.println("New set of Data");
        System.out.println("");
 
        for (int m = 0; m < subArray.length; m++) {
            System.out.println("Rainfall (mm) " + subArray[m] + " on Day " + m);
        }
 
        System.out.println("");
 
        boolean below = false;
 
        for (int l = 0; l < subArray.length; l++) {
            if (subArray[l] < threshold) {
                below = true;
                totalBelow += 1;
            }
        }
        System.out.println(
                "The number of days below the threshold of " + threshold + " mm" + " is " + totalBelow + " day/s");
        return true;
    }
 
    public void displayMaximumRainfall() {
 
        int minRainfall;
        maxRainfall = this.rD[0];
        minRainfall = this.rD[0];
 
        for (int i = 1; i < rD.length - 1; i = i + 2) {
            if (i + 1 > rD.length) {
                if (this.rD[i] > maxRainfall)
                    maxRainfall = this.rD[i];
                if (this.rD[i] < minRainfall)
                    minRainfall = this.rD[i];
            }
            if (this.rD[i] > this.rD[i + 1]) {
                if (this.rD[i] > maxRainfall)
                    maxRainfall = this.rD[i];
                if (this.rD[i + 1] < minRainfall)
                    minRainfall = this.rD[i + 1];
            }
            if (this.rD[i] < this.rD[i + 1]) {
                if (this.rD[i] < minRainfall)
                    minRainfall = this.rD[i];
                if (this.rD[i + 1] > maxRainfall)
                    maxRainfall = this.rD[i + 1];
            }
 
        }
        System.out.println("The maximum rainfall value stored is " + maxRainfall + " mm");
    }
 
    public void displayHistogram() {
 
        String display09 = ("0-9mm");
        String display1019 = ("10-19mm");
        String display2029 = ("20-29mm");
        String display3039 = ("30-39mm");
        String display4049 = ("40-49mm");
        String display5059 = ("50-59mm");
 
        System.out.println("----------------------------------------------------");
        System.out.println("Histogram: Spread of Rainfall ('*' represents each day of data)");
        System.out.println("====================================================");
 
        System.out.print(display09);
 
        for (int j = 0; j < rD.length; j++) {
 
            if (rD[j] >= 0 && rD[j] < 10)
                System.out.print("|*|");
        }
        System.out.println();
        System.out.println("====================================================");
        System.out.print(display1019);
 
        for (int j = 0; j < rD.length; j++) {
 
            if (rD[j] >= 10 && rD[j] < 20)
                System.out.print("|*|");
        }
        System.out.println();
        System.out.println("====================================================");
 
        System.out.print(display2029);
 
        for (int j = 0; j < rD.length; j++) {
 
            if (rD[j] >= 20 && rD[j] < 30)
                System.out.print("|*|");
        }
        System.out.println();
        System.out.println("====================================================");
 
        System.out.print(display3039);
 
        for (int j = 0; j < rD.length; j++) {
 
            if (rD[j] >= 30 && rD[j] < 40)
                System.out.print("|*|");
        }
        System.out.println();
        System.out.println("====================================================");
 
        System.out.print(display4049);
 
        for (int j = 0; j < rD.length; j++) {
 
            if (rD[j] >= 40 && rD[j] < 50)
                System.out.print("|*|");
        }
        System.out.println();
        System.out.println("====================================================");
 
        System.out.print(display5059);
 
        for (int j = 0; j < rD.length; j++) {
 
            if (rD[j] >= 50 && rD[j] < 60)
                System.out.print("|*|");
        }
        System.out.println();
        System.out.println("====================================================");
        System.out.println("Histogram: Daily Rainfall ('*' represents 10mm of rain)");
        int day = 0;
        String asterisk = "";
 
        for (int j = 0; j < rD.length; j++) {
            day++;
            if (rD[j] >= 10 && rD[j] <= 19) {
                asterisk = " *";
                System.out.println("Day " + day + " " + asterisk);
            }
            if (rD[j] >= 20 && rD[j] <= 29) {
                asterisk = " **";
                System.out.println("Day " + day + " " + asterisk);
            }
            if (rD[j] >= 30 && rD[j] <= 39) {
                asterisk = " ***";
                System.out.println("Day " + day + " " + asterisk);
            }
            if (rD[j] >= 40 && rD[j] <= 49) {
                asterisk = " ****";
                System.out.println("Day " + day + " " + asterisk);
            }
            if (rD[j] >= 50 && rD[j] <= 59) {
                asterisk = " *****";
                System.out.println("Day " + day + " " + asterisk);
            }
        }
    }
 
    public int getThreshold() {
        return threshold;
    }
 
    public int getStartDay() {
        return startDay;
    }
 
    public int getEndDay() {
        return endDay;
    }
 
    public String getRainGaugeLocation() {
        return rainGaugeLocation;
    }
 
    public float getRainGaugeLatitude() {
        return rainGaugeLatitude;
    }
 
    public float getRainGaugeLongitude() {
        return rainGaugeLongitude;
    }
 
    public int getDaysOfData() {
        return daysOfData;
    }
 
    public int getDailyRainfall() {
        return dailyRainfall;
    }
 
    public int getMaxNumGauges() {
        return maxNumGauges;
    }
 
    public int getCurrentNumGauges() {
        return currentNumGauges;
    }
}