Sum of the lengths of a string array using Java 8 streams - java

I've written this code that doesn't compile:
String[] text = {"hello", "bye"};
IntStream.of(Arrays.stream(text).map(String::length)).sum()
Do I need to convert the stream to an IntStream? And why do I get an error when I pass String::length to the map() function?

You should use Stream.mapToInt in order to get an IntStream instance:
String[] text = {"hello", "bye"};
int total = Arrays.stream(text).mapToInt(String::length).sum();

Try this
Arrays.stream(text)
.filter(Objects::nonNull)
.mapToInt(String::length)
.reduce(0,Integer::sum);

Do I need to convert the stream to an IntStream?
Well, you don't need to in order to find the total length of all the strings but it's better to do so for performance reasons.
And why do I get an error when I pass String::length to the map()
function?
If you change the method reference to a lambda, you'll get a better hint at what is wrong. i.e.
IntStream.of(Arrays.stream(text).map(e -> e.length())).sum();
Now, you don't only have a squiggly line near the map function but also under the IntStream.of method. After hovering over the of method on an IDE, I get the message:
"cannot resolve method of(java.util.stream.Stream<R>)"
Now, this tells us that we're passing the wrong thing to the of method. There are two overloads of the of method:
of(int... values)
of(int t)
As you can see these two methods expect either a set of values to be passed or a single value to be passed, being of type int.
Clearly, the IntStream.of method is not our friend, in this case, rather we will want:
int length = Arrays.stream(text) // Stream<String>
.mapToInt(String::length) //IntStream
.sum(); // int
This approach simply maps each string to its length and sums them all up.

Related

Java Get First Array Item from Optional

