Is there any way to break the Java Stream with custom condition and collect all the items till the condition matches to the list using Java 8

huangapple go评论76阅读模式
英文:

Is there any way to break the Java Stream with custom condition and collect all the items till the condition matches to the list using Java 8

问题

Question: 我有一个包含 List<Object> 的集合需要在 **Java 8** 中根据以下条件进行过滤

 1. 将列表中的对象按日期降序排列其中日期也可以为空
 2. 逐个迭代列表中的每个元素并验证某些条件如果条件匹配则仅中断迭代并返回所有符合条件的元素直到条件不匹配为止),并忽略剩余的元素

代码片段

      public class Employee {
    
    	private int empId;
    
    	private String empName;
    
    	private Date empDob;
    	
    	//构造函数
    	//Getter和Setter
    	
    }

测试类

    public static void main(String[] args) {

		List<Employee> asList = Arrays.asList(new Employee(1, "Emp 1", getDate(1998)),
				new Employee(2, "Emp 2", getDate(2005)), new Employee(3, "Emp 3", getDate(2000)),
				new Employee(4, "Emp 4", null), new Employee(5, "Emp 5", getDate(1990)),
				new Employee(6, "Emp 6", new Date()));

		List<Employee> result = asList.stream()
				.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
				.filter(i -> i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
						&& i.getEmpName().equals("Emp 3"))
				.collect(Collectors.toList());
		System.out.println(result);

	}

	public static Date getDate(int year) {
		Calendar c1 = Calendar.getInstance();
		c1.set(year, 01, 01);
		return c1.getTime();

	}

我尝试过的上述代码只返回与条件匹配的元素结果如下

    [Employee [empId=3, empName=Emp 3, empDob=Wed Feb 01 15:55:57 MYT 2000]]

> 我需要的预期输出如下

我期望的结果如下它应该收集所有符合条件的元素):

    [Employee [empId=6, empName=Emp 6, empDob=Sat Aug 15 16:06:22 MYT 2020], 
     Employee [empId=2, empName=Emp 2, empDob=Tue Feb 01 16:06:22 MYT 2005], 
     Employee [empId=3, empName=Emp 3, empDob=Tue Feb 01 16:06:22 MYT 2000]]
英文:

Question: I have some collection List<Object> which need to be filtered with below condition in Java 8,

  1. Arrange the object in the list in a descending order of date (where date can be null as well)
  2. Iterate each elements of the list one-by-one and validate some condition, if condition matches, then break the iteration their only and return all the elements(till the condition matches) and ignore the remaining elements.

Code snippet:

  public class Employee {
private int empId;
private String empName;
private Date empDob;
//Constructor
//Getter Setter
}

Test Class:

public static void main(String[] args) {
List&lt;Employee&gt; asList = Arrays.asList(new Employee(1, &quot;Emp 1&quot;, getDate(1998)),
new Employee(2, &quot;Emp 2&quot;, getDate(2005)), new Employee(3, &quot;Emp 3&quot;, getDate(2000)),
new Employee(4, &quot;Emp 4&quot;, null), new Employee(5, &quot;Emp 5&quot;, getDate(1990)),
new Employee(6, &quot;Emp 6&quot;, new Date()));
List&lt;Employee&gt; result = asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.filter(i -&gt; i.getEmpName() != null &amp;&amp; !StringUtils.isEmpty(i.getEmpName())
&amp;&amp; i.getEmpName().equals(&quot;Emp 3&quot;))
.collect(Collectors.toList());
System.out.println(result);
}
public static Date getDate(int year) {
Calendar c1 = Calendar.getInstance();
c1.set(year, 01, 01);
return c1.getTime();
}

The above code which I tried is returning only the element which is matches with the condition and result is:

[Employee [empId=3, empName=Emp 3, empDob=Wed Feb 01 15:55:57 MYT 2000]]

> Expected Output which I need to do:

The result which I am expecting is something like below (it should collect all the elements till the condition matches)

[Employee [empId=6, empName=Emp 6, empDob=Sat Aug 15 16:06:22 MYT 2020], 
Employee [empId=2, empName=Emp 2, empDob=Tue Feb 01 16:06:22 MYT 2005], 
Employee [empId=3, empName=Emp 3, empDob=Tue Feb 01 16:06:22 MYT 2000]]

