Would some one be able to help me please?
If I have a class like this
public class a {
public String b (String c){
String d = "e";
return d;
}
}
When I call a f = new a();
f.b();
I'm unable to have the string d returned. I get the error "cannot be applied to ()"
I'm sure I'm doing something stupid but I cant work it out.
You have
public String b (String c){
but call b() without any parameter. That's what the error wants to tell you...
method b takes a parameter. so try
f.b("some string c");
Your method b requires a String to be passed into it.
When you call f.b() it looks for a method with a signature similar to
public String b(){
// your code
}
You have to call like
f.b(aStringVariable);
or
f.b("Some String");
You have to pass the variable while calling the function.
Add ... to your method parameter declaration. This will make String parameter optional.
public String b (String... c){
String d = "e";
return d;
}
and then new a().b().
When you call f.b() you're not passing a string to the method. You declared your function as public String b(String c). That means you have to pass a string when you call f.b.
If you change you declaration to public String b() you do not have to pass a string.
Another solution is simply passing a string, i.e f.b("a string").
You are passing String c into your b method
public String b (String c)
you are getting that error because there needs to be a string variable like
a f = new a(); f.b(c);
Where c is some predefined string.
Use some string parameter and it will work: f.b("String")
Related
I read few stack overflow responses of questions similar to this but could not get satisfying answer. I want to create a generic method which accepts a graph object of type E. I want to pass this object alongwith a class name. In that method, I want to read an input from user and check if that is an instance of given class and throw some error message if it is not. I tried to use following code for the same:
public void readDependencyPair(Scanner scanner, String prompt, MyGraph<E> graph, String clazz) {
System.out.println(prompt);
Object obj = scanner.next();
Class<?> c = Class.forName(clazz);
if(obj instanceof c) {...
}
}
The above code gives error at line "if obj is instance of c" saying "c cannot be resolved to a type. Create class 'c' or interface 'c' or enum 'c'".
I even tried to pass Class clazz instead of String parameter. And it still shows the same error that 'clazz' cannot be resolved to a type.
You can use
if (c.isInstance(obj))
....
see the docs here
You can use Class for parameter type, for example, to declare a function like:
public boolean isInstance(Class<?> c,Object obj){
return obj.getClass().equals( c);
}
Then use it in this way:
#Test
public void testIsInstance(){
User u = new User();
Assert.assertTrue(isInstance( User.class, u));
}
There's already an existing method for what you're trying to do, Class#isAssignableFrom:
public void readDependencyPair(Scanner scanner, String prompt, MyGraph<E> graph, String clazz) {
System.out.println(prompt);
String obj = scanner.next();
Class<?> c = Class.forName(clazz);
if(Class.forName(obj).isAssignableFrom(c)) {
...
}
}
I'm struggling to see why the following code compiles:
public class MethodRefs {
public static void main(String[] args) {
Function<MethodRefs, String> f;
f = MethodRefs::getValueStatic;
f = MethodRefs::getValue;
}
public static String getValueStatic(MethodRefs smt) {
return smt.getValue();
}
public String getValue() {
return "4";
}
}
I can see why the first assignment is valid - getValueStatic obviously matches the specified Function type (it accepts a MethodRefs object and returns a String), but the second one baffles me - the getValue method accepts no arguments, so why is it still valid to assign it to f?
The second one
f = MethodRefs::getValue;
is the same as
f = (MethodRefs m) -> m.getValue();
For non-static methods there is always an implicit argument which is represented as this in the callee.
NOTE: The implementation is slightly different at the byte code level but it does the same thing.
Lets flesh it out a bit:
import java.util.function.Function;
public class MethodRefs {
public static void main(String[] args) {
Function<MethodRefs, String> f;
final MethodRefs ref = new MethodRefs();
f = MethodRefs::getValueStatic;
f.apply(ref);
//is equivalent to
MethodRefs.getValueStatic(ref);
f = MethodRefs::getValue;
f.apply(ref);
//is now equivalent to
ref.getValue();
}
public static String getValueStatic(MethodRefs smt) {
return smt.getValue();
}
public String getValue() {
return "4";
}
}
A non-static method essentially takes its this reference as a special kind of argument. Normally that argument is written in a special way (before the method name, instead of within the parentheses after it), but the concept is the same. The getValue method takes a MethodRefs object (its this) and returns a string, so it's compatible with the Function<MethodRefs, String> interface.
In the Java Tutorial it is explained that there are 4 different types of method references:
reference to a static method
reference to an instance method of a particular object
reference to an instance method of an arbitrary object of a particular type
reference to a constructor
Your case is #3, meaning that when you have an instance of MethodRef i.e. ref, calling apply on your function f will be equivalent to String s = ref.getValue().
For non-static methods, the type of this is considered implicitly to be the first argument type. Since it's of type MethodRefs, the types check out.
public class Main {
interface Capitalizer {
public String capitalize(String name);
}
public String toUpperCase() {
return "ALLCAPS";
}
public static void main(String[] args) {
Capitalizer c = String::toUpperCase; //This works
c = Main::toUpperCase; //Compile error
}
}
Both are instance methods with same signature. Why does one work and the other doesn't?
Signature of String::toUpperCase: String toUpperCase();
There are 3 constructs to reference a method:
object::instanceMethod
Class::staticMethod
Class::instanceMethod
The line:
Capitalizer c = String::toUpperCase; //This works
use 3'rd construct - Class::instanceMethod. In this case first parameter becomes the target of the method. This construct is equivalent (translates) to following Lambda:
Capitalizer = (String x) -> x.toUpperCase();
This Lambda expression works because Lambda gets String as parameter and returns String result - as required by Capitalizer interface.
The line:
c = Main::toUpperCase; //Compile error
Translates to:
(Main m) -> m.toUpperCase();
Which does not work with the Capitalizer interface. You could verify this by changing Capitalizer to:
interface Capitalizer {
public String capitalize(Main name);
}
After this change Main::toUpperCase will compile.
You have a method which
public String capitalize(String name);
Takes a String and returns a String. Such a method can have a number of patterns.
A constructor
c = String::new; // calls new String(String)
// or
c = s -> new String(s);
A function on String which takes no arguments
c = String::toLowerCase; // instance method String::toLowerCase()
// or
c = s -> s.toLowerCase();
of a method which takes a String as the only argument
// method which takes a String, but not a Main
public static String toUpperCase(String str) {
c = Main::toUpperCase;
// or
c = s -> toUpperCase(s);
In every case, the method referenced has to take the String.
If not you can do this instead.
c = s -> capitalize(); // assuming Main.capitalize() is static
This tells the compiler to ignore the input.
You should change:
public String toUpperCase()
to
public static String toUpperCase(String text)
You should read the java tutorial on method references. The different kind of method references and there is a similar example with String::compareToIgnoreCase (Reference to an Instance Method of an Arbitrary Object of a Particular Type).
The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example. The method reference would invoke the method a.compareToIgnoreCase(b).
I'd simply like to know if the following is possible to do somehow.
public void foo(int a) {
String a = Integer.toString(a);
}
Now obviously this code doesn't actually work; the string a shadows the parameter a. What I'd like to know is, is there a way to explicitly tell the compiler "Hey, this is actually that other a up there!" I'm looking for something similar to the this keyword, except for method parameters.
Is there anything like this or am I forced to use a different variable name?
No, this feature does not exist in java. You should just make up another variable name.
You can do-
String ab = Integer.toString(a);
Even if you could use the same variable name as the parameter variable, it would create confusion. You cannot do that in Java. Just use some other variable name.
Also, modifying method parameters are not a good idea. Rather, have them declared final like-
public void foo(final int a) {
String ab = Integer.toString(a);
}
You can't do that but you could overload the method
public void foo(int a) {
foo(Integer.toString(a));
}
public void foo(String a) {
//
}
For what you want to do, you should probably just create another variable. For example:
public void foo(int a1) {
String a = Integer.toString(a1);
}
You cannot have twice the same name of the variable in the same range. But you can override names of the variables, fields for example:
class A
{
int a;
void f(int a)
{
this.a = a;
}
}
Now field a is overridden, and using this you can refer to the overriden field.
Hi Im studying for my scja exam and have a question about string passing by ref/value and how they are immutable. The following code outputs "abc abcfg".
What I want to know is why is this happening? Im not understanding what happens inside of method f. String is passed by value so surely it should change to "abcde" inside the method? Because if b+="fg" appends to the string why doesnt it work inside the method?
Thanks!
public class Test {
public static void main(String[] args){
String a =new String("abc");
String b = a;
f(b);
b+="fg"
System.out.println(a + " " + b);
}
public static void f(String b){
b+="de";
b=null;
}
}
The line b+="de"; in the void f(String b) functions creates a completely new object of String that does not affect the object in the main function.
So when we say String is immutable when mean any change on a String object will result in creating a completely new String object
public class Test {
public static void main(String[] args){
String a =new String("abc");
String b = a; // both a & b points to the same memory address
f(b); // has no effect
// b still has the value of "abc"
b+="fg" // a new String object that points to different location than "a"
System.out.println(a + " " + b); // should print "abc abcfg"
}
public static void f(String b){
b+="de"; // creates a new object that does not affect "b" variable in main
b=null;
}
}
In your method f() you are assigning a new String to the parameter b, but parameters are just like local variables, so assigning something to them has no effect on anything outside the method. That's why the string you passed in is unchanged after the method call.
This line of code:
b += "de";
Roughly translates to:
b = b + "de";
Which creates a new String and stores it in the local variable 'b'. The reference outside the method is not changed in anyway by this. There are a couple of key things to remember when trying to understand how/why this works this way.
In Java, all method arguments are passed by value.
Methods have a local stack where all their data is stored, including the method arguments.
When you assign a new object to a variable that was passed into a method, you are only replacing the address in the local stack, with the address of the new object created. The actual object address outside of the method remains the same.
When you pass the String into the method, it creates a new String object in the method. If you put a println statement in your method, like this:
public static void f(String b){
b+="de";
System.out.println(b);
b=null;
}
You would see the output "abcde".
However, once you come out of the method, you go back to your original object, which has not been altered. Therefore, appending fg to it will only produce a NEW string (b), containing "abcfg".
Your creating a new object of String when you say something like b+="de"
Its like saying b = new String(b+"de");
If you really want to keep the value passed in then use a stringBuilder like this:
StringBuilder a =new StringBuilder("abc");
StringBuilder b = a;
f(b);
b.append("fg");
System.out.println(a + " " + b);
}
public static void f(StringBuilder b){
b.append("de");
b=null;
}
Now your output will be "abcdefg" because stringbuilder object b was passed into f as the value of the object itself. I modified the value without using "new" to point to another object. Hope its clear now.