Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 54 additions & 8 deletions java8/PROBLEMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ java8/
│ │ ├── MaxMinNumberStream.java # ✅ Complete
│ │ ├── MaxMinNumberTraditional.java # ✅ Complete
│ │ └── Pair.java # ✅ Helper class
│ ├── Q005_print_string/
│ │ ├── PrintStringsComparison.java # ✅ Complete
│ │ ├── PrintStringsStream.java # ✅ Complete
│ │ └── PrintStringsTraditional.java # ✅ Complete
│ ├── Q006_count_evens_odds/
│ │ └── CountEvensOddsComparison.java # ✅ Complete (Single class)
│ └── util/
│ └── ComparisonUtils.java # ✅ Shared utilities
└── target/ # Compiled output (not tracked in git)
Expand Down Expand Up @@ -88,6 +94,34 @@ java8/

---

### Q005: Filter Strings by Substring
**Location:** `com.modernjava.guide.java8.Q005_print_string`
**Concepts:** filter(), contains(), String operations, forEach()
**Problem:** Print all strings containing a specific substring (e.g., "_test")
**Input:** `["Apple_test", "Banana", "Cherry_test", "Date", "Elderberry", "Fig_test"]`
**Output:** `Apple_test, Cherry_test, Fig_test`
**Traditional:** ✅ `PrintStringsTraditional.java` - for loop with contains() check
**Stream:** ✅ `PrintStringsStream.java` - `filter(n -> n.contains(substring))`
**Comparison:** ✅ `PrintStringsComparison.java` - tests with 20, 1K, 100K, 1M strings
**Note:** Large array outputs are suppressed for performance testing

---

### Q006: Count Even and Odd Numbers
**Location:** `com.modernjava.guide.java8.Q006_count_evens_odds`
**Concepts:** count(), filter(), predicates, single-pass iteration
**Problem:** Count how many even and odd numbers are in an array
**Input:** `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`
**Output:** `Even count: 5, Odd count: 5`
**Implementation:** ✅ `CountEvensOddsComparison.java` - **Single class with both approaches**
**Methods:**
- `countTraditional()` - Single for loop counting both even/odd
- `countStream()` - Two separate stream pipelines with filter().count()
**Test Cases:** 10, 1K, 100K elements
**Note:** This demonstrates the **single-class approach** for simple problems - all code in one file

---

## 🛠️ Utility Classes

### ComparisonUtils
Expand All @@ -97,8 +131,11 @@ java8/
**Methods:**
- `repeat(String str, int count)` - Repeats string N times (Java 8 compatible alternative to String.repeat())
- `formatTime(long nanos)` - Formats nanoseconds to human-readable format (ns, μs, ms)
- `printNumbers(int[] numbers)` - Prints array elements comma-separated
- `printNumbers(int[] numbers)` - Prints integer array elements comma-separated
- `printStrings(String[] strings)` - Prints string array elements comma-separated
- `getArrayOfSpecifiedSize(int size)` - Generates random int array with positive, negative, and zero values (range: -100 to +100)
- `getStringArrayWithPatternAtEnd(int size, String pattern)` - Generates random string array from sample pool, randomly appending pattern to some strings
- `getStringArray()` - Returns the predefined string samples array

---

Expand All @@ -108,21 +145,26 @@ java8/
- **Terminal Operations:** `forEach()`, `count()`, `sum()`, `max()`, `min()`
- **Intermediate Operations:** `filter()`, `map()`
- **Method References:** `System.out::println`, `Integer::compare`
- **Lambda Expressions:** `n -> n % 2 == 0`, `n -> n * n`
- **Lambda Expressions:** `n -> n % 2 == 0`, `n -> n * n`, `n -> n.contains(substring)`
- **String Operations:** `contains()`, filtering by substring

### Comparison Topics
- Traditional vs Stream syntax
- Performance analysis with JIT warmup
- Code readability and maintainability
- When to use each approach
- Handling edge cases (empty arrays, single elements)
- Output suppression for large datasets in performance testing
- **Single-class approach** for simple problems (Q006+)

### Java 8 Features Demonstrated
- ✅ Lambda expressions
- ✅ Method references
- ✅ Stream API basics
- ✅ Stream API basics (int and object streams)
- ✅ Functional interfaces
- ✅ Optional (in max/min operations)
- ✅ String filtering and predicates
- ✅ Counting with filter().count()

---

