10

This title sounds stupid even to me, but there must be at least somewhat clever way to achieve such effect and I don't know how else to explain it. I need to sort array using sorted in stream API. Here is my stream so far:

Arrays.stream(sequence.split(" "))
        .mapToInt(Integer::parseInt)
        .boxed()
        .sorted((a, b) -> a.compareTo(b))
        .forEach(a -> System.out.print(a + " "));

Now I have two different sorts of course - ascending and descending and the sort I need to use is specified in the user input. So what I want to do is having something like switch with 2 cases: "ascending" and "descending" and a variable to store the lambda expression respectively:

switch(command) {
    case "ascending": var = a.compareTo(b);
    case "descending": var = b.compareTo(a);
}

Then I my sorted looks like:

 .sorted((a, b) -> var)

I got the idea in a python course I attended. There it was available to store an object in variable, thus making the variable "executable". I realize that this lambda is not an object, but an expression, but I'm asking is there any clever way that can achieve such result, or should I just have

if(var)

and two diferent streams for each sort order.

4
  • You can assign lambdas to variables (they're just another way of writing anonymous inner classes), have a look here for example: stackoverflow.com/questions/21920039/… Commented Mar 31, 2016 at 12:19
  • this lambda (int a, int b) -> a.compareTo(b) is in fact an anonymous class object implementing IntBiFunction interface. Commented Mar 31, 2016 at 12:29
  • 2
    @SashaSalauyou It can implement arbitrary interfaces, as long as they only have one method with the appropriate signature (e.g. IntBinaryOperator). The problem is that there is no "generic superinterface" that represents all these types. Commented Mar 31, 2016 at 13:43
  • @Marco13 oh, I see. Thank you for clarification (and of course, I meant IntBinaryOperator) Commented Mar 31, 2016 at 13:46

3 Answers 3

15

The question is not stupid at all. Answering it in a broader sense: Unfortunately, there is no generic solution for that. This is due to the type inference, which determines one particular type for the lambda expression, based on the target type. (The section about type inference may be helpful here, but does not cover all details regarding lambdas).

Particularly, a lambda like x -> y does not have any type. So there is no way of writing

GenericLambdaTypefunction = x -> y;

and later use function as a drop-in replacement for the actual lambda x -> y.

For example, when you have two functions like

static void useF(Function<Integer, Boolean> f) { ... }
static void useP(Predicate<Integer> p) { ... }

you can call them both with the same lambda

useF(x -> true);
useP(x -> true);

but there is no way of "storing" the x -> true lambda in a way so that it later may be passed to both functions - you can only store it in a reference with the type that it will be needed in later:

Function<Integer, Boolean> f = x -> true;
Predicate<Integer>         p = x -> true;
useF(f);
useP(p);

For your particular case, the answer by Konstantin Yovkov already showed the solution: You have to store it as a Comparator<Integer> (ignoring the fact that you wouldn't have needed a lambda here in the first place...)

Sign up to request clarification or add additional context in comments.

2 Comments

You could still useP(f::apply)
@DidierL Sure, but this implies that you already stored it with a known type (namely, Function, or any other type where the method is called apply....)
8

You can switch between using Comparator.reverseOrder() and Comparator.naturalOrder:

Comparator<Integer> comparator = youWantToHaveItReversed ? Comparator.reverseOrder(): Comparator.naturalOrder();
Arrays.stream(sequence.split(" "))
      .map(Integer::valueOf)
      .sorted(comparator)
      .forEach(a -> System.out.print(a + " "));

1 Comment

The method reference Integer::compareTo is as obsolete as a comparator implemented as (a, b) -> a.compareTo(b). If the items are comparable, you can just use Comparator.naturalOrder(), e.g. Comparator<Integer> comparator = Comparator.naturalOrder();. Or you get rid of the follow-up if statement and do a simple Comparator<Integer> comparator = youWantToHaveItReversed? Comparator.reverseOrder(): Comparator.naturalOrder();
0

In Lambdas you can use a functionblock (a,b) -> { if(anything) return 0; else return -1;}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.