I was having some problem when trying to get the first array item out of Optional. Following as my code:
String[] temp = new String[2];
temp[0] = "email1";
temp[1] = "email2";
Optional<String[]> email = Optional.of(temp);
System.out.println(email.map(e -> e.get(0)).orElse(null));
I am trying to get the first email, otherwise just return as null. However, when I run this, I am getting these error messages:
System.out.println(email.map(e -> e.get(0)).orElse(null));
^
symbol: method get(int)
location: variable e of type String[]
1 error
When I tried to do this:
System.out.println(email.stream().findFirst().get());
It prints out weird value:
[Ljava.lang.String;#7adf9f5f
Any ideas? Thanks!
Arrays don't really have methods, per se. .get is something you call on a Collection, not a primitive array. Since the Optional contains an actual, primitive Java array, just use brackets [] to access the element.
System.out.println(email.map(e -> e[0]).orElse(null));
An Optional works alike an if-else test but lay out inside a special object to carry a value and make comparison to an equivalent
You put an "array" as a value into the Optional, the only object get() could return is the array not any of it's elements, also, get() for Optional does not take an argument in it.
The isPresent() boolean and the void
ifPresent(ConsumerAndItsValue cmv) methods are a test to find if the "VALUE" is present, works much more like comparing using if object.equals(this object)
So of you want to use it for particular email addresses you simply put in each string , the tests cannot see into the array, those elements are more objects.
Create a java.util.Consumer≪Anobject> the functional code assigned "to a lambda", Anobject should be the type in accept method accept(T to) method.
Here's a stack overflow page I found
Proper usage of Optional.ifPresent()
And it is possible to iterate over an array contents (external site example). https://mkyong.com/java8/java-8-consumer-examples/

How to convert Array to HashMap in Java with Stream API

I was trying to something pretty simple, but it fails on compilation, and I can't understand who
I have a list of headers, I need to convert it to
Map<Index, String> meaning the key (index) and the value is the header name
I know how to make it with for each, but I want to have it in Collectors.to map
any help would be appreciated
final String[] headerDisplayName = getHeaderDisplayName(harmonizationComponentDataFixRequest);
IntStream.of(0, headerDisplayName.length).collect(Collectors.toMap(Function.identity(), index-> headerDisplayName[index]));
You can use range method in combination with boxed method of IntStream.
(When you use the of method like in your example, only 0 and the size of the array are in this stream. In addition this would lead to an ArrayIndexOutOfBoundsException)
A possible solution would look like this (first parameter of the range method is included, the second parameter is excluded)
Map<Integer, String> map = IntStream.range(0, headerDisplayName.length)
.boxed()
.collect(Collectors.toMap(
Function.identity(),
i -> headerDisplayName[i])
);
Adding to the #csalmhof's answer, I think it's to explain here why using boxed is working.
If you don't use boxed() method and simply write the following:
Map<Integer, String> map = IntStream.range(0, headerDisplayName.length)
.collect(Collectors.toMap(
Function.identity(),
index -> headerDisplayName[index])
);
Java will have to take index as of type Object and there's no implicit conversion that can happen and so you'll get error.
But if you put boxed() like in the following code, you won't get error:
Map<Integer, String> map = IntStream.range(0, headerDisplayName.length)
.boxed()
.collect(Collectors.toMap(
Function.identity(),
index -> headerDisplayName[index])
);
you're not getting error here because java interprets index as an Integer and there's implicit casting happening from Integer to int.
A good IDE can help you with this type of explanation. In IntelliJ if you press ctrl + space after keeping your cursor on index (with Eclipse key-map enabled) you will get the following without boxed().
And this is what you get when you've boxed() placed.
I hope this clarifies why using boxed() is saving you from compilation error. Also, you can use this thing in future to find actual type of parameter in lambda which can be helpful in case cases (one of the case is the one that OP pointed out)

Java get nice toString for Object reference to some array type

If I have a reference of type Object and I know that this is an array, but I don't know what kind of array, what is the best way to generate a nice String?
Or in other words, what is the best / nicest implementation for the following method:
private static String anyArrayToString(Object someArray) {
if (!someArray.getClass().isArray()) {
throw new IllegalArgumentException("someArray is not an array!");
}
return ???;
}
I am aware of the methods from Arrays, namely Arrays.toString(int[]), Arrays.toString(double[]), etc. These do not work here because they are strongly typed and I don't feel like having a big if-else-if cascade. (although this is my plan B if no better solution can be found)
Ideally I would want a method that works on Object references such as System.arraycopy which checks dynamically if the passed reference is an array or not.
why do I not know what kind of array it is?
Because I get the object reference via reflection after iterating over all get-methods of a different object. It is part of a utility method that finds arbitrary differences between two complex objects even if these differences are nested deep.
Thank you very much.
Edit:
This is NOT a duplicate of What's the simplest way to print a Java array? because here the element type of the array is unknown and we only have a reference to Object rather than some specific array type.
The cleanest and most concise way of doing this would be to use the Java8 Stream API and the methods from the Array utility class.
The static method Array.getLength takes a reference of type Object. If that reference points to an array, the length of that array is returned. Otherwise an exception is thrown. Tne static method Array.get works accordingly to give access to individual array elements.
private static String anyArrayToString(Object someArray) {
if (!someArray.getClass().isArray()) {
throw new IllegalArgumentException("someArray is not an array!");
}
return "[" + IntStream.range(0, Array.getLength(someArray))
.mapToObj(i -> Objects.toString(Array.get(someArray, i)))
.reduce("", (l, r) -> l+", "+r)
+ "]";
}

Java 8 Streams:Why does mapToInt needs the Integer::parseInt as a parameter?

I am trying to understand something following the next example:
Stream.of("a1", "a2", "a3")
.map(s -> s.substring(1))
.mapToInt(Integer::parseInt)
.max()
. (etc.)
Why does mapToInt needs the
Integer::parseInt
as a parameter? Shouldn't it be implicit for it? Isn't this parameter redundant?
It's important to differentiate between what calling Stream#mapToInt(ToIntFunction) does and what the ToIntFunction argument does.
The call to mapToInt is what the stream is going to do (i.e. map the elements to an int).
The ToIntFunction argument is how the stream is going to map each element to an int.
Could they have included a no-arg mapToInt method that implicitly parses Strings to ints? Yes, but look at how well that works for Stream#sorted()—and that situation is nowhere near as arbitrary or ambiguous as a no-arg mapToInt method.
The no-arg sorted method assumes the elements are Comparable which is a fundamental, standardized and wide-spread interface in Java—any class can implement the interface (whereas there's only one class that can be a String). Thus while the method is not type-safe it can be argued the use-case is common enough to justify its existence.
However, a no-arg mapToInt method that assumes the elements are Strings and parses their content to an int is a highly specific use-case. Why would such a generic API offer such a specific operation? It'd be an entirely arbitrary decision with no reasonable justification. For instance, why not map each String to its length instead? And why is String being handled specially but not some other type(s)? Hence the method accepts a ToIntFunction argument that describes how to map the elements to an int on a case-by-case basis.
It may help to note that Integer::parseInt is a method reference, which is shorthand for a trivial lambda expression. Both are an implementation of a functional interface which is less verbose option than using an anonymous class. In other words, you're creating a new ToIntFunction instance and passing it as an argument.
All of the following are functionally equivalent:
// method reference
stream.mapToInt(Integer::parseInt)
// lambda expression
stream.mapToInt((String value) -> Integer.parseInt(value)) // explicit parameter types
stream.mapToInt(value -> Integer.parseInt(value)) // implicit parameter types
// anonymous class
stream.mapToInt(new ToIntFunction<>() {
#Override
public int applyAsInt(String value) {
return Integer.parseInt(value);
}
})
Where stream is a Stream<String>.
It is not redundant. You need to say how convert (say) the string "1" to the integer 1.
(I guess you could argue that a no-argument mapToLong method would be convenient, but the designers didn't include one in the API.)
I guess you could also be asking why go to the bother of the explicit integer conversion.
If you try to apply Stream::max to a stream of numbers-represented-as-strings, you will get the lexically largest value, not the numerically largest value. For example "9" is larger than "11".
Note that the Stream::max method does not have an overload with no arguments. You would need to provide a comparator; e.g.
Stream.of("a1", "a2", "a3")
.map(s -> s.substring(1))
.max(compareAsIntegers)
where
Comparator<String> compareAsIntegers = new Comparator<String>() {
public int compare (String s1, String s2) {
return Integer.compare(Integer.parseInt(s1),
Integer.parseInt(s2));
}
}
the operations you are doing are like:
Stream.of("a1", "a2", "a3") //step1
.map(s -> s.substring(1)) //step2
.mapToInt(Integer::parseInt) //step3
.max()
you define a stream of strings (in step1), then you take eauch of them an discard the 1 char on it leaving a stream of "1", "2"and "3", (step2) but note that those are still string objects...
then you convert that into integers therefore you need to give to the 'mapToInt' a "function" that takes a string as parameter and returns an integer (step3)
and that is defined in the Integer class:
https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#parseInt(java.lang.String)
you can for sure write and pass your own function... but why to reinvent the wheel? :)
substring returns a string not an integer.
mapToInt converts the stream of objects (in this case Strings) to an IntStream of int primitives. However it doesn't know how to do the mapping, you need to provide it a function, which in your case is parseInt.
Well actually, after reading the kind answers here I understood
1. That my question was not clear enough.
2. The answer...
So,
What I really meant was - isn't passing the Integer::parseInt as an argument to mapToInt redundant? Because I felt the mapToInt describes exactly the purpose of the method - mapping an object to int, And adding the parseInt is needless because it actually the same - parse an object to int...
But then I tried to pass also Integer:valueOf and it was accepted as well - so I understood that there are couple of options to pass to mapToInt, and that answered my question...
1)mapToInt function's main purpose is to convert current stream to Intstream, over which other Integer operations can be performed like sum,Min,max etc.
It's generics you can never predict what will be the input, in your case it is String, it might be double ,long or Something else.
It has been left to Developers to take care of explicit cast.
You can write your own function, here in this case it is function<T,int> which is nothing but the ToIntFunction taken as an argument of mapToInt func.
You can rewrite your own functional interface like function<String, int> , but here also u need to do parseInt inside of function applyAsInt, but this will be a one time job that you can reuse while making certain other similar calls.

Passing on a Multi-Dimensional Array to another Method in Java

I have numbers[x][y] and int pm2 = 0;. Is there a way to pass on this Mult-Array onto public static boolean checkNumber(int[] list, int num)? <- the parameters has to be used this way.
I invoked checkNumber(numbers[x][y], pm2);
I need to use the checkNumber method to check if a number has already been entered and returns true if the number is present and false if number is absent.
I am allowed to use multiple methods thought so I did have an idea of doing numbers[x][0] , numbers[x][1] etc, etc and invoking them into multiple checkNumber() methods. I was just wondering if there's a shorter way.
You have single dimensional array as parameter.
So you have to pass one at a time probably in loop.
I was just wondering if there's a shorter way.
No there isn't. The Java language doesn't support any kind of array "slicing", and you can't subvert the type system to allow you to refer use an array with a different type to what it really has.
You need to implement your idea of iterating the int[] component array of the int[][], passing each one to checkNumber(int[], int). Something like this:
for (int[] subarray : numbers) {
checkNumbers(subarray, pm2);
}

Categories

Resources