Compilation error while using Method reference in Java 8 - java

I am not understanding the reason, for having the compilation error for the below program. Where am I going wrong? I want to print the value of the string as output using method reference.
public class ConsumerDemo{
public static void main(String[] args) {
test("hello", (str)-> str::toUpperCase);
}
public static void test(String str, Consumer<String> consumer) {
consumer.accept(str);
}
}

test("hello", String::toUpperCase)
should be the correct syntax.
In order to print the upper case of the input, you can use:
String str = "hello"; // any input value
test(str.toUpperCase(), System.out::println);

you cannot combine lambda syntax and method reference syntax as such.
You're either looking for:
test("hello", String::toUpperCase);
or:
test("hello", s -> s.toUpperCase());
but this then means the result of String::toUpperCase/s -> s.toUpperCase() is ignored hence, you'll need to perform something more useful. for example:
test("hello", s -> System.out.println(s.toUpperCase()));

Related

Difference between two implementation with lambda expression and simple method form?

Two bellow snippets with the same output, one with using Functional interface and lambda expression, while the other snippet uses two simple method and easy to understand. What are the benefits first snippet code while it increases complexity.
First:
interface StringFunction {
String run(String str);
}
public class Main {
public static void main(String[] args) {
StringFunction exclaim = (s) -> s + "!";
StringFunction ask = (s) -> s + "?";
printFormatted("Hello", exclaim);
printFormatted("Hello", ask);
}
public static void printFormatted(String str, StringFunction format) {
String result = format.run(str);
System.out.println(result);
}
}
Second:
public class Main {
public static void main(String[] args) {
System.out.println(exclaim("Hello"));
System.out.println(ask("Hello"));
}
static String exclaim(String s) {
return s + "!";
}
static String ask(String s) {
return s + "?";
}
}
In the first example, you are passing a behaviour which you can change for every call in a much cleaner and succinct way than your second way e.g.
StringFunction exclaim = s -> s + "!";
printFormatted("Hello", exclaim);
exclaim = s -> s + "!!!";
printFormatted("Hello", exclaim);
If you have to do it in your second way, you will have to write another method for it.
On a side note, in your lambda expression, you do not need the parenthesis in case of a single parameter i.e. you can write it simply as (I've already done this way in the code above):
StringFunction exclaim = s -> s + "!";
StringFunction ask = s -> s + "?";
Biggest advantage of lambda expressions is they are focused on expression instead of object's state.
That means you specify exactly what you wants without dealing with object you pass
there. This allows you to use any object and get result you are expecting.
After all lambdas are still interfaces defining behavior as any other interfaces and depends on their implementation in concrete class.
Your provided code snippet is missing bigger complexity so lambda seems to be overkill there. But in complex systems it supports better maintainability and get rid of tight coupling

Java consumers ability to accept and return boolean or string

This is a regular Consumer with usage:
public static void main(String[] args){
Consumer<String> consumer = (str) -> {
//stuff
};
consumer.accept(args[0]);
}
Here is what I am attempting to do (make it so consumer returns as boolean)
public static void main(String[] args){
Consumer<String> consumer = (str) -> {
return str.equals("yes"); //type mis-match error because consumer is void not boolean
};
boolean a = consumer.accept(args[0]); //type mis-match error because consumer is void not boolean
}
How can I manipulate consumer to return as a boolean?
Without obviously creating a whole new interface.... (below)
public interface ConsumerB {
boolean accept(String s);
}
For the case in which one wants to pass a String and get a boolean, one can use Predicate<String>. There are similiar functions if one wants to return one of the following primitives:
for int: ToIntFunction<String>,
for long: ToLongFunction<String>, and
for double: ToDoubleFunction<String>.
In line with the rest of the java.util.function- and the java.util.stream package, there are no further To<Primitive>Function interfaces for the primitives byte, short, char and float.
For the case in which one wants to pass a String and get a String, one can use UnaryOperator<String>.
For the general case in which one wants to pass some T and get some R, one can use Function<T, R>.
Whether this, however, improves the readability of the code is another question...
A consumer that returns something is not a consumer anymore. It becomes a Predicate<String>:
Predicate<String> consumer = (str) -> {
return str.equals("yes");
};
You also mentioned in the title that you want the functional interface to return a String. In that case, use Function<String, String>.

Function<String, Consumer<String>> java 8

What does this below lambda function do?
public class FunctionInterface {
public static void main(String[] args) {
Function<String, Consumer<Integer>> secondFunction = s -> x -> System.out.println(x);
System.out.println(secondFunction.apply("Text"));
}
}
The above code is printing some random value, how to make it print text?
Your variable secondFunction is a Function that takes a String and returns a Consumer<Integer>. In this line:
System.out.println(secondFunction.apply("Text"));
you are calling apply on the Function, which will return a Consumer<Integer>, and then you print the object, which will cause toString to be called on the Consumer<Integer> object (and then the string will be printed).
It will not run the lambda expression, which is what you seem to expect. Try this instead:
// Call accept(123) on the consumer, which will execute the lambda
secondFunction.apply("Text").accept(123);
You say you wanted to print "Text" maybe this is easier?
You don't need to return the consumer with a Function. I'm confused what is the purpose?
Consumer<String> consumer = System.out::println;
consumer.accept("Text");

Why does a lambda need to capture the enclosing instance when referencing a final String field?

This is based on this question. Consider this example where a method returns a Consumer based on a lambda expression:
public class TestClass {
public static void main(String[] args) {
MyClass m = new MyClass();
Consumer<String> fn = m.getConsumer();
System.out.println("Just to put a breakpoint");
}
}
class MyClass {
final String foo = "foo";
public Consumer<String> getConsumer() {
return bar -> System.out.println(bar + foo);
}
}
As we know, it's not a good practice to reference a current state inside a lambda when doing functional programming, one reason is that the lambda would capture the enclosing instance, which will not be garbage collected until the lambda itself is out of scope.
However, in this specific scenario related to final strings, it seems the compiler could have just enclosed the constant (final) string foo (from the constant pool) in the returned lambda, instead of enclosing the whole MyClass instance as shown below while debugging (placing the breaking at the System.out.println). Does it have to do with the way lambdas are compiled to a special invokedynamic bytecode?
In your code, bar + foo is really shorthand for bar + this.foo; we're just so used to the shorthand that we forget we are implicitly fetching an instance member. So your lambda is capturing this, not this.foo.
If your question is "could this feature have been implemented differently", the answer is "probably yes"; we could have made the specification/implementation of lambda capture arbitrarily more complicated in the aim of providing incrementally better performance for a variety of special cases, including this one.
Changing the specification so that we captured this.foo instead of this wouldn't change much in the way of performance; it would still be a capturing lambda, which is a much bigger cost consideration than the extra field dereference. So I don't see this as providing a real performance boost.
If the lambda was capturing foo instead of this, you could in some cases get a different result. Consider the following example:
public class TestClass {
public static void main(String[] args) {
MyClass m = new MyClass();
m.consumer.accept("bar2");
}
}
class MyClass {
final String foo;
final Consumer<String> consumer;
public MyClass() {
consumer = getConsumer();
// first call to illustrate the value that would have been captured
consumer.accept("bar1");
foo = "foo";
}
public Consumer<String> getConsumer() {
return bar -> System.out.println(bar + foo);
}
}
Output:
bar1null
bar2foo
If foo was captured by the lambda, it would be captured as null and the second call would print bar2null. However since the MyClass instance is captured, it prints the correct value.
Of course this is ugly code and a bit contrived, but in more complex, real-life code, such an issue could somewhat easily occur.
Note that the only true ugly thing, is that we are forcing a read of the to-be-assigned foo in the constructor, through the consumer. Building the consumer itself is not expected to read foo at that time, so it is still legit to build it before assigning foo – as long as you don't use it immediately.
However the compiler will not let you initialize the same consumer in the constructor before assigning foo – probably for the best :-)
You are right, it technically could do so, because the field in question is final, but it doesn't.
However, if it is a problem that the returned lambda retains the reference to the MyClass instance, then you can easily fix it yourself:
public Consumer<String> getConsumer() {
String f = this.foo;
return bar -> System.out.println(bar + f);
}
Note, that if the field hadn't been final, then your original code would use the actual value at the time the lambda is executed, while the code listed here would use the value as of the time the getConsumer() method is executed.
Note that for any ordinary Java access to a variable being a compile-time constant, the constant value takes place, so, unlike some people claimed, it is immune to initialization order issues.
We can demonstrate this by the following example:
abstract class Base {
Base() {
// bad coding style don't do this in real code
printValues();
}
void printValues() {
System.out.println("var1 read: "+getVar1());
System.out.println("var2 read: "+getVar2());
System.out.println("var1 via lambda: "+supplier1().get());
System.out.println("var2 via lambda: "+supplier2().get());
}
abstract String getVar1();
abstract String getVar2();
abstract Supplier<String> supplier1();
abstract Supplier<String> supplier2();
}
public class ConstantInitialization extends Base {
final String realConstant = "a constant";
final String justFinalVar; { justFinalVar = "a final value"; }
ConstantInitialization() {
System.out.println("after initialization:");
printValues();
}
#Override String getVar1() {
return realConstant;
}
#Override String getVar2() {
return justFinalVar;
}
#Override Supplier<String> supplier1() {
return () -> realConstant;
}
#Override Supplier<String> supplier2() {
return () -> justFinalVar;
}
public static void main(String[] args) {
new ConstantInitialization();
}
}
It prints:
var1 read: a constant
var2 read: null
var1 via lambda: a constant
var2 via lambda: null
after initialization:
var1 read: a constant
var2 read: a final value
var1 via lambda: a constant
var2 via lambda: a final value
So, as you can see, the fact that the write to the realConstant field did not happen yet when the super constructor is executed, no uninitialized value is seen for the true compile-time constant, even when accessing it via lambda expression. Technically, because the field isn’t actually read.
Also, nasty Reflection hacks have no effect on ordinary Java access to compile-time constants, for the same reason. The only way to read such a modified value back, is via Reflection:
public class TestCapture {
static class MyClass {
final String foo = "foo";
private Consumer<String> getFn() {
//final String localFoo = foo;
return bar -> System.out.println("lambda: " + bar + foo);
}
}
public static void main(String[] args) throws ReflectiveOperationException {
final MyClass obj = new MyClass();
Consumer<String> fn = obj.getFn();
// change the final field obj.foo
Field foo=obj.getClass().getDeclaredFields()[0];
foo.setAccessible(true);
foo.set(obj, "bar");
// prove that our lambda expression doesn't read the modified foo
fn.accept("");
// show that it captured obj
Field capturedThis=fn.getClass().getDeclaredFields()[0];
capturedThis.setAccessible(true);
System.out.println("captured obj: "+(obj==capturedThis.get(fn)));
// and obj.foo contains "bar" when actually read
System.out.println("via Reflection: "+foo.get(capturedThis.get(fn)));
// but no ordinary Java access will actually read it
System.out.println("ordinary field access: "+obj.foo);
}
}
It prints:
lambda: foo
captured obj: true
via Reflection: bar
ordinary field access: foo
which shows us two things,
Reflection also has no effect on compile-time constants
The surrounding object has been captured, despite it won’t be used
I’d be happy to find an explanation like, “any access to an instance field requires the lambda expression to capture the instance of that field (even if the field is not actually read)”, but unfortunately I couldn’t find any statement regarding capturing of values or this in the current Java Language Specification, which is a bit frightening:
We got used to the fact that not accessing instance fields in a lambda expression will create an instance which doesn’t have a reference to this, but even that isn’t actually guaranteed by the current specification. It’s important that this omission gets fixed soon…

