How to turn a number reading directly into a stream?

Asked

Viewed 62 times

3

Recently I wrote a reply exploring a little more the API of stream of Java 8, but I must say I was disappointed with some details of my code.

The idea was to read a sequence of numbers and then return what was the highest and lowest value of the readings taken. In this case, the entry ended when the number 0 was entered.

I don’t know how to skillfully use an iterable with the Apis of stream. So I decided to go by the pig method and goal: I can read dice and play in a ArrayList to then use this list quietly to stream. The resulting code was this:

Scanner input = new Scanner(System.in); 
ArrayList<Double> lista = new ArrayList<>();

double valorLido;
while (true) {
  valorLido = input.nextDouble();
  if (valorLido == 0) {
    break;
  }
  lista.add(valorLido);
}
DoubleSummaryStatistics summary = lista.stream().collect(Collectors.summarizingDouble(Double::doubleValue));
double maior = summary.getMax();
double menor = summary.getMin();
System.out.println("maior " + maior);
System.out.println("menor " + menor);

This code did not please me. I would like to be able to directly use the reading result to pass to stream no need to transform into any kind of collection.

For example, if I were to obtain an eternal reading, I would do so:

Iterable<Double> leitorDoubleAteh0(Scanner in) {
  return () -> new Iterator<Double>() {
    boolean conseguiuFetch;
    double valorFetch;
    void fetchNext() {
        valorFetch = in.nextDouble();
        conseguiuFetch = valorFetch != 0;
    }

    @Override
    public boolean hasNext() {
      return conseguiuFetch;
    }

    @Override
    public Double next() {
      if (!conseguiuFetch) {
        throw new NoSuchElementException("fim da leitura");
      }
      double valorRetorno = valorFetch;
      fetchNext();
      return valorRetorno;
    }

    {
      fetchNext();
    }
  };
}

That would at least give me access to foreach, but still it is not my desired stream.

  • 1

    I don’t know if I fully understood the question, but if the idea is how to go directly to min and max can do without collecting with lista.stream().max(Double::compare).get() since the max and min of the stream take a Comparator

  • Fair, but that doesn’t explain how to turn a reading sequence into a stream without going through a collection.

  • The big problem here is that reading from the console you don’t get an EOF. A solution with a number of known lines is elegant but helps you?

  • @Julianoalves known and limited number would not be my focus. The intention is to avoid loading an entire list into memory. I would like to work with stream using o(1) memory, no o(n)

1 answer

2


With the method Stream.generate(Supplier<? extends T>), you can read the numbers of Scanner without needing the ArrayList.

I know the tag is . But if you accept to use Java 9 or higher, you can use method Stream.takeWhile(Predicate<? super T>) to make the stop criteria.

That is the result:

Scanner input = new Scanner(System.in);
DoubleSummaryStatistics summary = Stream
        .generate(input::nextDouble)
        .takeWhile(z -> z != 0)
        .collect(Collectors.summarizingDouble(Double::doubleValue));
double maior = summary.getMax();
double menor = summary.getMin();
System.out.println("maior " + maior);
System.out.println("menor " + menor);
  • I have code limitations for Java 8 (GWT and Totalcross support, the versions used only support Java 8), but obviously I accept new suggestions. I’m negotiating with the operations people to try to move up to Java 10 on trial

Browser other questions tagged

You are not signed in. Login or sign up in order to post.