Convert Stream to IntStream - java

I have a feeling I'm missing something here. I found myself doing the following
private static int getHighestValue(Map<Character, Integer> countMap) {
return countMap.values().stream().mapToInt(Integer::intValue).max().getAsInt();
}
My problem is with the silly conversion from Stream to IntStream via the mapToInt(Integer::intValue)
Is there a better way of doing the conversion? all this is to avoid using max() from Stream, which requires passing a Comparator but the question is specifically on the convertion of Stream to IntStream

Due to type erasure, the Stream implementation has no knowledge about the type of its elements and can’t provide you with neither, a simplified max operation nor a conversion to IntStream method.
In both cases it requires a function, a Comparator or a ToIntFunction, respectively, to perform the operation using the unknown reference type of the Stream’s elements.
The simplest form for the operation you want to perform is
return countMap.values().stream().max(Comparator.naturalOrder()).get();
given the fact that the natural order comparator is implemented as a singleton. So it’s the only comparator which offers the chance of being recognized by the Stream implementation if there is any optimization regarding Comparable elements. If there’s no such optimization, it will still be the variant with the lowest memory footprint due to its singleton nature.
If you insist on doing a conversion of the Stream to an IntStream there is no way around providing a ToIntFunction and there is no predefined singleton for a Number::intValue kind of function, so using Integer::intValue is already the best choice. You could write i->i instead, which is shorter but just hiding the unboxing operation then.

I realize you are trying to avoid a comparator, but you could use the built-in for this by referring to Integer.compareTo:
private static int getHighestValue(Map<Character, Integer> countMap) {
return countMap.values().stream().max(Integer::compareTo).get();
}
Or as #fge suggests, using ::compare:
private static int getHighestValue(Map<Character, Integer> countMap) {
return countMap.values().stream().max(Integer::compare).get();
}

Another way you could do the conversion is with a lambda: mapToInt(i -> i).
Whether you should use a lambda or a method reference is discussed in detail here, but the summary is that you should use whichever you find more readable.

If the question is "Can I avoid passing converter while converting from Stream<T> to IntStream?" one possible answer might be "There is no way in Java to make such conversion type-safe and make it part of the Stream interface at the same time".
Indeed method which converts Stream<T> to IntStream without a converter might be looked like this:
public interface Stream<T> {
// other methods
default IntStream mapToInt() {
Stream<Integer> intStream = (Stream<Integer>)this;
return intStream.mapToInt(Integer::intValue);
}
}
So it suppose to be called on Stream<Integer> and will fail on other types of streams. But because streams are lazy evaluated and because of the type erasure (remember that Stream<T> is generic) code will fail at the place where stream is consumed which might be far from the mapToInt() call. And it will fail in a way that is extremely difficult to locate source of the problem.
Suppose you have code:
public class IntStreamTest {
public static void main(String[] args) {
IntStream intStream = produceIntStream();
consumeIntStream(intStream);
}
private static IntStream produceIntStream() {
Stream<String> stream = Arrays.asList("1", "2", "3").stream();
return mapToInt(stream);
}
public static <T> IntStream mapToInt(Stream<T> stream) {
Stream<Integer> intStream = (Stream<Integer>)stream;
return intStream.mapToInt(Integer::intValue);
}
private static void consumeIntStream(IntStream intStream) {
intStream.filter(i -> i >= 2)
.forEach(System.out::println);
}
}
It will fail on consumeIntStream() call with:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at java.util.stream.ReferencePipeline$4$1.accept(ReferencePipeline.java:210)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfInt.evaluateSequential(ForEachOps.java:189)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.IntPipeline.forEach(IntPipeline.java:404)
at streams.IntStreamTest.consumeIntStream(IntStreamTest.java:25)
at streams.IntStreamTest.main(IntStreamTest.java:10)
Having this stacktrace do you able to quickly identify that the problem is in produceIntStream() because mapToInt() was called on the stream of the wrong type?
Of course one can write converting method which is type safe because it accepts concrete Stream<Integer>:
public static IntStream mapToInt(Stream<Integer> stream) {
return stream.mapToInt(Integer::intValue);
}
// usage
IntStream intStream = mapToInt(Arrays.asList(1, 2, 3).stream())
but it's not very convenient because it breaks fluent interface nature of the streams.
BTW:
Kotlin's extension functions allow to call some code as it is a part of the class' interface. So you are able to call this type-safe method as a Stream<java.lang.Integer>'s method:
// "adds" mapToInt() to Stream<java.lang.Integer>
fun Stream<java.lang.Integer>.mapToInt(): IntStream {
return this.mapToInt { it.toInt() }
}
#Test
fun test() {
Arrays.asList<java.lang.Integer>(java.lang.Integer(1), java.lang.Integer(2))
.stream()
.mapToInt()
.forEach { println(it) }
}

