In Java, error handling is supported through the use of exceptions, with built-in structures like try-catch blocks that allow users to manage errors effectively. Java distinguishes between checked and unchecked exceptions, providing a framework to address various types of runtime and compile-time errors.
The fundamental structure for handling exceptions in Java involves try, catch, and optionally finally blocks. The try block contains code that may throw an exception, while the catch block defines how to handle specific exceptions. The finally block, if used, will execute regardless of whether an exception occurred.
As seen in my code example to the left, a divide by 0 error is expected, with 2 catch blocks for ArithmeticException or Exception as parameters. The output below shows the error message followed by the finally message. The finally block executes regardless of whether an exception occurs as reflected by my code.
In Java, file handling is accomplished using classes from the java.io package, and error handling during file operations is supported through exceptions. When attempting to read or write files, certain exceptions can occur, such as FileNotFoundException when a specified file does not exist, and IOException for general I/O errors.
The structure for handling these exceptions also involves try, catch, and optionally finally blocks. In a typical file handling scenario, the try block contains the code for file operations, such as opening and reading a file. The next catch blocks handle any exceptions that might occur, allowing for specific responses based on the type of error encountered.
For example, in my provided code snippet, I attempt to read from a file using a Scanner. If the file is not found, the FileNotFoundException is caught and a message is printed. Additionally, a generic catch block can handle any other unexpected exceptions that may occur during file operations. The finally block is used to execute cleanup code, such as closing the file, ensuring that resources are released regardless of whether an exception was thrown. This structure allows the coder to have control over multiple outcomes of their program, regardless of errors occurring.
A short output shows that since there is no input file (that I gave the program) the catch block executes followed by the finally block!
In Java, memory allocation and deallocation are managed predominantly through the creation of objects and the use of the garbage collector.
Memory allocation in Java occurs when you create instances of classes using the 'new' keyword. By allocating memory for an object, Java are reserves space in the heap for that object. This memory is automatically managed by the Java Virtual Machine (JVM).
My Example of Memory Allocation in the Person Class:
In my example of the Person class, here's how memory allocation works:
Person person = new Person("Alice");
Allocation: The line above creates a new Person object. The new keyword triggers allocation of memory on the heap for this object.
Memory Deallocation in Java:
Unlike languages such as C, where developers explicitly free allocated memory using free(), Java uses automatic garbage collection to reclaim memory. The JVM periodically checks for objects that are no longer referenced (i.e., unreachable) and automatically frees that memory, essentially preventing memory leaks.
How Deallocation is Demonstrated in Java:
Looking at modifications to my original Person class; for instance, if we let go of a reference:
In this example, by setting person to null, we effectively remove the reference to the Person object that holds "Alice". At this point, if there are no other references to this object, it becomes eligible for garbage collection (deallocation!).
This code example shows how memory is allocated in the C language. It also shows that there are explicit deallocation methods, unlike in Java.
This code example shows how memory is allocated in the Java language. There are no explicit deallocation methods though like there are in C!
I was able to implement a similar Word count (like in Task 1 of the base project) in Java. My implementation of the word counter reads a text file and counts the occurrences of each word, while ignoring punctuation and case differences.
The program begins by checking if a filename has been provided as an argument. It uses a HashMap to store word counts, where the key is the word and the value is the frequency of that word. A regular expression pattern is defined to match only alphabetic characters, ensuring that punctuation is filtered out.
Next, it processes the file using BufferedReader, converting each line to lowercase and splitting it into words. For each word, the program checks for matches using a Matcher object. If a valid word is found, it updates the count in the map.
Finally, the program sorts the entries in the map by frequency and prints the top 20 most frequently occurring words along with their counts. Error handling is also included to catch potential I/O issues during file reading!
File Reading and Writing in Java: (The word counter demonstrated above reads from a file as follows)
In Java, reading from and writing to files is accomplished using classes provided in the java.io package. For example, in my provided word counter program, the program reads a text file using BufferedReader and FileReader. To write to a file, you might use BufferedWriter along with FileWriter.
How to Open, Close, and Read from a (Text) File:
Opening a File: You open a text file using FileReader wrapped in a BufferedReader for the most efficient reading
Reading from a File: Use the readLine() method in a loop to read each line until the end of the file is reached
Closing a File: The try-with-resources statement ensures that the file is automatically closed when the try block is exited (touched on above)
Also, Java supports both text and binary files, allowing various streams for different data types.
Built-in Support for I/O:
Java has built-in support for I/O operations as part of the standard libraries. The java.io package provides the necessary classes and interfaces for handling file I/O, which includes reading, writing, and handling different file types.
Support for URLs:
Java also supports opening web locations (URLs) for I/O operations through the java.net package. You can create connections to URLs and read from them similarly to file streams, utilizing classes such as URL and URLConnection.
User Input Interaction:
Java provides support for user interaction through console input using the Scanner class. This allows you to read user input from the command line interactively. The simple example below shows the use of a Java scanner to get user input!
Java Garbage Collection Detector!
Constants:
ALLOCS_PER_CALL: Defines how many arrays will be created in each function call.
NUM_CALLS: Sets how many times the allocation function will be called.
THRESHOLD: This threshold is in nanoseconds, and it serves to compare the duration of each call to determine if a garbage collection event likely took place.
Main Method:
In the main loop, the allocateMemory() function is called multiple times.
It records the time taken for each call and prints it.
If the time exceeds the defined threshold, it prints a message indicating a potential GC event.
Memory Allocation in a Loop:
The allocateMemory() method allocates a specified number of integer arrays.
The references to the allocated objects are cleared at the end of the method to allow for garbage collection of those objects.
This output above shows my implementation of the Java Garbage Collection detection program.