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);
}
Related
I wrote code that works, however I had to create extra lines, is there a way to compress that in one line? The logic: take last page, perform searching function by regex, if not located, take the page before and perform searching function by regex
Optional<String> totalBoxesLastPage = lastPage.locate(INVOICE_TOTAL_AMOUNT_BOXES);
Optional<String> totalBoxes = totalBoxesLastPage.isPresent() ?
totalBoxesLastPage : nextToLastPage
.flatMap(p -> p.locate(INVOICE_TOTAL_AMOUNT_BOXES));
Thank you guys
You may use orElseGet with a supplier to call some function which computes the value if the optional is empty. If a value is present, it returns the value, otherwise returns the result produced by the supplying function. In your case you have to pass Supplier<String>. Moreover, your return type after unwrapping the Optional should be a String, not an Optional<String>.
String totalBoxes = totalBoxesLastPage
.orElseGet(() -> nextToLastPage.flatMap(p -> p.locate(INVOICE_TOTAL_AMOUNT_BOXES))
.orElseThrow(IllegalStateException::new));
This worked out for me , i was really blind by not seeing .or function
or(Supplier<? extends Optional<? extends T>> supplier)
public Optional<String> findBetweenTwo(Page lastPage,Optional<Page> nextToLast,Pattern pattern) {
return lastPage.locate(pattern).or(() -> nextToLast.flatMap(p -> p.locate(pattern)));
}
I have such code example.
import java.util.LinkedList;
import java.util.List;
import java.util.stream.LongStream;
public class RemovedNumbers {
public static List<long[]> removNb(long n) {
System.out.println(n);
long sum = ((n + 1) * n / 2);
long minMultiplication = sum - 2 * n + 1;
long minCandidate = (long) Math.sqrt(minMultiplication);
LinkedList<long[]> list = new LinkedList<>();
LongStream.rangeClosed(minCandidate, n)
.mapToObj(a -> new long[]{a, calculateB(a, sum)})
.filter(longs -> longs[0] > longs[1])
.filter(longs -> longs[1] <= n)
.filter(longs -> longs[0] * longs[1] == sum - longs[0] - longs[1])
.forEach(longs -> addArrays(list, longs));
return list;
}
private static long calculateB(long a, long sum) {
return (sum - a) / (a + 1);
}
private static void addArrays(final LinkedList<long[]> list, final long[] longs) {
list.addFirst(new long[]{longs[1], longs[0]});
list.add(longs);
}
}
This code is complicated for me in LongStream part.
I don't get some points, so I need a help:
I examine LongStream class.
This class uses four methods: rangeClosed, mapToObj, filter, forEach (their description I found on Java docs). Unfortunately, now I am starting to examine java 1.8 version, so I can't understand how it works and what's happens.
Where is appeared "a" in mapToObj? What is it? I don't see var "a" declaration in previous part of code.
As I've got lambda is made by such scheme: (arguments) -> (body). So the "a" is an argument, "new long[]..." - is a body. This part isn't causes any question for me. But the next one, whereis "longs" - argument, "longs[0] > longs[1]" - body, causes some questions. What is the var "longs"? It hasn't declaration in the past! HOW it appears? How it works?
Am I right that LongStream class can be writes in one line? Like: LongStream.rangeClosed().filter().filter().filter().forEach(); ?
Am I right that all methods execute consequently? By each other? The first rangeClosed, then mapToObj, then filter... or is there another order?
Thanks a lot!
Your third point kind of answers your second point - a is the parameter of the lambda expression passed to mapToObj.
If you can understand that, then your fourth point should be easy to understand as well. longs is the parameter for the lambda expression passed to filter. Remember that you can name your parameter names whatever you like. I guess the reason why the author of the code renamed the parameter to longs is because in the previous line, each long in the stream is mapped into a long[], so now it's a stream of long arrays.
Am I right that LongStream class can be writes in one line?
Yes, but you would end up with a super long line of code, so we almost never do that.
Am I right that all methods execute consequently? By each other? The first rangeClosed, then mapToObj, then filter... or is there another order?
The methods get called in that order, but the operations they do won't run immediately. This is the cool part of streams. The longs will only be mapToObj'ed and filter'ed when you do forEach, a terminal operation. In other words, mapToObj and filter are kind of like saying "this is what this stream should do..." and when you do forEach, you are saying "now do it!"
If you still don't get what streams are doing, try to think of them as a production line in a factory. At the start, you have longs on the conveyer belts. And then they pass through a machine, transforming each of them into a long[]. After that, they pass through three filters. These filters will push them off the conveyer belt unless the long arrays fulfil some condition.
EDIT:
If you want to write this code without lambdas, you can write it with anonymous classes instead:
LongStream.rangeClosed(minCandidate, n)
.mapToObj(new LongFunction<long[]>() {
#Override
public long[] apply(long a) {
return new long[]{a, calculateB(a, sum)};
}
})
.filter(new Predicate<long[]>() {
#Override
public boolean test(long[] longs) {
return longs[0] > longs[1] &&
longs[1] <= n &&
longs[0] * longs[1] == sum - longs[0] - longs[1];
}
})
.forEach(new Consumer<long[]>() {
#Override
public void accept(long[] longs) {
addArrays(list, longs);
}
});
Each lambda expression implements a functional interface, or to be more specific, it implements the single abstract method of that functional interface.
Therefore, in a -> new long[]{a, calculateB(a, sum)}, a is the argument of the method implemented by the functional interface. Since mapToObj accepts an argument of type LongFunction, this lambda expression implements the R apply(long value) method of that interface, which means that lambda expression can also be written as (long a) -> new long[]{a, calculateB(a, sum)}.
This mapToObj call transforms the LongStream to a Stream<long[]>, so the lambda expression of the following filter call - longs -> longs[0] > longs[1] can also be written as (long[] longs) -> longs[0] > longs[1] - it implements the functional interface Predicate<long[]>, which means it implements boolean test(long[] t).
Yes, you can write this entire stream pipeline in a single line, but it would be more readable split into multiple lines.
Am I right that all methods execute consequently? By each other? The first rangeClosed, then mapToObj, then filter... or is there another order
Not exactly. While each intermediate method produces an output used as input to the next method, the evaluation of these methods only begins once the terminal operation - forEach in this case - is executed. And these operations don't necessarily process all the elements of the Stream. For example, if the terminal operation would be firstFirst() instead of forEach, the pipeline would only process enough elements until the first element that passes all the filters is found.
Am I right that LongStream class can be writes in one line?
What you're witnessing here is method chaining. This is where method after method can get chained to eachother. This can be done for almost all classes.
Everything else is pretty much answered by Sweeper.
3 and 4:
you are tryng to understand how lambda work so I'll break it down your code for you:
// this return a LongStream obj
LongStream.rangeClosed(minCandidate, n)
// so with point notation you can access to one of the method in LongStream
// matToObj in this case.
.mapToObj(a -> new long[]{a, calculateB(a, sum)})
what is a? What ->? what the other stuff?
MapToObj takes a IntFunction mapper argument and a is a declaration of that type on the fly this is why you didin't see it before in the code.
the arrow indicates that the right site is the lamba expression, if you have a inline operation you can omit the return statement and you can not include {} brackets so imagine that statement like a return statement.
With lamba functions you can easily create chains of operation this is why you have many functions called one after another. You have to keep in mind that the next function takes as argument an object type that is of the same type of the return type of the previous function.
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);
}
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) }
}
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.