答案1

得分: 4

  1. 自己实现 AccumulatorCollector

    result = asList.stream().collect(ArrayList::new, (l, e) -&gt; {
    if (l.isEmpty() || !l.get(l.size() - 1).getEmpName().equals(&quot;Emp 3&quot;))
    l.add(e);
    }, (l1, l2) -&gt; {
    if (l1.isEmpty() || !l1.get(l1.size() - 1).getEmpName().equals(&quot;Emp 3&quot;))
    l1.addAll(l2);
    });
    
  2. 要求 JAVA>=9: 使用 Stream.takeWhile() 获取在停止之前的所有元素,然后检索要停止的元素

     // 添加所有在第一个 Emp3 之前的元素
    List&lt;Employee&gt; result = asList.stream()
    .sorted(comparing(Employee::getEmpDob, nullsLast(reverseOrder())))
    .takeWhile(i -&gt; i.getEmpName() != null &amp;&amp; !i.getEmpName().isEmpty()
    &amp;&amp; !i.getEmpName().equals(&quot;Emp 3&quot;))
    .collect(Collectors.toList());
    // 添加第一个 Emp3
    asList.stream()
    .sorted(comparing(Employee::getEmpDob, nullsLast(reverseOrder())))
    .filter(i -&gt; i.getEmpName() != null &amp;&amp; !i.getEmpName().isEmpty()
    &amp;&amp; i.getEmpName().equals(&quot;Emp 3&quot;))
    .findFirst().ifPresent(result::add);
    

这些方法都不是很优雅,但似乎没有更好的方法。

英文:

I'd suggest the solutions of Picking elements of a list until condition is met with Java 8 Lambdas

  1. Do your own Accumulator and Collector

    result = asList.stream().collect(ArrayList::new, (l, e) -&gt; {
    if (l.isEmpty() || !l.get(l.size() - 1).getEmpName().equals(&quot;Emp 3&quot;))
    l.add(e);
    }, (l1, l2) -&gt; {
    if (l1.isEmpty() || !l1.get(l1.size() - 1).getEmpName().equals(&quot;Emp 3&quot;))
    l1.addAll(l2);
    });
    
  2. REQUIRES JAVA>=9: Use Stream.takeWhile() to get all the element before stopping then retrieve the element to stop on

     // Add all element until the first Emp3
    List&lt;Employee&gt; result = asList.stream()
    .sorted(comparing(Employee::getEmpDob, nullsLast(reverseOrder())))
    .takeWhile(i -&gt; i.getEmpName() != null &amp;&amp; !i.getEmpName().isEmpty()
    &amp;&amp; !i.getEmpName().equals(&quot;Emp 3&quot;))
    .collect(Collectors.toList());
    // Add the first Emp3
    asList.stream()
    .sorted(comparing(Employee::getEmpDob, nullsLast(reverseOrder())))
    .filter(i -&gt; i.getEmpName() != null &amp;&amp; !i.getEmpName().isEmpty()
    &amp;&amp; i.getEmpName().equals(&quot;Emp 3&quot;))
    .findFirst().ifPresent(result::add);
    

None of them is very nice, but seems there no nice way to it

答案2

得分: 1

你应该获取所选员工的日期,然后筛选出所有日期大于等于他的日期的员工,并进行排序。

List<Employee> asList = Arrays.asList(new Employee(1, "员工 1", getDate(1998)),
                new Employee(2, "员工 2", getDate(2005)), new Employee(3, "员工 3", getDate(2000)),
                new Employee(4, "员工 4", null), new Employee(5, "员工 5", getDate(1990)),
                new Employee(6, "员工 6", new Date()));

Date searchedEmpDate = asList.stream()
                .filter(i -> i.getEmpName() != null && !i.getEmpName().isEmpty()
                        && i.getEmpName().equals("员工 3")).findAny().get().getEmpDob();

List<Employee> result = asList.stream()
                .filter(i -> i.getEmpDob() != null && i.getEmpDob().compareTo(searchedEmpDate) >= 0)
                .sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
                .collect(Collectors.toList());
System.out.println(result);
英文:

You should get date of selected employee, and then filter all with date bigger or equals his date, and then sort them.