Expand All @@ -132,23 +174,27 @@ Based on benchmark results in comparison classes:
- **Small arrays (< 100 elements):** Traditional approach is faster due to Stream overhead
- **Large arrays (10,000+ elements):** Stream performance improves, gap narrows
- **Very large arrays (1,000,000+ elements):** Traditional still edges out for simple operations
- **String operations:** Similar patterns - traditional loops excel for simple contains() checks
- **Counting operations:** Traditional single-pass is more efficient than multiple stream pipelines
- **Takeaway:** Use Streams for readability and composition, not raw speed in tight loops

---

## 🚧 Planned Problems

### Easy
- Q003: Print even numbers only
- Q004: Find sum of all numbers
- Q005: Find max/min element
- Q006: Count even vs odd numbers
- Q007: Remove duplicates
- Q007: Remove duplicates from array
- Q008: Convert all strings to uppercase
- Q009: Find average of numbers
- Q010: Check if any element matches a condition
- Q011: Sum all positive numbers

### Medium
- Q011: Group strings by length
- Q012: Find top K frequent elements
- Q013: Flatten nested lists
- Q014: Partition numbers into even/odd lists
- Q015: Find first element matching condition
- Q014: Partition list into even/odd
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate entry "Q014: Partition list into even/odd" appears on both line 177 and line 178. Remove one of these duplicate entries.

Suggested change
- Q014: Partition list into even/odd

Copilot uses AI. Check for mistakes.

### Hard
Expand Down
52 changes: 24 additions & 28 deletions java8/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ java8/
│ ├── Q002_print_evens/ # ✅ Filter even numbers
│ ├── Q003_square_nums/ # ✅ Sum of squares
│ ├── Q004_max_min/ # ✅ Find max & min
│ ├── Q005_print_string/ # ✅ Filter strings by substring
│ ├── Q006_count_evens_odds/ # ✅ Count even/odd (single class)
│ └── util/
│ └── ComparisonUtils.java # ✅ Shared utilities
└── target/ # Compiled output (gitignored)
Expand Down Expand Up @@ -62,6 +64,12 @@ mvn -pl java8 exec:java -Dexec.mainClass="com.modernjava.guide.java8.Q003_square

# Run Q004: Max & Min
mvn -pl java8 exec:java -Dexec.mainClass="com.modernjava.guide.java8.Q004_max_min.MaxMinNumberComparison"

# Run Q005: Filter Strings
mvn -pl java8 exec:java -Dexec.mainClass="com.modernjava.guide.java8.Q005_print_string.PrintStringsComparison"