Related

How should I design this method in order to take a list of lambda expressions as an input?

I have the following assignment:
Design a class whose objects have the methods:
setValue which, given a String and an integer value, associates the value with the noun of the variable
getValue which returns the integer value associated with a given String
execute which invokes in sequence a given list of lambda expressions, where each one takes an instance of the class, return nothing, and act on the class through the methods setValue and getValue.
So for the example, after the following:
MyClass instance = new MyClass();
instance.execute(List.of(e -> e.setValue("x", 1),
e -> e.setValue("y", 2)));
instance should contain the values 1 for "x" and 2 for "y".
Here is what I've done so far, I think it's alright:
public class MyClass {
private Map<String,Integer> map;
public int getValue(String name) {return map.get(name);}
public void setValue(String name, int value) {map.put(name, value);}
I am not seeing the way to go for execute. I know I need a functional interface for those lambda expressions, but then I can't solve errors shown by Eclipse when writing instance.execute(List.of(...)) , e.g. "The method of(Object, Object) in the type List is not applicable for the arguments ((<no type> e) -> {}, (<no type> e) -> {}).
How can I make it work?
You need to supply a list of Consumer<MyClass>. A Consumer is a functional interface with a single abstract method called accept which performs the action on the the given argument. Try this.
public void execute(List<Consumer<MyClass>> list) {
list.forEach(cons -> cons.accept(this));
}
The problem with List::of is that you have to either use Java 9 or you can simply do this.
public void execute(Consumer<MyClass> ...list) {
Stream.of(list).forEach(cons -> cons.accept(this));
}
You have it backwards: If you want to call the method for a number of values, those values are the stream. Presuming you have a Map<String, Integer> that represents your "x": 1 dataset, you can do this:
valuesMap.entrySet().stream()
.forEach(entry -> instance.setValue(entry.getKey(), entry.getValue());
Given your problem statement, though, it looks like you're being asked to do something closer to the Visitor pattern. In this case, you need an interface for the lambdas to implement, and there's a built-in one: Consumer<MyClass>. You should get familiar with this one as well as Supplier and Function, since they're very common.
If you declare your execute method to take a list of these, then you can use a for loop or a stream to process them, or use the convenient built-in forEach method:
public void execute(List<Consumer<MyClass>> consumers) {
consumers.forEach(consumer -> consumer.accept(this));
}

Math.toIntExact inside lambda expression?

I'm learning about lambda expressions.
Given a list of names, I want to count the numbers of names that start with N.
I did that:
final static List<String> friends = Arrays.asList("Brian", "Nate", "Neal", "Raju", "Sara", "Scott");
public static int countFriendsStartWithN() {
return Math.toIntExact(friends
.stream()
.filter(name -> name.startsWith("N"))
.count());
}
The call to the count method returns a primitive long but I want an int.
I used Math.toIntExact to get the long value as int.
Is it possible to get the int value directly inside the lambda expression?
No, it is not possible to fit your call to toIntExact into your chain of method calls, your stream pipeline. This is because count is a terminal operation and returns a primitive long on which no method call is possible. A terminal operation is an operation that ends the stream pipeline and produces a result (or a side effect).
So I believe the best thing you can do is to live with the code you already have. IMHO it’s fine.
Well, here's a somewhat silly way of calculating the count as an int without casting:
public static int countFriendsStartWithN() {
return friends.stream()
.filter(name -> name.startsWith("N"))
.mapToInt (s -> 1)
.sum();
}
You can't do anything inside the lambda expression you currently have, since that's a Predicate: it returns a boolean. Math.toIntExact returns an int.
You can do it without the Math.toIntExact (or a simple cast) like so:
return /* create stream, filter */
.mapToInt(a -> 1).sum();
But this is likely to be slower than doing what you are doing at the moment.
Yet another option that is not really better - it is possible to use a collector that applies a finisher:
public static int countFriendsStartWithN() {
return friends.stream()
.filter(name -> name.startsWith("N"))
.collect(Collectors.collectingAndThen(Collectors.counting(), Math::toIntExact));
}
This may have an advantage if you need it frequenty - you could build a utility method returning this Collector to make it reusable.
Here's a way to do this with reduce
public static int countFriendsStartWithN2() {
return friends
.stream()
.filter(name -> name.startsWith("N"))
.map(s -> 1)
.reduce(0, Integer::sum);
}

How to convert an Optional to an OptionalInt?

I have an Optional that I want to "convert" to an OptionalInt, but there doesn't seem to be a simple way to do this.
Here's what I want to do (contrived example):
public OptionalInt getInt() {
return Optional.ofNullable(someString).filter(s -> s.matches("\\d+")).mapToInt(Integer::parseInt);
}
However, there's no mapToInt() method for Optional.
The best I could come up with is:
return Optional.ofNullable(someString)
.filter(s -> s.matches("\\d+"))
.map(s -> OptionalInt.of(Integer.parseInt(s)))
.orElse(OptionalInt.empty());
but that seems inelegant.
Am I missing something from the JDK that can make the conversion more elegant?
While the code isn't more readable than an ordinary conditional expression, there is a simple solution:
public OptionalInt getInt() {
return Stream.of(someString).filter(s -> s != null && s.matches("\\d+"))
.mapToInt(Integer::parseInt).findAny();
}
With Java 9, you could use
public OptionalInt getInt() {
return Stream.ofNullable(someString).filter(s -> s.matches("\\d+"))
.mapToInt(Integer::parseInt).findAny();
}
As said, neither is more readable than an ordinary conditional expression, but I think, it still looks better than using mapOrElseGet (and the first variant doesn't need Java 9.
No, there's no way to do it in more elegant way using standard Java API. I asked Paul Sandoz about adding mapToInt, etc., here's his answer:
Me:
Isn't it a good idea to provide also a way
to transfer between Optional types like mapToInt, mapToObj, etc.,
like it's done in Stream API?
Paul:
I don’t wanna go there, my response is transform Optional* into a *Stream. An argument for adding mapOrElseGet (notice that the primitive variants return U) is that other functionality can be composed from it.
So you will likely to have in Java-9:
return Optional.of(someString).filter(s -> s.matches("\\d+"))
.mapOrElseGet(s -> OptionalInt.of(Integer.parseInt(s)), OptionalInt::empty);
But nothing more.
That's because JDK authors insist that the Optional class and its primitive friends (especially primitive friends) should not be widely used, it's just a convenient way to perform a limited set of operations on the return value of methods which may return "the absence of the value". Also primitive optionals are designed for performance improvement, but actually it's much less significant than with streams, so using Optional<Integer> is also fine. With Valhalla project you will be able to use Optional<int> and OptionalInt will become unnecessary.
In your particular case the better way to do it is using ternary operator:
return someString != null && someString.matches("\\d+") ?
OptionalInt.of(Integer.parseInt(someString)) : OptionalInt.empty();
I assume that you want to return the OptionalInt from the method. Otherwise it's even more questionable why you would need it.
If you have any object and not just a String, you can temporarily go through a Stream:
public static <T> OptionalInt toOptionalInt(Optional<T> optional, ToIntFunction<? super T> func) {
return optional.map(Stream::of).orElseGet(Stream::empty)
.mapToInt(func)
.findFirst();
}
This solution has the advantage to be a one-liner, meaning you can copy/paste the content of the method and just change func to whatever you want. The disadvantage is going through a Stream to achieve what you want. But if you want a generic one-liner, this is it.
If you want a utility method, you probably prefer to use the following:
public static <T> OptionalInt toOptionalInt(Optional<T> optional, ToIntFunction<? super T> func) {
if (optional.isPresent()) {
return OptionalInt.of(func.applyAsInt(optional.get()));
} else {
return OptionalInt.empty();
}
}
This is how I convert an Optional<String> to OptionalInt
OptionalInt lastSeenId = Optional.of("123").map(Integer::parseInt).map(OptionalInt::of).orElseGet(OptionalInt::empty);
Here's another option that doesn't need to use a Stream and avoids compiling regex every time:
private static final Predicate<String> IS_DIGITS = Pattern.compile("^\\d+$")
.asPredicate();
public OptionalInt getInt() {
return Optional.ofNullable(someString)
.filter(IS_DIGITS)
.map(Integer::valueOf)
.map(OptionalInt::of)
.orElseGet(OptionalInt::empty);
}
Note that you need to anchor the regex because asPredicate() uses find() instead of matches().
Or if you're using Guava, you can eliminate the regex entirely and use their Ints class:
public OptionalInt getInt() {
return Optional.ofNullable(someString)
.map(Ints::tryParse)
.map(OptionalInt::of)
.orElseGet(OptionalInt::empty);
}

Iterate an Enumeration in Java 8

Is it possible to iterate an Enumeration by using Lambda Expression? What will be the Lambda representation of the following code snippet:
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
while (nets.hasMoreElements()) {
NetworkInterface networkInterface = nets.nextElement();
}
I didn't find any stream within it.
(This answer shows one of many options. Just because is has had acceptance mark, doesn't mean it is the best one. I suggest reading other answers and picking one depending on situation you are in. IMO:
for Java 8 Holger's answer is nicest, because aside from being simple it doesn't require additional iteration which happens in my solution.
for Java 9 I would pick solution describe in Tagir Valeev answer)
You can copy elements from your Enumeration to ArrayList with Collections.list and then use it like
Collections.list(yourEnumeration).forEach(yourAction);
If there are a lot of Enumerations in your code, I recommend creating a static helper method, that converts an Enumeration into a Stream. The static method might look as follows:
public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
return StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
new Iterator<T>() {
public T next() {
return e.nextElement();
}
public boolean hasNext() {
return e.hasMoreElements();
}
},
Spliterator.ORDERED), false);
}
Use the method with a static import. In contrast to Holger's solution, you can benefit from the different stream operations, which might make the existing code even simpler. Here is an example:
Map<...> map = enumerationAsStream(enumeration)
.filter(Objects::nonNull)
.collect(groupingBy(...));
Since Java-9 there will be new default method Enumeration.asIterator() which will make pure Java solution simpler:
nets.asIterator().forEachRemaining(iface -> { ... });
In case you don’t like the fact that Collections.list(Enumeration) copies the entire contents into a (temporary) list before the iteration starts, you can help yourself out with a simple utility method:
public static <T> void forEachRemaining(Enumeration<T> e, Consumer<? super T> c) {
while(e.hasMoreElements()) c.accept(e.nextElement());
}
Then you can simply do forEachRemaining(enumeration, lambda-expression); (mind the import static feature)…
You can use the following combination of standard functions:
StreamSupport.stream(Spliterators.spliteratorUnknownSize(CollectionUtils.toIterator(enumeration), Spliterator.IMMUTABLE), parallel)
You may also add more characteristics like NONNULL or DISTINCT.
After applying static imports this will become more readable:
stream(spliteratorUnknownSize(toIterator(enumeration), IMMUTABLE), false)
now you have a standard Java 8 Stream to be used in any way! You may pass true for parallel processing.
To convert from Enumeration to Iterator use any of:
CollectionUtils.toIterator() from Spring 3.2 or you can use
IteratorUtils.asIterator() from Apache Commons Collections 3.2
Iterators.forEnumeration() from Google Guava
For Java 8 the simplest transformation of enumeration to stream is:
Collections.list(NetworkInterface.getNetworkInterfaces()).stream()
I know this is an old question but I wanted to present an alternative to Collections.asList and Stream functionality. Since the question is titled "Iterate an Enumeration", I recognize sometimes you want to use a lambda expression but an enhanced for loop may be preferable as the enumerated object may throw an exception and the for loop is easier to encapsulate in a larger try-catch code segment (lambdas require declared exceptions to be caught within the lambda). To that end, here is using a lambda to create an Iterable which is usable in a for loop and does not preload the enumeration:
/**
* Creates lazy Iterable for Enumeration
*
* #param <T> Class being iterated
* #param e Enumeration as base for Iterator
* #return Iterable wrapping Enumeration
*/
public static <T> Iterable<T> enumerationIterable(Enumeration<T> e)
{
return () -> new Iterator<T>()
{
#Override
public T next()
{
return e.nextElement();
}
#Override
public boolean hasNext()
{
return e.hasMoreElements();
}
};
}