List&lt;Employee&gt; asList = Arrays.asList(new Employee(1, &quot;Emp 1&quot;, getDate(1998)),
new Employee(2, &quot;Emp 2&quot;, getDate(2005)), new Employee(3, &quot;Emp 3&quot;, getDate(2000)),
new Employee(4, &quot;Emp 4&quot;, null), new Employee(5, &quot;Emp 5&quot;, getDate(1990)),
new Employee(6, &quot;Emp 6&quot;, new Date()));
Date searchedEmpDate = asList.stream()
.filter(i -&gt; i.getEmpName() != null &amp;&amp; !i.getEmpName().isEmpty()
&amp;&amp; i.getEmpName().equals(&quot;Emp 3&quot;)).findAny().get().getEmpDob();
List&lt;Employee&gt; result = asList.stream()
.filter(i -&gt; i.getEmpDob() != null &amp;&amp; i.getEmpDob().compareTo(searchedEmpDate) &gt;= 0)
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.collect(Collectors.toList());
System.out.println(result);

答案3

得分: 1

***Java 9+***

在Java 9及以上版本中您可以使用takeWhile()方法示例如下

    List<Employee> result = asList.stream()
                .sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
                .takeWhile(Predicate.not(i -> (i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
                        && i.getEmpName().equals("Emp 3"))))
                .collect(Collectors.toList());

请注意使用了`Predicate.not`,这将在满足条件之前对表达式进行求值即直到遇到"Emp 3"之前)。`List<Employee> result` 不包括"Emp 3"如果要添加"Emp 3"

    asList.stream()
                    .sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
                    .filter(i -> i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
                            && i.getEmpName().equals("Emp 3"))
                    .collect(Collectors.toCollection(() -> result));

***Java 8+***

您可以按照[此处][1]的描述实现自己的takeWhile方法或者您可以模拟takeWhile操作此方法接受已排序列表

    public static <T> List<T> takeWhile(List<T> list, Predicate<T> p) {
            int i = 0;
            for (T item : list) {
                if (!p.test(item)) {
                    return list.subList(0, i);
                }
                i++;
            }
            return list;
        }

然后调用方式为 -

    List<Employee> employees = takeWhile(asList.stream()
                    .sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
                    .collect(Collectors.toList()), i -> i.getEmpName() != null && !StringUtils.isEmpty(i.getEmpName())
                    && i.getEmpName().equals("Emp 3"));

  [1]: https://stackoverflow.com/questions/32290278/picking-elements-of-a-list-until-condition-is-met-with-java-8-lambdas
英文:

Java 9+

In java 9+ you can use takeWhile() as -

List&lt;Employee&gt; result = asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.takeWhile(Predicate.not(i -&gt; (i.getEmpName() != null &amp;&amp; !StringUtils.isEmpty(i.getEmpName())
&amp;&amp; i.getEmpName().equals(&quot;Emp 3&quot;))))
.collect(Collectors.toList());

Note use of Predicate.not, this will evaluate expression till condition is met (i.e. till "Emp 3" is NOT encountered. List&lt;Employee&gt; result doesn't include "Emp 3". To add "Emp 3"

asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.filter(i -&gt; i.getEmpName() != null &amp;&amp; !StringUtils.isEmpty(i.getEmpName())
&amp;&amp; i.getEmpName().equals(&quot;Emp 3&quot;))
.collect(Collectors.toCollection(() -&gt; result));

Java 8+

You can implement your own takeWhile as described here or you can simulate takeWhile as (this method takes sorted list)

public static &lt;T&gt; List&lt;T&gt; takeWhile(List&lt;T&gt; list, Predicate&lt;T&gt; p) {
int i = 0;
for (T item : list) {
if (!p.test(item)) {
return list.subList(0, i);
}
i++;
}
return list;
}

and call as -

List&lt;Employee&gt; employees = takeWhile(asList.stream()
.sorted(Comparator.comparing(Employee::getEmpDob, Comparator.nullsLast(Comparator.reverseOrder())))
.collect(Collectors.toList()), i -&gt; i.getEmpName() != null &amp;&amp; !StringUtils.isEmpty(i.getEmpName())
&amp;&amp; i.getEmpName().equals(&quot;Emp 3&quot;));

huangapple
  • 本文由 发表于 2020年8月15日 16:16:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63423981.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定