GabrielChu
GabrielChu

Reputation: 6156

Java stream with method references for instanceof and class cast

Can I convert the following code using method reference?

List<Text> childrenToRemove = new ArrayList<>();

group.getChildren().stream()
    .filter(c -> c instanceof Text)
    .forEach(c -> childrenToRemove.add((Text)c));

Let me give an example to illustrate what I mean, suppose we have

myList
    .stream()
    .filter(s -> s.startsWith("c"))
    .map(String::toUpperCase)
    .sorted()
    .forEach(elem -> System.out.println(elem));

using method reference it can be written as (last line)

myList
    .stream()
    .filter(s -> s.startsWith("c"))
    .map(String::toUpperCase)
    .sorted()
    .forEach(System.out::println);

What are the rules to convert an expression to a method reference?

Upvotes: 19

Views: 17205

Answers (2)

steffen
steffen

Reputation: 16948

Yes, you can use these method references:

.filter(Text.class::isInstance)
.map(Text.class::cast)
.forEach(childrenToRemove::add);

Instead of for-each-add, you can collect stream items with Collectors.toSet():

Set<Text> childrenToRemove = group.getChildren()
    // ...
    .collect(Collectors.toSet());

Use toList() if you need to maintain the order of children.

You can replace lambda expressions with method references if the signatures match by applying these rules:

ContainingClass::staticMethodName // method reference to a static method
containingObject::instanceMethodName // method reference to an instance method
ContainingType::methodName // method reference to an instance method
ClassName::new // method reference to a constructor

Upvotes: 44

Sergey Prokofiev
Sergey Prokofiev

Reputation: 1885

I think yes it's possible, like so

group.getChildren()
    .filter(Text.class::isInstance)
    .map(Text.class::cast)
    .collect(Collectors.toCollection(() -> childrenToRemove));

Upvotes: 0

Related Questions