4

How to properly create an Iterable<? extends SuperClass> from Iterator<SubClass>?

Let's just say that I have an Iterator<String> and I want to use a method that takes an Iterable<? extends CharSequence>. This is of course not possible:

private String foo(Deque<String> words) {
    Iterator<String> iterator = words.descendingIterator();
    return String.join(" ", () -> iterator);
}

The only way I found to make it compile was with

private String foo(Deque<String> words) {
       Iterator<? extends CharSequence> iterator = words.descendingIterator();
       return String.join(" ", () -> (Iterator<CharSequence>) iterator);
}

But I get an Unchecked cast warning. Is there a way to do this a clean way?

ETO
  • 6,970
  • 1
  • 20
  • 37
Ricola
  • 2,621
  • 12
  • 22
  • 2
    Two obvious problems here: `String.join` takes an `Iterable`, not an `Iterator`. Also, why are you using the supplier lambda expression? – ernest_k Jan 15 '19 at 18:54
  • 1
    Your question is the answer to the first "problem" you stated : http://www.lambdafaq.org/how-can-i-turn-an-iterator-into-an-iterable/ – Ricola Jan 15 '19 at 20:34
  • `.stream().collect(joining(" "))` – Boris the Spider Jan 15 '19 at 20:44
  • @BoristheSpider `.stream()` of what? `words.stream()` would be not be in the order I expect. You can create a stream from an `Iterable` with `.spliterator()` but you need an `Iterable` again. Anyway, the `.join()` method was just there for an example. – Ricola Jan 15 '19 at 20:53
  • Not sure why you think that you cannot create a `Stream` from an `Iterator` - https://stackoverflow.com/questions/24511052/how-to-convert-an-iterator-to-a-stream. Do that and don't create non-compliant `Iterable` implementations; using lambdas or otherwise. – Boris the Spider Jan 16 '19 at 20:09

2 Answers2

3

You could try also:

private String foo(Deque<String> words) {
    return String.join(" ", (Iterable<String>) words::descendingIterator);
}

But for general case it would be better to create an utility method:

public static <T> Iterable<T> iterable(Iterable<T> iterable) {
    return iterable;
}

Then use it simply like this:

 private static String foo(Deque<String> words) {
    return String.join(" ", iterable(words::descendingIterator));
}
ETO
  • 6,970
  • 1
  • 20
  • 37
-1

OK I found what I was looking for and it was actually pretty simple:

private String foo(Deque<String> words) {
    Iterator<String> iterator = words.descendingIterator();
    return String.join(" ", (Iterable<String>) () -> iterator);
}

No need to use the wildcard at all.

Ricola
  • 2,621
  • 12
  • 22
  • Well, it's nice that you finally decided to accept your own answer. :-) – ETO Sep 04 '19 at 18:54
  • It would be interesting to hear your arguments against my first solution (upvoted by the community). – ETO Sep 04 '19 at 18:56
  • @ETO : I never said that your answer was bad (I upvoted it). It's just that this was exactly was I was looking for and answering the original question : *How to properly create an Iterable extends SuperClass> from Iterator?*. In my question, I was just not casting it properly. – Ricola Sep 09 '19 at 10:18
  • Do not call your answer ***the correct way***. Let the community decide the correctness. – ETO Sep 09 '19 at 16:30
  • First of all, I don't gain rep by accepting my own answer. Secondly, the choice to select which answer is accepted is given to the one asking the question, which he choses based on what he was looking for. It's the way it is at stackoverflow and I have seen sometimes bad/incomplete answer accepted. That's not perfect but that's why you have upvotes to rank answers. Thirdly, I edited my answer not to call it the "correct way" as you were right about the proper wording. – Ricola Sep 12 '19 at 13:42