Does Java 8 forEach only apply to some?

There are no “if” statements, please if you are not explaining why this cannot be done without it.

I see how far I can only work in threads. I have this trouble:

List<Cube> revised = cubes.filter(p) .map(c -> f(c)) .map(c -> { if(c.prop()) { c.addComment(comment); } return c; }) .collect(Collectors.toList()); 

My best idea is how to do it without an "if"

 List<Cube> revised = cubes.filter(p) .map(c -> f(c)); revised .filter(Cube::prop) .forEach(c -> c.addComment(comment)); // can also map still 

Is there a way to do this in only one chain? In this case, the branch should happen in the stream. A method like forSome(predicate, lambda) will work.

I do not want to "minimize my own." I can use "if", but I'm trying to figure out what an expressive functional style might look like.

+5
source share
2 answers

There is no need to use map which returns the same element if you have peek . The following code cheats with a short-circuit statement:

 cubes.filter(p) .map(c -> f(c)) .peek(c -> c.prop() && c.addComment(comment)) 

I think the “modern” way using the “Optional” is much less readable:

 cubes.filter(p) .map(c -> f(c)) .peek(c -> Optional.of(c).filter(Cube::prop).ifPresent(c -> c.addComment(comment))) 
+3
source

You can implement your forSome function as follows:

 public static <T> T forSome(T c, Predicate<T> condition, Consumer<T> extraBehaviour) { if (condition.test(c)) { extraBehaviour.accept(c); } return c; } 

How can you use the map operator to insert it into the stream:

  List<Cube> revised = cubes.stream().filter(p) .map(c -> f(c)) .map(c -> forSome(c, Cube::prop, cube -> cube.addComment("my comment 2"))) .collect(Collectors.toList()); 

To give another use case, we can take the following example:

 class StudentExam { private final String studentName; private final List<Character> answers; private boolean passed = false; StudentExam(String studentName, List<Character> answers) { this.studentName = studentName; this.answers = answers; } public void markAsPassed() { this.passed = true; } public boolean isPassed() { return passed; } public Character getAnswer(int index) { return answers.get(index); } public String getStudentName() { return studentName; } } List<StudentExam> results = asList( new StudentExam("John", asList(new Character[] {'A', 'B'})), new StudentExam("Andy", asList(new Character[] {'A', 'C'})), new StudentExam("Mary", asList(new Character[] {'B', 'B'})), new StudentExam("Jane", asList(new Character[] {'C', 'D'})) ); 

Now we can, if the correct answers are "A" and "B", than we can pass through the objects and set the corresponding exam status.

  results.stream() .map(examResult -> forSome( examResult, er -> er.getAnswer(0).equals('A') || er.getAnswer(1).equals('B'), StudentExam::markAsPassed)) .forEach(studentExam -> studentExam.getStudentName() + " passed: " + studentExam.isPassed())); 

prints:

  • John: the truth has passed
  • Andy: the truth has passed
  • Maria: the truth has passed
  • Jane: gone lies
+1
source

Source: https://habr.com/ru/post/1272600/


All Articles