7

I have the following code:

public boolean foo(List<JSONObject> source, String bar, String baz) {
    List<String> myList = newArrayList();

    source.forEach(json -> {
        if (!(json.get(bar) instanceof JSONObject)) {
            myList.add(json.get(bar).toString());
        } else {
            myList.add(json.getJSONObject(attribute).get("key").toString());
        }
    });

    /**
     * do something with myList and baz
     */
}

I'm just wondering if there's a way to do the if-else condition inline using a filter.

Something along the lines of:

List<String> myList = source.stream()
                .filter(json -> !(json.get(bar) instanceof JSONObject))
                .map(item -> item.get(attribute).toString())
                .collect(Collectors.toList());

If I go by the approach above, I will miss the supposed to be "else" condition. How can I achieve what I want using a more java-8 way?

Thanks in advance!

1
  • 2
    you could move your if-else to the map operation, but it would just get unreadable. Java8 is not always the best approach, why not just use the simple old iterative way? Commented Dec 13, 2017 at 10:40

4 Answers 4

10

The only way I see is putting the condition in the map call. If you use filter you lose the "else" part.

List<String> myList = source.stream()
            .map(item -> {
                  if (!(item.get(bar) instanceof JSONObject)) {
                      return item.get(bar).toString();
                  } else {
                      return item.getJSONObject(attribute).get("key").toString();
                  }
            })
            .collect(Collectors.toList());

or, as Holger suggested in a comment, use the ternary conditional operator:

List<String> myList = source.stream()
            .map(i -> (i.get(bar) instanceof JSONObject ? i.getJSONObject(attribute).get("key") : i.get(bar)).toString())
            .collect(Collectors.toList());
Sign up to request clarification or add additional context in comments.

6 Comments

why use streams in the first place, is the question the OP should ask himself
@Eugene true, but it does remove the explicit creation of the List and adding elements to it.
@Eran which makes it worse in a way, there is no way to pass the expected size to Collectors.toList() while the OP's approach you could. It's not your answer I'm debating btw, but the approach in general
@Eran What about partitioningBy and then mapping results into a list depending on the result of the partitioning ?!
@Eugene: if you worry about the list’s initial capacity, you can use Arrays.asList( … stream op … .toArray(ElementType[]::new) ) to get a list without capacity increase operations (if the stream can predict the size). But this is rarely an issue (or consideration, as you note by the OP’s original code which doesn’t attempt to specify an initial capacity to the list either)…
|
5

What about something like this?

  List<String> myList = source.stream()
      .map(json -> !(json.get(bar) instanceof JSONObject) ? 
            json.get(bar).toString() : 
            json.getJSONObject(attribute).get("key").toString())
      .collect(Collectors.toList());

Not tested but you get the idea.

Comments

2

You can use the function partitioningBy that takes a Predicate and returns Map<Boolean, List<T>>. The true key contains the values that are true for the predicate and the false key contains the other values.

So you can rewrite your code like this :

Map<Boolean, List<String>> partition = source.stream()
            .collect(Collectors.partitionBy(json -> !(json.get(bar) instanceof JSONObject));

In this case, no need to use the filter function.

List<String> valuesWhenTrue = partition.get(Boolean.TRUE).stream().map(item -> item.get(attribute).toString()).collect(Collectors.toList());   

List<String> valuesWhenFalse = partition.get(Boolean.FALSE).stream().map(json.getJSONObject(attribute).get("key").toString()).collect(Collectors.toList());

Comments

1

How about extract the if-else into a private function

private String obtainAttribute(JSONObject json){
  if (!(json.get(bar) instanceof JSONObject)) {
    return json.get(bar).toString();
  }
    return json.getJSONObject(attribute).get("key").toString();
}

and call it in your lambda expression.

    List<String> myList = source.stream()
    .map(item -> obtainAttribute(item))
    .collect(Collectors.toList());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.