Can "main" in java return a String?

Is it possible that public static void main(String[] args) in java returns String instead of void? If yes, how?
public static String main(String[] args)
instead of:
public static void main(String[] args)
when I change my code as below:
public static String main(String[] args) throws IOException {
String str = null;
TurkishMorphParser parser = TurkishMorphParser.createWithDefaults();
str = new Stm(parser).parse("bizler");
System.out.println("str = " + str);
String replace = str.replace("[","");
String replace1 = replace.replace("]","");
List<String> result1 = new ArrayList<String>(Arrays.asList(replace1.split(",")));
String result = result1.get(0);
System.out.println("Result = " + result);
return result;
}
I receive this error:
Error: Main method must return a value of type void in class Stm, please define the main method as:
public static void main(String[] args)
In short - no, it can't.
You can always print to stdout from the main method (using System.out.print or System.out.println), but you can't change the return type of main.
The main method's return type must be void, because the java language specification enforces it. See 12.1.4.
For interprocess communication you can either use:
System.in and System.out
Sockets
No you can't... once the main is finished the program is dead.. So you don't have any benefit from that.. What is you purpose? What you are trying to achieve?
You can wrap all in other method that will return String to your main.
public static void main(String[] args) throws IOException {
String result = doSomething();
return result;
}
public static String doSomething() {
String str = null;
TurkishMorphParser parser = TurkishMorphParser.createWithDefaults();
str = new Stm(parser).parse("bizler");
System.out.println("str = " + str);
String replace = str.replace("[","");
String replace1 = replace.replace("]","");
List<String> result1 = new ArrayList<String>(Arrays.asList(replace1.split(",")));
String result = result1.get(0);
System.out.println("Result = " + result);
}
Yes you can but you can't run that class. You will get error
class Test {
public static String main(String[] args) {
return "1";
}
}
You will get error as
Error: Main method must return a value of type void in class Test, please
define the main method as:
public static void main(String[] args)
No. The to be a main() method, it must return nothing (ie be void).
However, you could refactor your code if you need the functionality of your method returning something:
public static void main(String[] args) throws IOException {
myMain(args);
}
public static String myMain(String[] args) throws IOException {
// your method, which can now be called from anywhere in your code
}
This is a very interesting scenario. While in general, we can change any method which is returning void to return anything else without much impact, main method is a special case.
In earlier programming languages, the return from main method was supposed to return exit values to the OS or calling environment.
But in case of Java (where multi-threading concept case into picture), returning a value from main method would not be right, as the main method returns to JVM instead of OS. JVM then finishes other threads e.g. deamon threads (if any) and performs other exit tasks before exit to OS.
Hence allowing main method to return, would have lead to a false expectation with the developers. hence it is not allowed.
Yes, it's definitely possible. That is, you can define a method public static String main(String[] args). It's just like defining any other method.
However, it won't be a main method despite its name, and thus won't be run when executing a program like a main method would. Quoting Java language specification, §12.14:
The method main must be declared public, static, and void.
Emphasis mine. You can't have non-void main methods in Java.
If you really, really need it to return something (which you don't), assign the output to a static variable. Then you won't need to return. i.e
static String a = "";
public static void main(String[] args){
//do sth
a = "whatever you want";
}
Now you have String a, use it whereever you want to use but I don't see any usage for this.
Answer is no.
When the program is run, the JVM looks for a method named main() which takes an array of Strings as input and returns nothing (i.e. the return type is void). But if it doesn't find such a method ( the main() method is returning String for example ) so it throws a java.lang.NoSuchMethodError
Before java, in C or C++, main function could be declared int or void. Why? Because main method is invoked by OS which is not responsible for the successful/unsuccessful execution of program. So, to let the OS know that the program executed successfully we provide a return value.
Now, in java, program is loaded by OS, but the execution is done by JRE. JRE itself is responsible for the successful execution of program. So, no need to change the return type.
It will be like telling your problems to god, when god himself is giving you problems to solve them.
;)

Categories