Guava Optional type, when transformation returns another Optional

I have a method that procudes an Optional<String>
But this String must be parsed at another application level as Integer or Long.
This I have a Function<String, Integer> that can be applied on the String, to produce an Integer.
This transformation can fail because the String may not be an Integer parsable value.
I would like to return Optional when the transformation fails, instead of throwing a parsing exception.
I can't make the STRING_TO_INTEGER_FUNCTION return null, because it is not allowed by Guava:
Exception in thread "main" java.lang.NullPointerException: Transformation function cannot return null.
Thus the only thing I can do is having a Function<String,Optional<Integer>> but then I get as final result an Optional<Optional<Integer>> which isn't really cool because I may have another transformations to apply on it.
Does someone know how can I do something like that in Guava?
Optional.of("Toto").transform(STRING_TO_INTEGER_FUNCTION) = // Optional<Integer> ?
Thanks
I guess you can do:
public static void main(final String[] args) {
final Optional<Integer> valid = Optional.of("42")
.transform(STR_TO_INT_FUNCTION)
.or(Optional.<Integer>absent());
System.out.println(valid); // Optional.of(42)
final Optional<Integer> invalid = Optional.of("Toto")
.transform(STR_TO_INT_FUNCTION)
.or(Optional.<Integer>absent());
System.out.println(invalid); // Optional.absent()
final Optional<Integer> absent = Optional.<String>absent()
.transform(STR_TO_INT_FUNCTION)
.or(Optional.<Integer>absent());
System.out.println(absent); // Optional.absent()
}
private static final Function<String, Optional<Integer>> STR_TO_INT_FUNCTION =
new Function<String, Optional<Integer>>() {
#Override
public Optional<Integer> apply(final String input) {
return Optional.fromNullable(Ints.tryParse(input));
}
};
Usage isn't that clumsy when you use Optional -> transform -> or in one line (assigning transformed optional integer would produce Optional<Optional<Integer>>).
Using Optional.transform just doesn't seem compatible with a transformation that might fail - theoretically this implies an optional optional, when what you want to do is consolidate absences. I would recommend using something like the following:
Optional<String> strOptional = Optional.of("Toto");
Optional<Integer> intOptional =
strOptional.isPresent()
? Optional.fromNullable(Ints.tryParse(strOptional.get()))
: Optional.<Integer>absent();
Another options except those stated above:
use plain old if/else (Guava team recommends not to overuse such constructs, it's often wise to obey these recommendation - otherwise you won't spare much lines of code and make readability worse)
use dirty trick: from(singleton("Toto")).transform(STRING_TO_INTEGER_FUNCTION).filter(notNull()).first().orNull() - only hypothetical idea, IMHO its badly readable too. At least it contains none generics, ?: operator or anonymous class, at the cost of more static imports.
wait for Java 8, where Optional.map allows null transformation result
You can vote for http://code.google.com/p/guava-libraries/issues/detail?id=1171 . Unfortunately Guava team seems hesitant with shifting this issue to some result.

Categories