Functional Reflection in Java

Class: CSCE-314


Notes:

Introduction

In Week 15, we explore two advanced concepts in modern Java: functional programming features and the Reflection API. Java remains a strongly object‑oriented language, but since Java 8, functional constructs allow developers to express computations more concisely and
declaratively.

Reflection complements this by allowing programs to examine and manipulate their own structure at runtime. These capabilities expand what Java applications can do and deepen understanding of Java’s design.

1. Functional Programming in Java

Functional programming encourages the use of pure functions, immutability, and higher‑order operations. Java supports this through key features such as lambda expressions, method references, and the Stream API.

1.1 Lambda Expressions

A lambda expression is a concise representation of an anonymous function or a block of behavior. It is often used where a functional interface (an interface with a single abstract method) is expected.

Runnable r = () -> System.out.println("Running!");  
r.run();  

The syntax () -> ... defines behavior without declaring an entire class. This enables cleaner, more readable code.

Lambda function = inline and disposable function

1.2 Method References

Method references offer a shorthand for passing existing methods as behavior.

list.forEachprintln; 

This form replaces (x) -> System.out.println(x) with a more compact expression, improving clarity.

1.3 Stream API

Streams allow high‑level operations on collections. They support functional operations such as map, filter, and reduce.

long count = names.stream()  
	.filter(n -> n.length() > 5)  
	.count();  

Streams encourage immutability: they do not modify the original collection but instead operate on a pipeline of transformations.

2. Java Reflection

Reflection gives Java the ability to inspect classes, methods, fields, and constructors at runtime. This capability is particularly useful in tools, debugging, dynamic loading, and advanced frameworks.

2.1 Inspecting Classes

You can use reflection to list a class's fields and methods:

Class<?> cls = String.class;  
for (var m : cls.getDeclaredMethods()) {  
	System.out.println(m.getName());  
}  

2.2 Invoking Methods Dynamically

Reflection can also dynamically invoke methods you discover at runtime:

Method m = cls.getMethod("substring", int.class, int.class);  
String result = (String)m.invoke("HelloWorld", 0, 5);  
System.out.println(result); // prints Hello  

Reflection-based method invocation must be used carefully because mismatched parameters or exceptions occur at runtime instead of compile time.

3. Using Streams and Reflection Together

Reflection often returns arrays of members such as methods or constructors. Combining streams with reflection allows for elegant filtering and processing.

Arrays.stream(cls.getDeclaredMethods())  
	.mapgetName  
	.filter(n -> n.startsWith("get"))  
	.forEachprintln;  

This snippet lists all getter-style methods of a class in a succinct and expressive way.

Summary

Functional programming tools such as lambdas and streams enable clear, expressive code for processing data. Reflection provides access to Java’s structure at runtime, allowing dynamic exploration and invocation. Together, these concepts deepen your understanding of how Java blends object‑oriented and functional paradigms.