I'm learning Java and stuck on a self test exercise writing a recursive function that prints a string backwards...
I understand the compiler error but I'm not sure what to do about it.
My code...
class Back {
void Backwards(String s) {
if (s.length = 0) {
System.out.println();
return;
}
System.out.print(s.charAt(s.length));
s = s.substring(0, s.length-1);
Backwards(s);
}
}
class RTest {
public static void main(String args[]) {
Back b;
b.Backwards("A STRING");
}
}
Compiler output...
john#fekete:~/javadev$ javac Recur.java
Recur.java:3: error: cannot find symbol
if (s.length = 0) {
^
symbol: variable length
location: variable s of type String
Recur.java:7: error: cannot find symbol
System.out.print(s.charAt(s.length));
^
symbol: variable length
location: variable s of type String
Recur.java:8: error: cannot find symbol
s = s.substring(0, s.length-1);
^
symbol: variable length
location: variable s of type String
3 errors
Finished code...
class Back {
static void backwards(String s) {
if (s.length() == 0) {
System.out.println();
return;
}
System.out.print(s.charAt(s.length()-1));
s = s.substring(0, s.length()-1);
backwards(s);
}
}
class RTest {
public static void main(String args[]) {
Back.backwards("A STRING");
}
}
Write it like this:
s.length() == 0 // it's a method, not an attribute
Some general 'good coding' suggestions:
Class names should represent a 'thing', usually a classname is a noun (e.g. "StringTool")
Methods should represent an action, usually a methodname is a verb (e.g. "reverse")
Parameter and variable names should be meaningful and describe what they represent.
You should not re-assign method parameters because it can be misleading.
A method should have precisely one responsability (so not reversing AND printing a string). This promotes clarity and reuse.
I have applied these suggestions to your finished code, see below:
public class StringTool {
public static String reverse(String source) {
// stop condition of the recursion
if (source.isEmpty()) {
return "";
}
int lastPosition = source.length() - 1;
String lastCharacter = source.charAt(lastPosition);
String restOfSource = source.substring(0, lastPosition);
// place the last character at the beginning and reverse the rest
// of the source recursively
return lastCharacter + reverse(restOfSource);
}
// test method
public static void main(String args[]) {
System.out.println(reverse("A STRING"));
}
}
In your if statement, you are assigning 0 to s.length rather than checking. do it this way:
if(s.length()==0)
//rest of your code
another fault is s.charAt(s.length()). The index of i th character in a string is (i-1), similar to the indices of an array. So the last character of the string has index (s.length()-1). So replace that line of code with s.charAt(s.length()-1).
This should better reflect what you're trying to accomplish:
class Back {
void Backwards(String s) {
if (s.length() == 0) {
System.out.println();
return;
}
System.out.print(s.charAt(s.length()));
s = s.substring(0, s.length()-1);
Backwards(s);
}
}
public class RTest {
public static void main(String args[]) {
Back b = new Back();
b.Backwards("RAPE APE");
}
}
length() is a function
comparison uses ==
You must instantiate b to use it
You forgot the parentheses:
s.length()
length is a method, not an attribute. You'll have to use it that way:
s.length(); // note the use of parens
Also, you'll have a compilation error after fixing that, because of the following condition:
if (s.length = 0) {
It should be
if (s.length == 0) {
And finally, in your main method, the b variable will have to be instantiated, using
Back b = new Back();
- With String we are provided a function named length() and not a field length.
- If you were using an Array then it would had been length as Array has one and only one Instance variable named length.
Eg:
s.length() == 0;
Related
I'm a Java newbie and I have this question.
Can I pass a variable to a method multiple times without creating a new object?
For example, if I have a variable x which is the user input, another variable called m and a method were: if x is "h" then m is "example1" else if x is "f" m is "example2".
If I write:
String x = Scanner.next();
And I create the object passing the x variable, when I write,
System.out.println(obj.m);
If the input was h It will print out "example1"
But if write down this after what i showed up:
x = Scanner.next();
System.out.println(obj.m);
Whatever character I write down the output will be "example 1"
If I type "f" the first time the output will be "example2"
But the second system.out.println() will print "example2" eventually if I typed "h" the second time
So is it possible to pass a variable only one time with a value that changes over time without creating a new object?
If I understand your question correctly, then yes, you can pass a variable to a method multiple times without creating a new object. Let's say you create a class like this:
public class Test {
public String m;
public void testMethod(String x) {
if ("h".equals(x)) {
m = "example1";
} else if ("f".equals(x)) {
m = "example2";
} else {
m = "other";
}
}
}
If you created an object from this class in a main method and pass in different values of x as the argument for testMethod(), the value of m would change:
public class MainClass {
public static void main(String[] args) {
Test obj = new Test();
String x = "h";
obj.testMethod(x);
System.out.println(obj.m); // prints example1
x = "f";
obj.testMethod(x);
System.out.println(obj.m); // prints example2
}
}
As I understood your question, I have added a solution that will create the object you mentioned one time and call the method inside it repeatedly as you enter values. This might help you
import java.util.Scanner;
public class A {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
ClassOfYourObject object = new ClassOfYourObject();
while (true) {
System.out.print("Enter letter : ");
String x = scanner.next();
object.yourMethodToPrint(x);
}
}
}
class ClassOfYourObject {
void yourMethodToPrint(String value) {
if (value.equals("h")) {
System.out.println("example1");
} else if (value.equals("f")) {
System.out.println("example2");
} else {
System.out.println("Invalid letter");
}
}
}
I have a program that takes letters for input and then sums the numeric value of each letter.
I have it so that if I input "abc", my output is "6".
I ignore uppercase letters, so if I input "abC", my output is "3".
What I want to do now, is in a separate class, make a method, which if set to true will run my main program as is, but when it is set to false, it will treat uppercase letters as lowercase, giving an input of "abC", an output of "6".
I hope this makes sense, I've tried a few different things but they all run the programm as is, ignoring uppercase.
Here is my code, I appreciate any constructive feedback.
Thanks
EDIT: I would also appreciate if you didn't downvote me for asking a question, if you don't want to help dont', seems every question I asked gets downvoted for no obvious or fair reason. I didn't want to ask for help since I knew this would happen. We all start have to somewhere!
Main method:
Scanner scan = new Scanner(System.in);
System.out.println("\nPlease enter the letters you would like to use:");
String s, t = "";
scan.next();
s = scan.next();
boolean b = Converter.caseSensitive(false, s);
scan.close();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (!t.isEmpty()) {
t += ",";
}
if (ch >= 'a' && ch <= 'z') {
int n = ch - 'a' + 1;
t += String.valueOf(n);
}
}
Second method in separate class:
public class Converter {
public static boolean caseSensitive(Boolean b, String s) {
for (char c : s.toCharArray()) {
if (Character.isLetter(c) && Character.isLowerCase(c)) {
b = s.equalsIgnoreCase(s);
return false;
}
}
s = s.toLowerCase();
return true;
}
}
I believe your question is "how do I record a static boolean value in a class and then request it from another class?"
public class Configuration {
private static boolean convertToUppercase = true;
public static void setConvertToUppercase(boolean convert) {
convertToUppercase = convert;
}
public static boolean getConvertToUppercase() {
return convertToUppercase;
}
}
This can be used as:
StringConverter.caseSensitive(Configuration.getConvertToUppercase(), input);
Note that most coders (me included) would consider this poor design but explaining why is outside the scope of your question.
There are a lot of other issues with your code. For example your method call above will leave the input string unchanged. But I suggest you ask another question with just the relevant code when you get stuck.
String is immutable in Java. Please read following stackoverflow question for more information about this topic:
String is immutable. What exactly is the meaning?
public static void main(String[] args) throws Exception
{
String test = "abc";
toUpperCase(test);
System.out.println(test);
}
private static void toUpperCase(String test)
{
test = test.toUpperCase();
}
Please note that above code will output:
abc
In order to have "ABC" as result you need to use following code:
public static void main(String[] args) throws Exception
{
String test = "abc";
test = toUpperCase(test);
System.out.println(test);
}
private static String toUpperCase(String test)
{
return test.toUpperCase();
}
This one outputs:
ABC
So your Converter.caseSensitive method should return String.
I don't think you really need the Converter class. You can delete class and replace the line:
boolean b = Converter.caseSensitive(false, s);
with this
boolean shouldCountUppercaseLetters = false;
if (shouldCountUppercaseLetters) {
s = s.toLowerCase();
}
public class MyClass {
public void display(String s) {
final char c = s.charAt(0);
System.out.println(c);
if (s.length() > 1) {
display(s.substring(1));
}
}
public static void main(String[] args) {
MyClass mC = new MyClass();
mC.display("SampleString");
}
}
When I execute the following code how is that I am able to modify the value of final variable c when calling display recursively. Isnt final supposed to restrict the user from doing that
You are not modifying the variable, each call of this method gets a new instance of the variable. If you only want one instance you can move the declaration into the class body and declare it "static".
Variable c is scoped inside its enclosing method. That's why when you call it recursively, each time it is different variable c.
You are not modifying a final variable, you are creating a new stack frame and that creates a new variable c for your method display. Also, your method takes one char from the String each time, and you get a new String. So,
public void display(final String s) { // <-- you *could* make `s` final
if (s == null || s.length() < 1) return;
final char c = s.charAt(0);
System.out.print(c); // <-- why put each char on a new line?
if (s.length() > 1) {
display(s.substring(1)); // <-- recurse.
} else {
System.out.println(); // <-- last char. new line.
}
}
Let me explain further. I have a String function (called stringReversal) that returns a reversed string, it has no errors in the function. But, when I try to print using System.out.println() from the main function, it gives me the error "Can not make a static reference to the non static method stringReversal (string s) from the type StringReverse".
I tried giving my stringReversal a static modifier, but after doing so, it gave me run time errors.
Here's what my code looks like:
public class StringReverse {
public String stringReversal(String s){
if(s == null){
return null;
}
else if(s.length()% 2 == 0){
int size = s.length();
for(int i =0; i<s.length(); i++){
s.replace(s.charAt(i), s.charAt(size));
size--;
if(i == (s.length()/2) || size==0)
break;
}
}
else{
for(int i =0; i<s.length(); i++){
int size = s.length();
s.replace(s.charAt(i), s.charAt(size));
size--;
if(i == ((s.length()/2) +1) || size==0 )
break;
}
}
return s;
}
public static void main(String[] args) {
String str = "Hello";
String rev = stringReversal(str);
System.out.println();
}
}
You have to instantiate your class to call object members, or you need to make your function static, indicating it's not part of object oriented paradigm
In your case you can do
StringReverse sr = new StringReverse();
String rev = sr.stringReversal("hello");
or declare your method differently
public static String stringReversal(String s)
In fact the class name StringReverse itself does not sound like some kind of object, so the second way is preferred impo
The deeper problem you have is the confusion on how Java handle OO and entrance function in general. Java is primarily an OO language so most of the time everything shall be an object or a member of a object. But when you telling the VM to run some java code, there got to be a place to start, which is the main method. There has to be one main method and it must be under some class, but it really has nothing to do with the class that contains it. Within the main method, you either start your OO life by instantiating objects and invoking their members (method 1) or stay in the spaghetti world for a bit longer, by calling other static members as procedures (method 2).
You have two options:
Keep the method non static and then create an instance of your class to call the method:
public static void main(String[] args) {
String str = "Hello";
StringReverse sr = new StringReverse(); // instance of class
String rev = sr.stringReversal(str);
System.out.println(); // just prints a blank line lol...
}
Make the method static (you should do this):
public static String stringReversal(String s) {
// ...
}
public static void main(String[] args) {
String str = "Hello";
String rev = stringReversal(str);
System.out.println(); // just prints a blank line lol...
}
Either way, you have to fix your "run time errors". You can't get around that. If your method doesn't work, keeping it not static won't make it work either.
By the way, I think you meant to do System.out.println(rev); instead of System.out.println();
For the record, here is how to easily reverse a string (both methods work):
public static String stringReversal(String s) {
StringBuffer reverseString = new StringBuffer();
// reverse the string
for (int i = s.length() - 1; i > -1; i--) {
reverseString.append(s.charAt(i));
}
return reverseString.toString();
}
/* using the reverse() method in the StringBuffer class
instead of reversing the string through iterations */
public static String stringReversal2(String s) {
return new StringBuffer(s).reverse().toString();
}
This is happening because your Main method is static, but the class that it's in is not. In order to call a non-static method, you need to create an instance of the class. Alternatively, the method can be made static, but in order to refer to it you need to include the class name in your call (as if to use the class itself like an object containing the method - see below).
There are three solutions to this problem:
Make an instance of the class and call the method from your object (recommended).
make the method static and use StringReverse.stringReversal().
Make the class AND the method static.
I'm following the CS106A lectures online. I'm going through the code on Lecture 12, but it's giving me errors in Eclipse.
This is my code. It seems the error is because of the word void in my main method. I tried deleting the main method, but of course Java can't run without it.
I'm a newbie and no one has explained what the String[] args thing really means, but I've been told to just ignore it and use it. I'd appreciate if someone could explain that to me as well.
This errors also comes up on the 'toLower' method; no idea what it means:
Illegal modifier for parameter toLower; only final is permitted
(if it helps; the point of the code is to convert an uppercase letter to a lowercase one)
public class CS106A {
public static void main(String[] args){
public char toLower(char ch);
if (ch >= 'A' && ch <= 'Z'){
return ((ch - 'A') + 'a');
}
return ch;
}
}
Thanks
You should be defining your method outside of main, like:
public class YourClass
{
public static void main(String... args)
{
}
public char yourMethod()
{
//...
}
}
Java does not support nested methods; however, there are workarounds, but they are not what you're looking for.
As for your question about args, it is simply an array of Strings that correspond to command line arguments. Consider the following:
public static void main(String... args) //alternative to String[] args
{
for (String argument: args)
{
System.out.println(argument);
}
}
Executing via java YourClass Hello, World!
Will print
Hello, Word!
You cannot declare a method (toLower) inside another method (main).
Yes void return type can not return any value.
It will be better if you create a separate function for this process which will return some value and call it from main().
public class Test
{
public static void main(String[] args)
{
String[] a = testMethod();
}
public String[] testMethod()
{
.....
.....
return xx;
}
}
Hope it will help you.
Thanks
You need to declare your method outside of the main
public class YourClass
{
public static void main(String... args)
{
}
public char yourMethod()
{
}
}
the string args bit is so when you run it through command line you can send values (as strings)
>java myprogram var1 var2 ....
Because You have added ; at the end of an method
corrected Code:
public class CS106A {
public static void main(String[] args){
Char char=new CS106A.toLower('s');
System.out.println(char);
}
public char toLower(char ch)
{
if (ch >= 'A' && ch <= 'Z'){
return ((ch - 'A') + 'a');
}
return ch;
}
}
Please Read how to write Methods in java on any java website
You can't have nested method in java.
toLower() method is inside main().
separately use both method. void means there isn't any return from those method.
You can try as follows
public static void main(String[] args){
char output=new CS106A().toLower('a'); // calling toLower() and take the
// return value to output
}
public char toLower(char ch){
if (ch >= 'A' && ch <= 'Z'){
return ((ch - 'A') + 'a');
}
return ch;
}
nested method defining is not allowed in java .You have defined your method toLower() inside main method
You cannot have such nested methods in Java. CS106A is a class. main() and toLower() are two methods of it. Write them separately.
As for String[] args in the main() method argument it is similar to saying int arc, char **argv in C if you have learned it before. So basically args is an array where all the command line arguments go.
public class CS106A
{
public static char toLower(char ch)
{
if (ch >= 'A' && ch <= 'Z')
{
return ((ch - 'A') + 'a');
}
return ch;
}
public static void main(String[] args)
{
System.Out.Println(toLower('A'));
}
}
Hope this will help you.
string[] args in main method is used to follow the prototype defined by the technology. If you dont used it then JVM will considered it as a simple method. Also as this is prototype then remember technology used 0 byte of an array. for ex:
class MainDemo{
public static void main(){
System.out.println("I am main method without arg");
}
public static void main(String[] args){
main(); //As method is static so no need to create an object
System.out.println("MainDemo");
}
}
O/p for above will give:
I am main method without arg
MainDemo
Regarding your code, you cannot define/declare any method inside main method. Use it outside main method but within class.