# Run Q006: Count Even/Odd
mvn -pl java8 exec:java -Dexec.mainClass="com.modernjava.guide.java8.Q006_count_evens_odds.CountEvensOddsComparison"
```

---
Expand Down Expand Up @@ -106,32 +114,40 @@ mvn -pl java8 exec:java -Dexec.mainClass="com.modernjava.guide.java8.Q004_max_mi

## 📊 Current Status

### Completed Problems (4/4)
### Completed Problems (6/6)
- ✅ **Q001:** Print All Numbers - Stream basics, forEach(), method references
- ✅ **Q002:** Print Even Numbers - filter(), predicates
- ✅ **Q003:** Sum of Squares - map(), sum(), transformations
- ✅ **Q004:** Max & Min - max(), min(), Optional handling
- ✅ **Q005:** Filter Strings by Substring - filter(), contains(), String operations
- ✅ **Q006:** Count Even/Odd Numbers - count(), filter() (single-class approach)

### Utility Classes
- ✅ **ComparisonUtils** - Shared helpers (repeat, formatTime, printNumbers, getArrayOfSpecifiedSize)
- ✅ **ComparisonUtils** - Shared helpers (repeat, formatTime, printNumbers, printStrings, getArrayOfSpecifiedSize, getStringArrayWithPatternAtEnd)

See **[PROBLEMS.md](PROBLEMS.md)** for detailed problem statements and concepts covered.

---

## 🎓 Learning Approach

**Two implementation patterns:**
1. **Multi-file approach (Q001-Q005):** Separate Traditional/Stream/Comparison classes
2. **Single-class approach (Q006+):** All methods in one comparison class - better for simple problems

Each problem demonstrates:
1. **Traditional Approach** - Classic Java loops and conditionals
2. **Stream Approach** - Java 8 Stream API with lambdas
3. **Comparison** - Side-by-side execution with performance metrics

### Key Concepts Covered
- Lambda expressions: `n -> n % 2 == 0`
- Lambda expressions: `n -> n % 2 == 0`, `n -> n.contains(substring)`
- Method references: `System.out::println`
- Stream operations: `filter()`, `map()`, `forEach()`, `sum()`, `max()`, `min()`
- Performance analysis: nano-time benchmarks with multiple test cases
- Stream operations: `filter()`, `map()`, `forEach()`, `sum()`, `max()`, `min()`, `count()`
- String operations: `contains()`, filtering by substring
- Performance analysis: nano-time benchmarks with multiple test cases (small to 1M+ elements)
- Edge cases: empty arrays, single elements, large datasets
- Output suppression for large dataset performance testing

---

Expand Down Expand Up @@ -179,36 +195,16 @@ See **[Troubleshoot.md](Troubleshoot.md)** for complete error reference.
- This module uses `<source>1.8</source>` and `<target>1.8</target>` configuration
- All utility methods are Java 8 compatible (no String.repeat(), no var, etc.)
- Performance benchmarks include JIT warmup considerations
- Random array generation uses range -100 to +100 (positive, negative, zero values)
- Random int array generation uses range -100 to +100 (positive, negative, zero values)
- Random string array generation uses predefined sample pool with configurable pattern matching
- Large array outputs (size > 100) are suppressed during comparison tests for readability

---

**See also:**
- [Root README](../README.md) - Multi-module project overview
- [Git Best Practices](../docs/GIT_BEST_PRACTICES.md) - Contribution guidelines
- [Troubleshooting](../docs/TROUBLESHOOTING.md) - Global error reference
1. **Traditional Solution** - Pre-Java 8 imperative style with loops
2. **Stream Solution** - Java 8+ functional style with Stream API
3. **Comparison Runner** - Side-by-side execution with performance metrics

Example problems:
- **Q001: Print Numbers** - forEach(), method references, lambda expressions (WORKING)
- **Q002: Sum of Squares** - filter(), map(), reduce() (INCOMPLETE - needs Stream version)

**For detailed structure:** See [LEARNING_STRUCTURE.md](LEARNING_STRUCTURE.md)

---

## Java 8 Features & Resources

Features newly included within Java 8: https://www.oracle.com/java/technologies/javase/8-whats-new.html

Key topics to explore:
- **Stream API**: https://docs.oracle.com/javase/tutorial/collections/streams/
- **Lambda Expressions**: Functional interfaces and method references
- **Optional**: Better null handling
- **Date/Time API**: Modern date and time handling
- **Default Methods**: Interface evolution

Additional resources:
- Java learning path: https://docs.oracle.com/javase/tutorial/tutorialLearningPaths.html
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.modernjava.guide.java8.Q005_print_string;

import com.modernjava.guide.java8.util.ComparisonUtils;

/**
* Q005: Print all strings containing a specific substring
* Compares Traditional approach vs Stream API approach
* Tests with small, medium, and large datasets
*/
public class PrintStringsComparison {
public static void main(String[] args) {
String substring = "_test";

System.out.println("Q005: Print All Strings containing substring '_test' using Both Approaches");
System.out.println(ComparisonUtils.repeat("=", 80));

// Test Case 1: Small dataset (20 strings)
System.out.println("\n" + ComparisonUtils.repeat("-", 30) + " Test Case 1: Small Dataset " + ComparisonUtils.repeat("-", 30));
String[] strings = ComparisonUtils.getStringArrayWithPatternAtEnd(20, substring);
System.out.println("Input (size=" + strings.length + "): ");
ComparisonUtils.printStrings(strings);
compareApproaches(strings, substring, 20);

// Test Case 2: Medium dataset (1,000 strings)
System.out.println("\n\n" + ComparisonUtils.repeat("-", 30) + " Test Case 2: Medium Dataset " + ComparisonUtils.repeat("-", 30));
strings = ComparisonUtils.getStringArrayWithPatternAtEnd(1_000, substring);
System.out.println("Input (size=" + strings.length + "): ");
System.out.println("[... 1,000 strings ...]");
compareApproaches(strings, substring, 1_000);

// Test Case 3: Large dataset (100,000 strings)
System.out.println("\n\n" + ComparisonUtils.repeat("-", 30) + " Test Case 3: Large Dataset " + ComparisonUtils.repeat("-", 30));
strings = ComparisonUtils.getStringArrayWithPatternAtEnd(100_000, substring);
System.out.println("Input (size=" + strings.length + "): ");
System.out.println("[... 100,000 strings ...]");
compareApproaches(strings, substring, 100_000);

// Test Case 4: Very Large dataset (1,000,000 strings)
System.out.println("\n\n" + ComparisonUtils.repeat("-", 30) + " Test Case 4: Very Large Dataset " + ComparisonUtils.repeat("-", 30));
strings = ComparisonUtils.getStringArrayWithPatternAtEnd(1_000_000, substring);
System.out.println("Input (size=" + strings.length + "): ");
System.out.println("[... 1,000,000 strings ...]");
compareApproaches(strings, substring, 1_000_000);
}

private static void compareApproaches(String[] strings, String substring, int size) {
// Traditional Approach
System.out.println("\nAPPROACH: Traditional");
System.out.println(ComparisonUtils.repeat("-", 80));
long startTime = System.nanoTime();

if (size > 50) {
System.out.println("[Skipped printing output for large array of size " + size + "]");
} else {
PrintStringsTraditional.printStrings(strings, substring);
}

long endTime = System.nanoTime();
long traditionalTime = endTime - startTime;
System.out.println("Time: " + traditionalTime + " ns (" + ComparisonUtils.formatTime(traditionalTime) + ")");

// Stream API Approach
System.out.println("\nAPPROACH: Stream API");
System.out.println(ComparisonUtils.repeat("-", 80));
long streamStartTime = System.nanoTime();
PrintStringsStream.searchStrings(strings, substring);


Comment on lines +66 to +68
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistency in output display logic for stream approach. Line 52 uses size > 50 threshold for skipping output, but the stream approach on line 66 does not suppress output for large arrays, which could produce excessive console output for the large test cases (1K, 100K, 1M strings). This will create inconsistent behavior and potentially very long output for large arrays.

Suggested change
PrintStringsStream.searchStrings(strings, substring);
if (size > 50) {
System.out.println("[Skipped printing output for large array of size " + size + "]");
} else {
PrintStringsStream.searchStrings(strings, substring);
}

Copilot uses AI. Check for mistakes.
long streamEndTime = System.nanoTime();
long streamTime = streamEndTime - streamStartTime;
System.out.println("Time: " + streamTime + " ns (" + ComparisonUtils.formatTime(streamTime) + ")");

// Performance Comparison
System.out.println("\n" + ComparisonUtils.repeat("-", 80));
System.out.println("PERFORMANCE COMPARISON:");
System.out.println("Traditional: " + ComparisonUtils.formatTime(traditionalTime));
System.out.println("Stream API: " + ComparisonUtils.formatTime(streamTime));
if (traditionalTime < streamTime) {
double ratio = (double) streamTime / traditionalTime;
System.out.println("Traditional is " + String.format("%.2f", ratio) + "x faster");
} else {
double ratio = (double) traditionalTime / streamTime;
System.out.println("Stream API is " + String.format("%.2f", ratio) + "x faster");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.modernjava.guide.java8.Q005_print_string;

import com.modernjava.guide.java8.util.ComparisonUtils;

import java.util.Arrays;

/**
* search strings containing a substring using Stream API
*/
public class PrintStringsStream {

public static void main(String[] args) {
System.out.println("Q005: Print All Strings containing substring '_test' using Stream API");
ComparisonUtils.repeat("-",80);;
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double semicolon detected on line 14. Remove the extra semicolon at the end of this line.

Suggested change
ComparisonUtils.repeat("-",80);;
ComparisonUtils.repeat("-",80);

Copilot uses AI. Check for mistakes.
String[] strings = ComparisonUtils.getStringArrayWithPatternAtEnd(40,"_test");
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after comma in method arguments. Should be getStringArrayWithPatternAtEnd(40, "_test") with a space after the comma for consistency with Java code style conventions.

Suggested change
String[] strings = ComparisonUtils.getStringArrayWithPatternAtEnd(40,"_test");
String[] strings = ComparisonUtils.getStringArrayWithPatternAtEnd(40, "_test");

Copilot uses AI. Check for mistakes.
//{"Apple_test", "Banana", "Cherry_test", "Date", "Elderberry", "Fig_test", "Grape", "Honeydew_test"};
String subString = "_test";

System.out.println("Input with length "+strings.length+": ");
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after + operator. Should be "Input with length " + strings.length + ": " with spaces around the concatenation operators for consistency.

Suggested change
System.out.println("Input with length "+strings.length+": ");
System.out.println("Input with length " + strings.length + ": ");

Copilot uses AI. Check for mistakes.
ComparisonUtils.printStrings(strings);

System.out.println("Output: ");
searchStrings(strings, subString);
}


public static void searchStrings(String[] strings, String subString){
Comment on lines +23 to +27
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method naming inconsistency. In PrintStringsStream.java, the method is named searchStrings() while in PrintStringsTraditional.java, it's named printStrings(). Both methods have the same purpose (filtering and printing strings with a substring). For consistency and clarity, they should have the same name. Consider using printStringsWithSubstring() or filterAndPrintStrings() for both.

Suggested change
searchStrings(strings, subString);
}
public static void searchStrings(String[] strings, String subString){
printStringsWithSubstring(strings, subString);
}
public static void printStringsWithSubstring(String[] strings, String subString){

Copilot uses AI. Check for mistakes.
Arrays.stream(strings)
.filter(n->n.contains(subString))
.forEach(n->System.out.print(n+","));
Comment on lines +29 to +30
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space in lambda expression arrow operator. Should be .filter(n -> n.contains(subString)) with spaces around the arrow operator for consistency with Java lambda style conventions.

Suggested change
.filter(n->n.contains(subString))
.forEach(n->System.out.print(n+","));
.filter(n -> n.contains(subString))
.forEach(n -> System.out.print(n+","));

Copilot uses AI. Check for mistakes.
Comment on lines +29 to +30
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space in lambda expression arrow operator. Should be .forEach(n -> System.out.print(n+",")) with spaces around the arrow operator for consistency with Java lambda style conventions.

Suggested change
.filter(n->n.contains(subString))
.forEach(n->System.out.print(n+","));
.filter(n -> n.contains(subString))
.forEach(n -> System.out.print(n+","));

Copilot uses AI. Check for mistakes.
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.modernjava.guide.java8.Q005_print_string;

import com.modernjava.guide.java8.util.ComparisonUtils;

public class PrintStringsTraditional {
public static void main(String[] args) {
String substring = "_test";
String[] strings = ComparisonUtils.getStringArrayWithPatternAtEnd(20,substring);
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after comma. Should be getStringArrayWithPatternAtEnd(20, substring) with a space after the comma for consistency with Java code style conventions.

Suggested change
String[] strings = ComparisonUtils.getStringArrayWithPatternAtEnd(20,substring);
String[] strings = ComparisonUtils.getStringArrayWithPatternAtEnd(20, substring);

Copilot uses AI. Check for mistakes.
System.out.println("Q005: Print All Strings containing substring '_test' using Traditional Approach");
System.out.println(ComparisonUtils.repeat("-",80));;
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double semicolon detected. Remove the extra semicolon at the end of this line.

Suggested change
System.out.println(ComparisonUtils.repeat("-",80));;
System.out.println(ComparisonUtils.repeat("-",80));

Copilot uses AI. Check for mistakes.
System.out.println("Input: ");
ComparisonUtils.printStrings(strings);
System.out.println("Output: ");
printStrings(strings, substring);
}

public static void printStrings(String[] strings, String substring) {
/**
* Traditional approach to print all strings in an array.
* Steps:
* 1. Use a for-each loop to iterate through each string in the array.
* 2. Print each string to the console.
Comment on lines +19 to +22
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misleading documentation comment. The comment states "print all strings in an array" but the method actually prints only strings containing the specified substring. Update the comment to accurately reflect the method's behavior: "Traditional approach to print all strings containing the specified substring."

Suggested change
* Traditional approach to print all strings in an array.
* Steps:
* 1. Use a for-each loop to iterate through each string in the array.
* 2. Print each string to the console.
* Traditional approach to print all strings containing the specified substring.
* Steps:
* 1. Use a for-each loop to iterate through each string in the array.
* 2. If the string contains the specified substring, print it to the console.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misleading documentation comment. Step 2 states "Print each string to the console" but the method actually prints only strings that contain the specified substring. Update to: "2. Print strings that contain the substring to the console."

Suggested change
* 2. Print each string to the console.
* 2. Print strings that contain the substring to the console.

Copilot uses AI. Check for mistakes.
*/
for (String str : strings) {
if(str.contains(substring))
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after if keyword. Should be if (str.contains(substring)) with a space before the opening parenthesis, following Java style conventions.

Suggested change
if(str.contains(substring))
if (str.contains(substring))

Copilot uses AI. Check for mistakes.
System.out.print(str+",");
Comment on lines +25 to +26
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Missing braces for if statement. According to Java best practices, single-line if statements should include braces for better readability and maintainability. Should be:

if(str.contains(substring)) {
    System.out.print(str+",");
}
Suggested change
if(str.contains(substring))
System.out.print(str+",");
if(str.contains(substring)) {
System.out.print(str+",");
}

Copilot uses AI. Check for mistakes.
}
System.out.println("\n");
}
}
Loading