Java Core Development Guide: Exception Handling, Collections Framework, Map and Stream API Usage
Exception Handling
Exception Hierarchy
Java exceptions are divided into two main categories: runtime exceptions (unchecked exceptions) and compile-time exceptions (checked exceptions), all inheriting from the Throwable class.
throws Keyword
The throws keyword is used at method declaration to indicate that the method may throw specified exceptions, leaving the exception handling responsibility to the method caller.
Custom Exceptions
You can implement custom exceptions by inheriting from existing exception classes. If you inherit from RuntimeException, the custom exception is an unchecked exception; if you inherit from Exception, it is a checked exception that requires explicit throws declaration on methods that throw it.
// Custom unchecked exception for invalid age input
public class InvalidAgeException extends RuntimeException {
public InvalidAgeException() {}
public InvalidAgeException(String errorMessage) {
super(errorMessage);
}
}
public class CustomExceptionDemo {
public static void main(String[] args) {
try {
validateUserAge();
} catch (InvalidAgeException e) {
String errorMsg = e.getMessage();
System.out.println("Error occurred: " + errorMsg);
}
}
// throw keyword is used inside method to throw a concrete exception object
public static void validateUserAge() {
Scanner ageScanner = new Scanner(System.in);
System.out.println("Please enter student age:");
int inputAge = ageScanner.nextInt();
if (inputAge < 0 || inputAge > 150) {
throw new InvalidAgeException("Input age is out of valid range (0~150)");
}
System.out.println("Valid age entered: " + inputAge);
}
}
Note: If your custom exception inherits from a checked exception class, all methods throwing this exception must declare it with the
throwskeyword.
Difference between throws and throw
throws |
throw |
|---|---|
| Used after method signature | Used inside method body |
| Declares types of exceptions the method may throw | Throws a concrete exception instance |
| Can declare multiple exception types | Can only throw one exception object at a time |
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class ThrowsUsageDemo {
public static void main(String[] args) {
try {
parseDateAndInputNumber();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
public static void parseDateAndInputNumber() throws NumberFormatException, ParseException {
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
Date parsedDate = dateFormatter.parse("2022-4-13");
readAndParseInteger();
}
public static void readAndParseInteger() throws NumberFormatException {
Scanner inputScanner = new Scanner(System.in);
System.out.println("Please enter a number:");
String inputStr = inputScanner.next();
int parsedNum = Integer.parseInt(inputStr);
System.out.println("Parsed number: " + parsedNum);
}
}
Collections Framework
Core Collection Types and Characteristics
- List series: Ordered, allows duplicate elements, supports index access
- Set series: Unordered (most implementations), does not allow duplicate elements, no index support
import java.util.ArrayList;
import java.util.HashSet;
public class CollectionTypeComparisonDemo {
public static void main(String[] args) {
// List implementation: ordered, allows duplicates, index supported
ArrayList<String> orderedFruitList = new ArrayList<>();
orderedFruitList.add("Banana");
orderedFruitList.add("Apple");
orderedFruitList.add("Cherry");
orderedFruitList.add("Date");
for (int i = 0; i < orderedFruitList.size(); i++) {
String fruit = orderedFruitList.get(i);
System.out.println(fruit);
}
System.out.println("--------------------------");
// Set implementation: unordered, no duplicates, no index support
HashSet<String> uniqueFruitSet = new HashSet<>();
uniqueFruitSet.add("Banana");
uniqueFruitSet.add("Apple");
uniqueFruitSet.add("Cherry");
uniqueFruitSet.add("Apple"); // duplicate element will be ignored
// Set has no get() method for index access
System.out.println(uniqueFruitSet); // Output: [Apple, Banana, Cherry] (order may vary)
}
}
Common Methods of Collection Interface
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class CommonCollectionApiDemo {
public static void main(String[] args) {
Collection<String> celebrityCollection = new ArrayList<>();
// Add elements
celebrityCollection.add("Liu Yifei");
celebrityCollection.add("Gigi Lai");
celebrityCollection.add("Athena Chu");
System.out.println("Initial collection: " + celebrityCollection);
// Remove specified element
boolean isRemoved = celebrityCollection.remove("Liu Yifei");
System.out.println("Is Liu Yifei removed: " + isRemoved);
System.out.println("After removal: " + celebrityCollection);
// Check if element exists
boolean hasOldWang = celebrityCollection.contains("Old Wang");
System.out.println("Contains Old Wang: " + hasOldWang);
// Check if collection is empty
boolean isEmpty = celebrityCollection.isEmpty();
System.out.println("Is collection empty: " + isEmpty);
// Convert collection to array
String[] celebrityArr = new String[celebrityCollection.size()];
celebrityCollection.toArray(celebrityArr);
System.out.println("Converted array: " + Arrays.toString(celebrityArr));
// Add all elements from another collection
Collection<String> newCelebrityCollection = new ArrayList<>();
newCelebrityCollection.add("Tian Liang");
newCelebrityCollection.add("Li Xiao");
celebrityCollection.addAll(newCelebrityCollection);
System.out.println("After adding all elements: " + celebrityCollection);
// Clear all elements
celebrityCollection.clear();
System.out.println("After clear: " + celebrityCollection);
}
}
Collection Traversal Methods
1. Iterator Traversal
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorTraversalDemo {
public static void main(String[] args) {
Collection<String> celebrityCollection = new ArrayList<>();
celebrityCollection.add("Liu Yifei");
celebrityCollection.add("Gigi Lai");
celebrityCollection.add("Athena Chu");
// Get iterator instance for the collection
Iterator<String> collectionIterator = celebrityCollection.iterator();
// Traverse while there are remaining elements
while (collectionIterator.hasNext()) {
String currentElement = collectionIterator.next();
System.out.println(currentElement);
}
}
}
2. Enhanced For Loop Traversal
import java.util.ArrayList;
import java.util.Collection;
public class EnhancedForLoopDemo {
public static void main(String[] args) {
Collection<String> celebrityCollection = new ArrayList<>();
celebrityCollection.add("Liu Yifei");
celebrityCollection.add("Gigi Lai");
celebrityCollection.add("Athena Chu");
for (String celebrity : celebrityCollection) {
System.out.println(celebrity);
}
}
}
3. forEach Lambda Traversal
import java.util.ArrayList;
import java.util.Collection;
public class ForeachLambdaDemo {
public static void main(String[] args) {
Collection<String> celebrityCollection = new ArrayList<>();
celebrityCollection.add("Liu Yifei");
celebrityCollection.add("Gigi Lai");
celebrityCollection.add("Athena Chu");
// Anonymous inner class implementation
celebrityCollection.forEach(System.out::println);
// Simplified lambda implementation
celebrityCollection.forEach(celebrity -> System.out.println(celebrity));
}
}
Special Notes for Collection Operations
LinkedHashSetmaintains insertion order when retrieving elements- If you need to remove elements during traversal, only use the
remove()method of the iterator to avoid concurrent modification exceptions - Sort rule: In custom comparators, returning
o1 - o2results in ascending order, returningo2 - o1results in descending order
import java.util.ArrayList;
import java.util.Iterator;
public class IteratorRemoveElementDemo {
public static void main(String[] args) {
ArrayList<String> celebrityList = new ArrayList<>();
celebrityList.add("Cecilia Cheung");
celebrityList.add("Gigi Lai");
celebrityList.add("Liu Yifei");
Iterator<String> iterator = celebrityList.iterator();
while (iterator.hasNext()) {
String current = iterator.next();
System.out.println(current);
if (current.equals("Gigi Lai")) {
iterator.remove(); // Safe removal during traversal
}
}
System.out.println("After removal: " + celebrityList);
}
}
Collections Utility Class
The java.util.Collections class provides a set of static utility methods for operating on collections.
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class CollectionsUtilityDemo {
public static void main(String[] args) {
ArrayList<String> celebrityList = new ArrayList<>();
// Add multiple elements in one call
Collections.addAll(celebrityList, "Liu Yifei", "Gigi Lai", "Cecilia Cheung");
System.out.println("Initial list: " + celebrityList);
// Shuffle elements randomly
Collections.shuffle(celebrityList);
System.out.println("After shuffle: " + celebrityList);
// Default ascending sort
Collections.sort(celebrityList);
System.out.println("After ascending sort: " + celebrityList);
// Custom descending sort
Collections.sort(celebrityList, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);
}
});
System.out.println("After descending sort: " + celebrityList);
}
}
Map Collection
A Map stores key-value pairs, where key are unique and values can be duplicated.
Map Traversal Methods
1. Key Lookup Traversal
import java.util.HashMap;
import java.util.Set;
public class MapTraversalDemo {
public static void main(String[] args) {
HashMap<String, String> characterPairMap = new HashMap<>();
characterPairMap.put("Yang Guo", "Little Dragon Maiden");
characterPairMap.put("Guo Jing", "Huang Rong");
characterPairMap.put("Nobita", "Shizuka");
// Get all keys first, then lookup values by key
Set<String> keySet = characterPairMap.keySet();
for (String key : keySet) {
String value = characterPairMap.get(key);
System.out.println(key + " : " + value);
}
}
}
2. Key-Value Entry Traversal
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapEntryTraversalDemo {
public static void main(String[] args) {
HashMap<String, String> characterPairMap = new HashMap<>();
characterPairMap.put("Yang Guo", "Little Dragon Maiden");
characterPairMap.put("Guo Jing", "Huang Rong");
characterPairMap.put("Nobita", "Shizuka");
// Get all key-value entry objects
Set<Map.Entry<String, String>> entrySet = characterPairMap.entrySet();
for (Map.Entry<String, String> entry : entrySet) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + " ---- " + value);
}
}
}
3. Lambda forEach Traversal
import java.util.HashMap;
public class MapLambdaTraversalDemo {
public static void main(String[] args) {
HashMap<String, String> characterPairMap = new HashMap<>();
characterPairMap.put("Yang Guo", "Little Dragon Maiden");
characterPairMap.put("Guo Jing", "Huang Rong");
characterPairMap.put("Nobita", "Shizuka");
// Simplified lambda traversal
characterPairMap.forEach((key, value) -> System.out.println(key + " ---- " + value));
}
}
Nested Map Usage Example
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class NestedMapDemo {
public static void main(String[] args) {
HashMap<String, List<String>> provinceCityMap = new HashMap<>();
ArrayList<String> jiangsuCities = new ArrayList<>();
Collections.addAll(jiangsuCities, "Nanjing", "Yangzhou");
ArrayList<String> hubeiCities = new ArrayList<>();
Collections.addAll(hubeiCities, "Wuhan", "Xiaogan");
ArrayList<String> hebeiCities = new ArrayList<>();
Collections.addAll(hebeiCities, "Shijiazhuang", "Tangshan");
provinceCityMap.put("Jiangsu Province", jiangsuCities);
provinceCityMap.put("Hubei Province", hubeiCities);
provinceCityMap.put("Hebei Province", hebeiCities);
Set<Map.Entry<String, List<String>>> entrySet = provinceCityMap.entrySet();
for (Map.Entry<String, List<String>> entry : entrySet) {
String province = entry.getKey();
List<String> cities = entry.getValue();
System.out.println(province + " : " + cities);
}
}
}
Stream API
Stream API provides a functional programming style for operating on collections and arrays efficiently.
Steps to Use Stream
- Get a Stream instance from a data source (collection, array, etc.)
- Perform entermediate operations (filter, map, sort, etc.)
- Perform terminal operations (collect, count, forEach, etc.) to get final result
Note: Double-column Map collections cannot get Stream directly, you need to convert them to single-column entry set first. Arrays can get Stream via
Arrays.stream()orStream.of().
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;
public class StreamInitDemo {
public static void main(String[] args) {
// Get Stream from Map
HashMap<String, String> characterPairMap = new HashMap<>();
characterPairMap.put("Guo Jing", "Huang Rong");
Stream<Map.Entry<String, String>> mapStream = characterPairMap.entrySet().stream();
// Get Stream from array
String[] celebrityArr = {"Zhang Wuji", "Zhou Zhiruo", "Zhao Min"};
Stream<String> arrayStream1 = Arrays.stream(celebrityArr);
Stream<String> arrayStream2 = Stream.of("Zhang Sanfeng", "Zhang Wuji");
}
}
Common Stream Operations
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class StreamOperationDemo {
public static void main(String[] args) {
ArrayList<String> numberStrList = new ArrayList<>();
Collections.addAll(numberStrList, "10", "7", "9", "11");
// Convert string to integer, sort, then collect to new list
List<Integer> sortedNumList = numberStrList.stream()
.map(Integer::valueOf)
.sorted()
.collect(Collectors.toList());
System.out.println(sortedNumList); // Output: [7, 9, 10, 11]
}
}
Stream Notes
- Stream operations do not modify the original collection or array
- A Stream instance can only be used once, any operation after terminal operation will throw an expection