I'm new to java and I keep getting
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 4"
I've read similar questions on here, and tried to apply the fixes but none of them seem to work. Maybe I'm applying them wrong?
The error I get points to the line of code indicated by <<<<<<<<<
But the method I'm editing that caused the error to appear is indicated by ******
The code used to compile and run just fine before I added the defaultHolidays method (the method I'm editing that is causing the error). The goal of this method is to take the contents of a file and display them on the calendar that is printed to screen via an array. The contents of the file look like this:
1/1 New_Year's_Day
01/18 M_L_K_Day
and so on
Here's my code, sorry it's so long:
// Import general tools
import java.io.*;
import java.io.File; // Import the File class
import java.util.*;
// Import tools to get current date
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;
// Start of class
public class RCal3Winter21 {
// Start of main method
public static void main (String[] args) throws FileNotFoundException {
// define the basics
String[][] strEventArray = new String[12][]; // creates the array to be filled later
// helps run or break out of the program
int intRunCode = 1;
// helps prevent invalid input
int intRequestedMo = 15;
// greet the user
System.out.println();
System.out.printf("%30s %n", "Welcome to CalintEndar!");
System.out.printf("%36s %n", "~ for all your planning needs ~");
System.out.println();
// indicates how many boxes(days) are associated with each month
strEventArray = sizeOfArray (strEventArray);
//begin program in earnest
runMenu(intRequestedMo, strEventArray);
} // intEnd main method
// compiles on scratchpaper
// removes leading zero from month & converts to int
public static int noZoMo(String strTempDate) {
//break temp date string into individual chars
char month0 = strTempDate.charAt(0);
char month1 = strTempDate.charAt(1);
char slash = strTempDate.charAt(2);
char day1 = strTempDate.charAt(3);
char day2 = strTempDate.charAt(4); <<<<<< This is the line the error highlights
String strMo;
// If/else to display month w/out leading 0s
if (month0 == '0') {
strMo = String.valueOf(month1);
} else {
strMo = String.valueOf(month0) + String.valueOf(month1);
} // End of if/else loop to display month w/out leading 0s
// converts month from string to int
int intMo = Integer.parseInt(strMo);
// returns month without leading zeros
return intMo;
}
// compiles on scratchpaper
// removes leading zero from day & converts to int
public static int noZoDay(String strTempDate) {
//break temp date string into individual chars
char month0 = strTempDate.charAt(0);
char month1 = strTempDate.charAt(1);
char slash = strTempDate.charAt(2);
char day1 = strTempDate.charAt(3);
char day2 = strTempDate.charAt(4);
String strDay;
// If/else to display day w/out leading 0s
if (day1 == '0') {
strDay = String.valueOf(day2);
} else {
strDay = String.valueOf(day1) + String.valueOf(day2);
} // End of if/else loop to display day w/out leading 0s
// converts day from string to int
int intDay = Integer.parseInt(strDay);
// returns day without leading zeros
return intDay;
}
// compiles in scratchpaper
// displays the menu and gather's the user's response
// returns response as a string to be worked with
public static String menuDisplay() {
// prints menu and prompts for input
System.out.println();
System.out.println("Please pick from the menu below");
System.out.println("\t\"e\" to enter a date and display it's calendar.");
System.out.println("\t\"ev\" to input an event.");
System.out.println("\t\"fp\" to save your calendar to a file");
System.out.println("\t\"t\" to get today's date and display today's calendar");
System.out.println("\t\"n\" to display the next month");
System.out.println("\t\"p\" to display the previous month");
System.out.println("\t\"q\" to quit CalintEndar");
// Scanner to gather user input
Scanner in = new Scanner(System.in);
// assigns user input to string
String command = in.nextLine();
// ignores case used
command = command.toLowerCase();
// returns the user input
return command;
} // intEnd menueDisplay method
// can't run in scratchpaper, too many method calls
// converts the user input to actions
public static void runMenu(int intRequestedMo, String[][] strEventArray) throws FileNotFoundException {
// method tools
boolean booRunProg = true; // value continues to run or breaks out of while loop
String strUsrInput;
// while loop to run menu selection & allow exit
while (booRunProg == true) {
strUsrInput = menuDisplay(); // sets input val frm menuDisplay to local str
// for use in this method/while loop
switch (strUsrInput) { // checks user input against menu options
case "e": // user requests specific date
intRequestedMo = optionE(strEventArray);
break;
case "t": // user requests today's date
intRequestedMo = optionT(strEventArray);
break;
case "n": // user wants to see the next month
intRequestedMo = optionN(intRequestedMo, strEventArray);
break;
case "p": // user wants to see previous month
intRequestedMo = optionP(intRequestedMo, strEventArray);
break;
case "ev": // user wants to add event
strEventArray = optionEV(strEventArray);
break;
case "fp": // user wants to save event
optionFP( strEventArray);
break;
case "q": // user wants to quite program
System.out.println("Thanks for using Calendar!");
booRunProg = false;
break;
default: // user made an error, try again
System.out.println("Invalid command. Please try again.");
break;
} // end switch case
} // end while loop
} // end runMenu method
// runs in scratchpaper, but without method call
// user enters a requested date
public static int optionE(String[][] strEventArray){
// Prompt user
System.out.println("What date would you like to see? (mm/dd)");
// Scanner to gather user input
Scanner input = new Scanner(System.in);
// set user input to a string
String strTempDate = input.next();
// remove the leading zeros from the current date
int intRequestedMo = noZoMo(strTempDate);
// returns the value of the current date as a string
drawCalnDate(strEventArray, intRequestedMo);
return intRequestedMo;
} // end optionE method
// runs in scratchpaper without method call
// show today's date
public static int optionT(String[][] strEventArray)
throws FileNotFoundException {
// get current date
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd");
LocalDateTime now = LocalDateTime.now();
// convert current date information to a string
String strTempDate = dtf.format(now);
// remove the leading zeros from the current date
int intRequestedMo = noZoMo(strTempDate);
defaultHolidays(strEventArray, intRequestedMo);
drawCalnDate(strEventArray, intRequestedMo);
// returns the value of the current date as a string
return intRequestedMo;
} // end optionT method
// runs in scratchpaper w/out method calls
// user wants to see the next month
public static int optionN(int intRequestedMo, String[][] strEventArray)
throws FileNotFoundException {
// making sure there's a calendar on the screen
if (intRequestedMo == 15) {
System.out.println("Error. Must select a calendar first.");
return intRequestedMo;
} // end if
else { // ensure cal goes from december to january
if (intRequestedMo == 12){
intRequestedMo = 1;
defaultHolidays(strEventArray, intRequestedMo);
drawCalnDate(strEventArray, intRequestedMo);
} else {
intRequestedMo++;
defaultHolidays(strEventArray, intRequestedMo);
drawCalnDate(strEventArray, intRequestedMo);
return intRequestedMo;
} // end else
}// end first if
return intRequestedMo;
} // end optionN method
// runs in scratchpaper w/out method calls
// user wants to see previous month
public static int optionP(int intRequestedMo, String[][] strEventArray)
throws FileNotFoundException {
// making sure there's a calendar on the screen
if (intRequestedMo == 15) {
System.out.println("Error. Must select a calendar first.");
return intRequestedMo;
} else { // ensure cal goes from january to december
if (intRequestedMo == 1){
intRequestedMo = 12;
defaultHolidays(strEventArray, intRequestedMo);
drawCalnDate(strEventArray, intRequestedMo);
} else {
intRequestedMo--;
defaultHolidays(strEventArray, intRequestedMo);
drawCalnDate(strEventArray, intRequestedMo);
} // end second if/else
} // end first if/else
return intRequestedMo;
}
// user wants to add an event
public static String[][] optionEV (String[][] strEventArray) throws FileNotFoundException {
// create scanner
Scanner userIn = new Scanner(System.in);
// prompt for date for the event
System.out.println();
System.out.println("When is the event? (mm/dd format)");
// get date from user
String strNewEvDate = userIn.next();
// remove zeros and change to ints
int intMo = noZoMo(strNewEvDate);
int intDay = noZoDay(strNewEvDate);
// prompt for event name
System.out.println();
System.out.println("What's happening?");
System.out.println("Title the event in event_name format.");
System.out.println("19 characters or less");
// get event name from user
String strNewEvent = userIn.next();
// puts event in array
strEventArray[intMo-1][intDay-1] = strNewEvent;
// return updates to strEventArray
return strEventArray;
} // end optionEV method
// user wants to print a month to file
public static void optionFP(String[][] strEventArray) throws FileNotFoundException {
// create scanner
Scanner userIn = new Scanner(System.in);
// prompt user
System.out.print("What month would you like to print to a file?");
// get user input
int printMonth = userIn.nextInt();
//<<
} // end optionFP method
public static String[][] defaultHolidays (String[][] strEventArray, int intRequestedMo) *********
throws FileNotFoundException {
File readFile = new File("defaultHolidays.txt"); // checks for file to be read
String strFileDate = "temp";
String strFileEvent = "temp";
String event;
String date;
int intFileMo = 0;
int intFileDay = 0;
// new scanner to read the file
Scanner input = new Scanner(readFile);
//System.out.println();
// to print the file to the screen
while (input.hasNext()) {
date = input.next();
strFileEvent = input.nextLine().trim();
if (date.length() != 4) {
System.out.println("There is an error in the file");
System.out.println("Date must be in mm/dd format");
} else {
intFileMo = noZoMo(date);
intFileDay = noZoDay(date);
strEventArray[intFileMo-1][intFileDay-1] = strFileEvent;
}
} // end while
return strEventArray;
} // end method defaultHolidays
public static String[][] sizeOfArray (String[][] strEventArray) {
strEventArray[0] = new String[31];
strEventArray[1] = new String[28];
strEventArray[2] = new String[31];
strEventArray[3] = new String[30];
strEventArray[4] = new String[31];
strEventArray[5] = new String[30];
strEventArray[6] = new String[31];
strEventArray[7] = new String[31];
strEventArray[8] = new String[30];
strEventArray[9] = new String[31];
strEventArray[10] = new String[30];
strEventArray[11] = new String[31];
return strEventArray;
} // end method to indicate num boxes in each array "row"
// indicates how many days are in each month
public static int daysInMo(int intRequestedMo) {
// if then to determine number of days in month
if (intRequestedMo == 4 || intRequestedMo == 6 ||
intRequestedMo == 9 || intRequestedMo == 11) {
return 30;
}
else if (intRequestedMo == 2) {
return 28;
}
else {
return 31;
}
} // end daysInMonth method
// method to display month on top of calendar
public static void topDateDisp(int intRequestedMo) {
// declarations
String centSngl;
String centDbl;
String mon = "Monday";
String tue = "Tuesday";
String wed = "Wednesday";
String thu = "Thursday";
String fri = "Friday";
String sat = "Saturday";
String sun = "Sunday";
// if to account for double digits
if (intRequestedMo > 0 && intRequestedMo < 10) {
for (int i = 1; i <= 71; i++) { // for to center
System.out.print(" ");
} // end for to center month
System.out.println(intRequestedMo);
} // end if for single digit
else {
for (int i = 1; i <= 70; i++) { // for to center
System.out.print(" ");
} // end for to center month
System.out.println(intRequestedMo);
} // end else if double digit
// line break for aesthetics
System.out.println();
// print the days of the week at the top of the calendar
System.out.printf("%13s%21s%21s%19s%19s%21s%18s %n", mon, tue, wed, thu, fri, sat, sun );
} // end topDateDisp
// method to change start day of the week
public static int[] getStartEnd (int intRequestedMo) {
// declare array variable
int[] intStartEndAry = new int[2];
if (intRequestedMo == 2 || intRequestedMo == 3 || intRequestedMo == 11) {
intStartEndAry[0] = 1; // mon
intStartEndAry[1] = 7;
} else if (intRequestedMo == 6) {
intStartEndAry[0] = 0; // tues
intStartEndAry[1] = 6;
} else if (intRequestedMo == 9 || intRequestedMo == 12) {
intStartEndAry[0] = -1; // weds
intStartEndAry[1] = 5;
} else if (intRequestedMo == 4 || intRequestedMo == 7) {
intStartEndAry[0] = -2; // thurs
intStartEndAry[1] = 4;
} else if (intRequestedMo == 1 || intRequestedMo == 10) {
intStartEndAry[0] = -3; // fri
intStartEndAry[1] = 3;
} else if (intRequestedMo == 5) {
intStartEndAry[0] = -4; // sat
intStartEndAry[1] = 2;
} else {
intStartEndAry[0] = -5; // sun
intStartEndAry[1] = 1;
}
return intStartEndAry;
} // end getStartEnd
// Start of method to fill in date rows on the calendar
public static void drawDateRow (int intDaysInMo, int intRequestedMo, int intStart, int intEnd) {
String single = " ";
String dble = " ";
// for loop to create row length
for (int i = intStart; i <= intEnd; i++) {
if(i <= 9 && i > 0) {
System.out.print("|" + i + single);
} else if (i > 9 && i <= intDaysInMo) {
System.out.print("|" + i + dble);
} else { // handles the hanging days at the end of the month
System.out.print("|" + single + " ");
} // End of nested if/else loop to account for double digits
} // intEnd of for loop to draw calendar & dates
System.out.println("|"); // Draws last pipe to complete calendar
} // end method
public static void drawEventRow(int intRequestedMo, int intDaysInMo, String[][] strEventArray,
int intStart, int intEnd) {
// declarations
int intEvtLength;
String strEvtName;
int intNumSpaces;
// for to create row length, fill with events, or draw blanks
for (int i = intStart; i < intEnd; i++) { // creates row length
// if the requested day is more than 1 and less than the max days in the month
if ( i > 0 && i <= intDaysInMo) {
// if array slot has a value
if (strEventArray[intRequestedMo - 1][i - 1] != null){
// get the event name from the array
strEvtName = strEventArray[intRequestedMo - 1][i - 1];
// get the length of the event name
intEvtLength = strEvtName.length();
// make room for the event
intNumSpaces = 19 - intEvtLength;
// print the first | of the calendar design
System.out.print("|");
// print the event name
System.out.print(strEvtName);
// loop to print event or blank depending on array
for (int k = 1; k <= intNumSpaces; k++) {
System.out.print(" ");
} // end innnermost for loop
// if the array slot is null
} else {
System.out.print("| ");
} // end second if/else
// if the day number is less than 0 or more than max days of month
} else {
System.out.print("| ");
} // end first if/else
}// end for
} // end drawEventRow method
// Start of method to draw horizontal line for the calendar
public static void drawLine() {
// Start of for loop to draw horizontal line for the calendar
for (int i = 1; i <= 141; i++) {
System.out.print("~");
} // End of for loop to draw horizontal line for the calendar
System.out.println(); // line break
} // End of of method to draw horizontal line for the calendar
// Start of method to create spaces in the calendar
public static void drawSpace() {
// draws the blanks in the days
for (int j = 1; j <= 5; j++){
// Start of nested space for loop
for (int i = 1; i <= 7; i++) {
System.out.print("| ");
} // End of nested space for loop
System.out.println("|"); // Draws last pipe to complete calendar
} // End of method to create spaces in the calendar
}
// Start of method to draw calendar & dates together
public static void drawCalnDate(String[][] strEventArray, int intRequestedMo) {
// declare variables
int intDaysInMo;
int[] aryStartEnd = new int[2];
// initialize variables
intDaysInMo = daysInMo(intRequestedMo); // get num days in req'd month
aryStartEnd = getStartEnd(intRequestedMo); // get start/end values once
// separate the values of the array
int intStart = aryStartEnd[0];
int intEnd = aryStartEnd[1];
topDateDisp(intRequestedMo);
// if/else to display only required rows of weeks
if (intRequestedMo == 2) {
// Start of for loop to draw calendar & dates together
// each run through the for loop draws a row
for (int i = 1; i <= 4; i++) {
drawLine();
drawDateRow(intDaysInMo, intRequestedMo, intStart, intEnd);
drawEventRow(intRequestedMo, intDaysInMo, strEventArray, intStart, intEnd);
intStart += 7;
intEnd += 7;
drawSpace();
} // end for to draw cal
} else if (intRequestedMo == 5 || intRequestedMo == 8) {
// Start of for loop to draw calendar & dates together
// each run through the for loop draws a row
for (int i = 1; i <= 6; i++) {
drawLine();
drawDateRow(intDaysInMo, intRequestedMo, intStart, intEnd);
drawEventRow(intRequestedMo, intDaysInMo, strEventArray, intStart, intEnd);
intStart += 7;
intEnd += 7;
drawSpace();
} // end for to draw cal
} else {
// Start of for loop to draw calendar & dates together
// each run through the for loop draws a row
for (int i = 1; i <= 5; i++) {
drawLine();
drawDateRow(intDaysInMo, intRequestedMo, intStart, intEnd);
drawEventRow(intRequestedMo, intDaysInMo, strEventArray, intStart, intEnd);
intStart += 7;
intEnd += 7;
drawSpace();
} // end for to draw cal
} // end of if/else if/else
drawLine();
} // end drawCalnDate method
}// End of class
Your code explicitly assumes the date will have 5 characters in the form mm/dd
, but your first input violates that assumption as it is only 1/1
. If the date were formatted in all cases with 2-digit month and 2-digit date (i.e. 01/01
), your code would work.
You need to use the date parsing capabilities that are built-in to Java (java.time
package).