I'm learning how to use stream, and I get a problem with this method.
public static String[] inArray(String[] array1, String[] array2) {
return Arrays.stream(array1)
.filter(str -> Arrays.stream(array2).anyMatch(s -> s.contains(str)))
.distinct().sorted().toArray(**String[]::new**);
}
I'm so confused about String[]::new, could you give me a hint?
String[]::new means size -> new String[size].
When Stream#toArray(IntFunction<A[]> generator) is ready to produce an array, it calls generator and passes (generator.apply) the size of the inner collection to get a collection to fill it up.
I would say the existing answers provide some insight but none of them yet talk about IntFunction<R>.
To add to them explain, what it means in the context of Stream.toArray(String[]::new) is that it represents an IntFunction implementation such as :
new IntFunction<String[]>() {
#Override
public String[] apply(int value) {
return new String[value];
}
}
where the code creates a newly allocated String[] of size value and produces the array of that size as an output.
You are right to be confused, because Java isn't really super clear about types vs. classes.
We know that String[] is a type, as you can declare variables of that type:
jshell> String[] s = new String[]{"Hello", "world"}
s ==> String[2] { "Hello", "world" }
However, String[] actually is treated as a class in Java and not just a type:
jshell> s.getClass()
$2 ==> class [Ljava.lang.String;
That funny looking [Ljava.lang.String, representing the type "array of string" shows up in response to the getClass invocation. I agree that it is surprising. But every object in Java has to have a class, and String[] is that class. (In other languages, you might see something like Array<String> which might be a dash clearer. But then Java has type erasure so again, things look a little confusing.)
In your particular case, here's what's going on. You need to be careful with types when making arrays from streams. Naively, you might get:
jshell> Arrays.asList("a", "b").stream().toArray()
$5 ==> Object[2] { "a", "b" }
So we want the version of toArray that gives us an array:
jshell> Arrays.asList("a", "b").stream().toArray((n) -> new String[n])
$7 ==> String[2] { "a", "b" }
That's better! The result type is an array of strings, instead of just an array of obejcts. Now the (n)->new String[n] can be replaced with a method reference for construction. Java allows array types in method references! So we can write:
jshell> Arrays.asList("a", "b").stream().toArray(String[]::new)
$8 ==> String[2] { "a", "b" }
Aside: There are some caveats when using array types in method references like this, such as the requirement that the array type must be reifiable, but I think that's a little beyond what you might have been asking. The TL;DR here is that, by design, Java allows array types in (constructor-like) method references with ::new.
This is a method reference expression see JLS 15.13. The syntax for method references is:
MethodReference:
ExpressionName :: [TypeArguments] Identifier
Primary :: [TypeArguments] Identifier
ReferenceType :: [TypeArguments] Identifier
super :: [TypeArguments] Identifier
TypeName . super :: [TypeArguments] Identifier
ClassType :: [TypeArguments] new
ArrayType :: new
The particular case you are looking at is the last one. In your example, String[] is an ArrayType which means that it consists of a type name followed by one or more [].
There shouldn't be a class named String[] which is very lame and I could not interpret what it is actually meant for.
See above: it is a type specification not a class name. From a syntactic / linguistic perspective, this usage is analogous to:
Class<?> c = String[].class;
or
if (a instanceof String[])
or even
public void myMethod(String[] arg)
(You wouldn't call those "lame" ... would you?)
Now you could have a valid case for saying that it is syntactically unexpected (especially to a pre-Java 8 programmer) to be able to use the new keyword like this. But this unexpected syntax is a consequence of the strong imperative that the designers have to NOT break backwards compatibility when adding new language features to Java. And it is not unintuitive. (At least, I don't think so. When I first saw this construct, is was obvious to me what it meant.)
Now, if they were starting with a clean slate in 2018, a lot of details of the Java language design would be simpler and cleaner. But they don't have the luxury of doing that.
The documentation of Stream#toArray says it exactly:
The generator function takes an integer, which is the size of the desired array, and produces an array of the desired size.
for example:
IntFunction<int[]> factory = int[]::new;
// v--- once `apply(3)` is invoked,it delegates to `new int[3]`
int [] array = factory.apply(3);
// ^--- [0, 0, 0] create an int array with size 3
String[]::new is a method reference expression and it must be assigned/casted to a certain functional interface type at compile time:
A method reference expression is used to refer to the invocation of a method without actually performing the invocation. Certain forms of method reference expression also allow class instance creation (§15.9) or array creation (§15.10) to be treated as if it were a method invocation.
A method reference expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived from T.
Edit
As #Eugene mentioned in comments below. It's necessary to let you know how and where the stream create an fixed size array to collecting all elements.
The following table is showing the stream how to calculates the array size:
sequential stream - AbstractSpinedBuffer#count
parallel stream
stateless OPs with known/fixed size Spliterator - AbstractConcNode#AbstractConcNode
stateful OPs
fixed size Spliterator - Spliterator#estimateSize
unknown size Spliterator - AbstractConcNode#AbstractConcNode
The following table is showing the stream where to creates a fixed size array by array generator IntFunction:
sequential stream
stateful/stateless OPs with unknown/fixed size Spliterator - SpinedBuffer#asArray
parallel stream
stateless OPs with known/fixed size Spliterator - Nodes#flatten
stateful OPs
fixed size Spliterator - Nodes#collect
unknown size Spliterator - Nodes#flatten
String[]::new
This is lambda for the following method:
public String[] create(int size) {
return new String[size];
}
Your whole stream operation is terminating converting that into an array, that is what you do with the last method toArray(), but an array of what?....
of Strings ( thus String[]::new)
The parameter of toArray(...) is a Functional Interface (namely IntFunction<R> and then String[]::new is defined as the Method Reference or in that case constructor to use that generates an array of the desired type.
See https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html
And https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
Adding to the answer of Andrew Tobilko:
"String[]::new means size -> new String[size]"
which, since toArray takes an IntFunction, is similar to:
IntFunction<String[]> generator = new IntFunction<String[]>() {
#Override
public String[] apply(int size) {
return new String[size];
}
};
To convert your stream to another List, you can use:
.collect(Collectors.toList());
Related
I’m storing references to BiConsumers<Integer, X> adapted to Consumer<Integer>:
public void setConsumer(BiConsumer<Integer, X> consumer) {
fieldConsumer = integer -> consumer.accept(integer, fieldSubject);
}
But I need 2 of them, so I changed the code to use an array:
private Consumer<Integer>[] fieldConsumers;
public MyClass(int numberOfConsumers) {
Consumer<Integer> consumer = integer -> {};
fieldConsumers= (Consumer<Integer>[]) Array.newInstance(consumer.getClass(), numberOfObservers);
}
public void addConsumer(int consumerIndex, BiConsumer<Integer, X> consumer) {
// Offending line
fieldConsumers[consumerIndex] = responseType-> consumer.accept(responseType, fieldSubject);
}
So that the callback can be triggered with a:
for (Consumer<Integer> consumer: fieldConsumers) {
consumer.accept(responseType);
}
I got the error:
java.lang.ArrayStoreException:
on this line:
fieldConsumers[consumerIndex] = responseType-> consumer.accept(responseType, fieldSubject);
Now, If you are still reading this, I have one more question:
Am I still holding reference to outside Consumers if I do it this way, as opposed to using the old fieldConsumers.add(consumer) where fieldConsumers is a List<BiConsumer<Integer, X>> ?
You used Array.newInstance(consumer.getClass(), numberOfObservers) to create the Consumer<Integer>[] array. But consumer.getClass() returns the actual class of the object you’re invoking the method on, which is always an implementation class of the interface. An array of this element type can only hold objects of the same concrete class, not arbitrary implementations of the interface.
This is not different to, e.g.
CharSequence cs = "hello";
CharSequence[] array = (CharSequence[]) Array.newInstance(cs.getClass(), 1);
array[0] = new StringBuilder();
Here, cs has the type CharSequence and the reflective array creation appears to create an array of type CharSequence[], so storing a StringBuilder should be possible. But since cs.getClass() returns the actual implementation class String, the array is actually of type String[], hence, the attempt to store a StringBuilder produces an ArrayStoreException.
In case of lambda expressions, things get slightly more complicated, as the actual implementation classes of the functional interface are provided at runtime and intentionally unspecified. You used the lambda expression integer -> {} for the array creation in the constructor, which evaluated to a different implementation class than the responseType-> consumer.accept(responseType, fieldSubject) within the addConsumer method, in this particular runtime.
This behavior is in line with this answer describing the behavior of the most commonly used environment. Still, other implementations could exhibit different behavior, e.g. evaluate to the same implementation class for a particular functional interface for all lambda expressions. But it’s also possible that multiple evaluations of the same lambda expression produce different classes.
So the fix is to use the intended interface element type, e.g.
fieldConsumers=(Consumer<Integer>[])Array.newInstance(Consumer.class, numberOfObservers);
But there is no need for a reflective array creation at all. You can use:
fieldConsumers = new Consumer[numberOfObservers];
You can not write new Consumer<Integer>[numberOfObservers], as generic array creation is not allowed. That’s why the code above uses a raw type. Using Reflection instead wouldn’t improve the situation, as it is an unchecked operation in either case. You might have to add #SuppressWarnings for it. The cleaner alternative is to use a List<Consumer<Integer>>, as it shields you from the oddities of arrays and generics.
It’s not clear what you mean with “reference to outside Consumers” here. In either case, you have references to Consumer implementations capturing references to BiConsumer implementations you received as arguments to addConsumer.
I want to replace lambda expression by method reference in the below example :
public class Example {
public static void main(String[] args) {
List<String> words = Arrays.asList("toto.", "titi.", "other");
//lambda expression in the filter (predicate)
words.stream().filter(s -> s.endsWith(".")).forEach(System.out::println);
}
}
I want to write a something like this :
words.stream().filter(s::endsWith(".")).forEach(System.out::println);
is it possible to transform any lambda expression to method reference.
There is no way “to transform any lambda expression to method reference”, but you can implement a factory for a particular target type, if this serves recurring needs:
public static <A,B> Predicate<A> bind2nd(BiPredicate<A,B> p, B b) {
return a -> p.test(a, b);
}
with this, you can write
words.stream().filter(bind2nd(String::endsWith, ".")).forEach(System.out::println);
but actually, there’s no advantage. Technically, a lambda expression does exactly what you want, there’s the minimum necessary argument transformation code, expressed as the lambda expression’s body, compiled into a synthetic method and a method reference to that synthetic code. The syntax
s -> s.endsWith(".") also is already the smallest syntax possible to express that intent. I doubt that you can find a smaller construct that would still be compatible with the rest of the Java programming language.
You can use selectWith() from Eclipse Collections. selectWith() takes a Predicate2 which takes 2 parameters instead of a Predicate. The second parameter to selectWith() gets passed as the second parameter to the Predicate2 every time it's called, once per item in the iterable.
MutableList<String> words = Lists.mutable.with("toto.", "titi.", "other");
words.selectWith(String::endsWith, ".").each(System.out::println);
By default Eclipse Collections is eager, if you want to iterate lazily then you can use asLazy()
words.asLazy().selectWith(String::endsWith, ".").each(System.out::println);
If you can't change from List:
List<String> words = Arrays.asList("toto.", "titi.", "other");
ListAdapter.adapt(words).selectWith(String::endsWith, ".").each(System.out::println);
Eclipse Collections' RichIterable has several other *With methods which work well with method references, including rejectWith(), partitionWith(), detechWith(), anySatisfyWith(), allSatisfyWith(), noneSatisfyWith(), collectWith()
Note: I am a contributor to Eclipse Collections.
Why is it that, if you have, let's say, these functions:
void func1(Object o){
//some code
}
void func1(Object[] o){
//some code
}
You can call, for example:
func1("ABC");
but not :
func1({"ABC", "DEF"}); // instead having to write:
func1(new Object[]{"ABC", "DEF"});
Question: Is there any special reason why the constructor needs to be called on arrays ?
The "array initialiser" is only available for declarations / assignments:
Object[] o = { 1, 2 };
Or for "array creation expressions":
new Object[] { 1, 2 };
Not for method calls:
// Doesn't work:
func1({1, 2});
It's the way it is... You can read about it in the JLS, chapter 10.6. Array Initializers. An extract:
An array initializer may be specified in a declaration (§8.3, §9.3, §14.4), or as part of an array creation expression (§15.10), to create an array and provide some initial values.
Apart from it not being defined in the JLS right now, there seems to be no reason why a future Java version wouldn't allow array initialisers / array literals to be used in other contexts. The array type could be inferred from the context in which an array literal is used, or from the contained variable initialisers
Of course, you could declare func1 to have a varargs argument. But then you should be careful about overloading it, as this can cause some confusion at the call-site
There was a suggestion that Java SE 5.0 was going to have an array literal notation. Unfortunately, we got varargs instead, with all the fun that goes with that.
So to answer the question of why, the language is just like that. You may see list literals in a later version of Java.
You are trying to perform inline array initialization which Java doesn't really support yet.
I suppose you could achieve the desired result using varargs if you so wished, but if you need to pass in an array to a method, you have to initialise it the way Java likes an array to be initialised.
When you call func1("ABC") an object of type String with value"ABC" is created automatically by java.For creating any other object other than of type String you need to used the new operator.
We declare String array like-
String[] a={"A"};
But when a method has String array as argument, why can't we call the method like-
mymethod({"A"});
Code-
class A{
static void m1(String[] a) { }
public static void main(String args[]){
m1(new String []{});//OK
m1({}); //Error
}
}
You can, although your syntax is a bit off.
mymethod(new String[]{"A"});
That's just the way the language is specified. From section 10.6 of the JLS:
An array initializer may be specified in a declaration (§8.3, §9.3, §14.4), or as part of an array creation expression (§15.10), to create an array and provide some initial values.
So you've seen it working in a declaration, and an array creation expression is the form which includes new ArrayElementType at the start:
myMethod(new String[] {"A"});
Bear in mind that when it's part of a declaration, there's only one possible element type involved. For method invocations, it's trickier - there could be multiple overloaded methods, etc. Basically, you'd need to make the expression {"A"} evaluate as a string array on its own, before participating in overload resolution.
For a bit of comparison, the same is true in C#, although C# 3 introduced implicitly typed arrays where the element type is inferred from the values, so you'd be able to write:
// C# 3
MyMethod(new[] {"A"});
You still need the new[] part though.
You can't pass an array like that. Declare it as a variable, then pass the variable to the method instead.
I don't understand that syntax. Trying to google various words plus "..." is useless.
It's called varargs. This fact should yield better Google results.
This is called Variadic function (wiki page with examples in many languges).
In computer programming, a variadic
function is a function of indefinite
arity, i.e. one which accepts a
variable number of arguments. Support
for variadic functions differs widely
among programming languages. There are
many mathematical and logical
operations that come across naturally
as variadic functions. For instance,
the summing of numbers or the
concatenation of strings or other
sequences are operations that can
logically apply to any number of
operands. Another operation that has
been implemented as a variadic
function in many languages is output
formatting. The C function printf and
the Common Lisp function format are
two such examples. Both take one
argument that specifies the formatting
of the output, and any number of
arguments that provide the values to
be formatted. Variadic functions can
expose type-safety problems in some
languages. For instance, C's printf,
if used incautiously, can give rise to
a class of security holes known as
format string attacks. The attack is
possible because the language support
for variadic functions is not
type-safe; it permits the function to
attempt to pop more arguments off the
stack than were placed there --
corrupting the stack and leading to
unexpected behavior. Variadic
functionality can be considered
complementary to the apply function,
which takes a function and a
list/sequence/array as arguments and
then calls the function once, with the
arguments being the elements of the
list.
One of may personal favorite not used features in Java. It is basically a reference array that is built from elements. One of the best ways to use it is on class constructor, or method where you need to constantly find a value like maximum of 2, 3, 4, 5 input elements.
One example is, when i built a generic binary tree node, for coding tasks, I used this in constructor. This enabled me simply add elements to the tree and distribute them.
Following creates String type binary tree, with root "Red" and 2 branches "Blue" and "Green".
new MBTN<String>("Red", "Blue", "Green").
Could you think what the alternatives would be :D You can't even simply make generic array of elements, so this would stretch like hell. It is definitely not useless.
They are the "variable arguments" or varargs (for short).
Basically it allows the passing of an unspecified number of Strings, so the method signature
public void printStuff(String...messages)
Effectively can handle the following calls
printStuff("hi");
printStuff("hi", "bye");
printStuff("Hello", "How are you?", "I'm doing fine.", "See you later");
You can effectively consider this a type of autoboxing. The printStuff argument can be seen as an array, so printStuff(String...messages) is conceptually handled like printStuff(String[] messages). Wtih the calls above effectively acting like
printStuff(new String[] {"hi"});
printStuff(new String[] {"hi", "bye"});
printStuff(new String[] {"Hello", "How are you?", "I'm doing fine.", "See you later"});
To access the messages internally, you use typical List handling primitives. Something like
...
if (messages != null) {
for (String message : messages) {
System.out.println(message);
}
}
...
That there is no need to actually create arrays is a bit of syntactic sugar added to Java with the advent of auto boxing.
As #BalusC mentioned, it's a varags parameter. This means you can pass a variable number of arguments to that method.
So for a method defined as
public void foo(String...strings) { }
The following invocations are legal:
foo();
foo("one param");
foo("one", "two", "three");
They are variable length parameters.
Here is one link with an example.
As mentioned by everyone...variable arguments (or varargs) allows you to do this....
//Method we're using for varargs
public void doSomething(String... datas) {
if (datas == null || datas.length == 0) {
System.out.println("We got nothing");
} else {
for (String data: datas) {
System.out.println(data);
}
}
}
Therefore, all these calls mentioned below are valid....
String d[] = {"1", "2", "3"};
doSomething(d); //An array of String, as long as the type is exactly as the varargs type.
//OR
doSomething("1", "2", "3", "4"); //I can add "infinitely" many arguments as the JVM can allocate me....
//OR
doSomething("1"); //Exactly 1;
Internally varargs is "essentially" a reference array of it's declared type.
It's a java method that took an arbitrary variable number of parameters
It means "Arbitrary number of arguments" meaning you can pass a unknown number of parameters into the method..
see
http://download.oracle.com/javase/tutorial/java/javaOO/arguments.html
Look for the "Arbitrary number of arguments" section
public Polygon polygonFrom(Point... corners) {
int numberOfSides = corners.length;
double squareOfSide1, lengthOfSide1;
squareOfSide1 = (corners[1].x - corners[0].x)*(corners[1].x - corners[0].x)
+ (corners[1].y - corners[0].y)*(corners[1].y - corners[0].y) ;
lengthOfSide1 = Math.sqrt(squareOfSide1);
// more method body code follows that creates
// and returns a polygon connecting the Points
}