Hi so I'm relatively new at Java, I have about 2 months of experience, so please try to answer my question using terms and code relevant to my learning level.
So, I have to make a program for school that makes a letter, fitting the following format:
Dear recipient name:
blank line
first line of the body
second line of the body
. . .
last line of the body
blank line
Sincerely,
blank line
sender name
my code looks like this:
private String body;
private String letter;
public Letter(String from, String to)
{
letter = ("Dear " + to + ":" + "\n" + "\n" + body + "\n" + "Sincerely," + "\n" + "\n" + from);
body = "";
}
public void addLine(String line)
{
body = body + line + "\n";
}
public String getText()
{
return letter;
}
Ive tried several different ways to get this program done, and the one that yields the best results is this one.. The thing is, we're only supposed to use two instance fields max. It seems that it's null because body isn't given a value in my constructor. There's also a program tester class that looks like this:
public class LetterTester
{
public static void main(String [] args)
{
Letter tyler = new Letter("Mary", "John");
tyler.addLine("I am sorry we must part.");
tyler.addLine("I wish you all the best.");
System.out.println(tyler.getText());
}
}
i skipped all the default stuff and some braces and theres no syntax errors, but when i run the tester class, I get:
Dear John:
null
Sincerely,
Mary
What am I doing wrong, and can someone please give a solution as to how to get rid of null? Keep in mind I can only use two instance fields, thanks.
body is null because that is the default value for reference fields. You could initialize it to empty string body = "" instead. That would work with your addLine() code. You should also move constructing the content from the constructor to getText(). In the constructor the required data is not yet available.
Also consider using a StringBuilder. That's usually better choise than + when you need to make several concatenations.
Edit: (after a clarifying comment by the OP, and myself reading the question better)
In the constructor you can start the letter like:
body = "Dear " + to + ":" + "\n\n";
sender = from;
Here I made sender a field. You don't need the letter field, so you can still stay at the max 2 fields limit.
You will have to initialize the body variable with an empty string. Otherwise its initialized as null, and thereby you cannot append anything to the string as you are doing in function addLine()
Related
I have string looks like below, the string is joined by line-breaker. In this string, the the first 2 lines and last two lines are fixed, "public class MyClass {/n public void code() {/n"
String doc =
"public class MyClass {
public void code() {
try (...) {
...
}
}
}"
I only want to take out the multiple lines code in the method code, which means no first 2 lines and last 2 lines. This is what I did in my project:
String[] lines = docj.split("\\r?\\n");
String[] codes = Arrays.copyOfRange(lines, 2, lines.length - 2);
String result = String.join("\n", codes);
Do you have better way to fetch the string in the middle?
The only real answer: use an existing parser framework, such as javaparser.
Seriously, that simple.
Anything else means: you are spending time and energy to solve a solved problem. The result will be deficient, compared to any mature product, and it will be a constant liability in the future. You can get your tool to work with code you have in front of you right now, but the second your tool gets used to "parse" slightly different code, it will most likely break.
In case you are asking for educational purposes, then learn how compiler works, and what it takes to tokenize Java source code, and how to turn it into an abstract syntax tree (AST) representation.
Assuming the task is meant for basic educational purposes or a quick hack (otherwise #GhostCat's answer draws first):
Already method detection, taken seriously is not so easy. Basically you have to start implementing your own syntax parser for a fraction the Java language: chop everything to single words, skip the class declaration, wait for "static", "public", "protected", "private", "synchronized", hope I didn't forget one, skip over them and the return type definition ("void", "string"...), then you are at the name, then come optional type parameters ("<T>"), then "(", then optionally method parameters etc.).
Perhaps there are restrictions to the task, that make it less complicated. You should ask for clarification.
The problem in any case will be to find the closing braces and skip them. If you can afford to neglect such stuff as braces in strings (string s = "ab{{c";) or comments ("/* {{{ */")it is enough to count up for each { occuring after e.g. "public void code() {" and count down for "}". when the brace count is 0 and you see another "}", that one can be skipped and everything until the next method declaration.
If that's not precise enough, or your requirements are of a more serious nature, you'd have to get into parsing, e.g. using antlr or Javaparser. Here's a project that seems to do a similar task.
Learning Java Parser takes some amount of time. It isn't difficult, and there is a Java Doc Documentation Page available on the Internet. (See Here) ... But unfortunately, there isn't a lot of text to read in the documentation pages themselves. This class prints out the Method Bodies from a source-code file that is saved as a String.
Every method in the class is printed...
import com.github.javaparser.ast.*;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.visitor.VoidVisitor;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.github.javaparser.*;
import java.io.IOException;
import java.util.Optional;
public class MethodBody
{
static final String src =
"public class MyClass {" + '\n' +
" public void code() {" + '\n' +
" try {" + '\n' +
" /* do stuff */ " + '\n' +
" }" + '\n' +
" catch (Exception e) { }" + '\n' +
" }" + '\n' +
"}";
public static void main(String[] argv) throws IOException
{
CompilationUnit cu = StaticJavaParser.parse(src);
VoidVisitor<?> visitor = new VoidVisitorAdapter<Void>()
{
public void visit(MethodDeclaration md, Void arg)
{
System.out.println("Method Name: " + md.getName());
Optional<BlockStmt> optBody = md.getBody();
if (! optBody.isPresent()) System.out.println("No Method Body Definition\n");
System.out.println("Method Body:\n" + optBody.get().toString() + "\n\n");
}
};
visitor.visit(cu, null);
}
}
The above code will print this to terminal:
Method Name: code
Method Body:
{
try {
/* do stuff */
} catch (Exception e) {
}
}
I am trying to remove every punctuation from my string: So far, I've done the following :
String line = "there's, isn't";
line.replaceAll("\\p{Punct}", "")
yet, this can't change "there's" into "theres" or "isn't" into "isnt".
I thought \p{Punct} includes every punctuation, including " ' " (as it's shown in api) yet this doesn't work. Can someone pls help?
Thanks in advance.
PS: expected outcome is: theres isnt
Strings are immutable in Java. String methods don't change the string in place, but instead return a modified copy of the string, so you need to assign the result back to the variable:
String line = "there's, isn't";
line = line.replaceAll("\\p{Punct}", "");
System.out.println(line); // theres isnt
As the previous answer said, the strings are immutable and once created you can't really change it. So once you code like String line = "there's, isn't";the string object "there's, isn't" will be created and line variable will be assigned to it. Java doesn't have the concept of pointers, but you can think of it as line variable pointing to the given string "there's, isn't". Now your next line line.replaceAll("\\p{Punct}", "") returns a newly created string object. You can assign it to another variable, say line_cleared=line.replaceAll("\\p{Punct}", "" and print that out: So here is the fully updated code:
String line = "there's, isn't";
line_cleared= line.replaceAll("\\p{Punct}", "");
System.out.println(line_cleared);
Today, I encountered a problem when I tried to combine multiple "variables" or objects, like the following example code:
String stuff = "blah blah" + amazingness.getName() + " fantabulous code: " + address.
The above example works fine normally, but it does not work in my case.
So basically, I have a server which receives data via UDP means. Now, in order to use UDP, I have to create many threads, so the application does not hang. I don't know if the problem has anything to do with multiple threading, since the processor randomly runs the threads in a random order.
I am using java version 1.8 update 05.
Here is the code in my method.
String message = "Client" + c.name + "(" + c.getID() + ") #" + c.address.toString() + ":" + c.port + "disconnected";
Where:c.name is "Classic", c.getID() returns a random number, c.address.toString() returns the client's ip address, and c.port is the client's port.
When I run the code, I get a message of "Client Classic" and nothing else.
The expected message is: "Client Classic(1932) # 70.40.423.110:8112 disconnected"
Here is a screen shot:
Where has the other values gone?
Now I start to think it may be because referencing other classes messes up the process of adding more values to the string.
So I try to get the values before setting the message string
String message = "";
String name = c.name;
int cID = c.getID();
String address = c.address.toString();
int port = c.port;
message = "Client " + name + "(" + cID + ") # " + address + ":" + port + "disconnected";
System.out.println(message);
Where:String name is Classic, cIDis a random number, address is an ip address, and port is a port number. All of the variables are not static. Still does not output the desired message:
NOW, I test it again without the threads, just a standalone class:
IT WORKS PERFECTLY! Now, my question is why does the above result occur and what did I do wrong?
I appreciate the time you have spent reading my question and I hope you can understand it.
Edit 1: I noticed, in the value of message, the end quotations were never added, will look into it.
Edit 2: looks like the fault is in the name variable, although I have no idea why.
Edit 3: Looks like the name variable contains multiple "null" characters, I will look into it.
Edit: I believe I have fixed the problem, I'll contain a rundown:
Since I created a byte array of length 1024 to send through the network, I never trimmed the array before sending.
Calling "string.trim()" deletes the excess whitespace characters created when I set the variable "name".
Even though I had found this out without seeing the answer from David, I'll credit him with the correct answer.
Do you only see this behavior in Eclipse? I suspect that what is happening is that your name variable contains a null (0) character, which is not a problem for Java per se, but may be a problem for SWT (the widget toolkit used by Eclipse).
For example, the following code creates an array filled with zeros, overwrites the first few 0's with some letters, and then constructs a string similarly to your example.
public class TestMain {
public static void main(String args[]) {
byte[] badChars = new byte[10]; // all bytes are 0
String test = "Middle";
for (int i = 0;i < test.length() && i < badChars.length; ++i) {
badChars[i] = (byte) test.charAt(i);
}
String a = new String(badChars);
System.out.println(a);
String p = "Before " + new String(badChars) + " After";
System.out.println(p);
}
}
The output of this in eclipse is
Middle
Before Middle
But when I run this within Intellij IDEA, I get
Middle
Before Middle After
Just as you would expect.
When I add the following code just after the last println above:
StringBuffer b = new StringBuffer();
for (int i = 0; i < p.length(); ++i) {
char ch = p.charAt(i);
if (ch > 0) {
b.append(ch);
}
}
System.out.println(b.toString());
I get the following in Eclipse
Middle
Before Middle
Before Middle After
So I think it is possible that your 'name' contains a null char, which is causing SWT problems when displayed (such as the debugger, or even the console). SWT uses native widgets (and probably native C style strings, meaning null terminated).
Hope this makes sense - try stripping nulls from your string before you print them, even though they shouldn't be significant in Java.
Can you try:
String message = String.format("Client %s (%d) # %s:%d disconnected", name, cID, address, port);
I might have overlooked some factors influencing the process but that is why i seek help here. It is my first post here and i have read the initial prescriptions for helping me getting the best question as a basis for the best answer. I hop you will understand(otherwise please make a comment with further questions)
The case is that i have been creating an ArrayList
ArrayList<String> liste = new ArrayList<String>();
I gather several names, quantities, and dates:
if(shepherd == 0) {
} else if(shepherd <= 0) {
System.out.println(shepherd);
String s = "('shepherd'," + "'" + shepherd + "'," +"'" + ft.format(date) + "'" + ")";
liste.add(s);
}
I have defined shepherd as follows:
double shepherd = 0;
Next, I wish to add these entries to my MySql database.
I construct a query, and print it out so that I can verify that it is of the correct format:
System.out.println("INSERT INTO kennel VALUES");
for(int i = 0; i < liste.size(); i++) {
System.out.println(liste.get(i));
if(i != liste.size()-1) {
System.out.println(",");
}
}
This shows the correct command, with the proper syntax, but it's only output to the console at this point.
I have to send this through some Jsch or Ganymed. Most likely as a String. So i am wondering how i could take all the different parts, the doubles, the strings, the loop and build up a String, identical to the printed line i get in console.
I sensed it would look like this:
String command = (mysql -e "use kennel;insert into department3 values ('shepherd','1','2013-03-04');";
I believe that I am having some trouble with the " and ( and '.
I hope i made it clear what the trouble is about. Thank you in advance. Sincerely
Your string need to be held within quotation marks. Because this will interfere with the quotation marks within your String, you need to escape them. You can do this by placing a backslash in front of the character. :)
String command = "(mysql -e \"use kennel;insert into department3 values ('shepherd','1','2013-03-04');\"";
I'm having a minor issue with Java String comparisons.
I've written a class which takes in a String and parses it into a custom tree type. I've written a toString class which then converts this tree back to a String again. As part of my unit tests I'm just checking that the String generated by the toString method is the same as the String that was parsed in the first place.
Here is my simple test with a few printouts so that we can see whats going on.
final String exp1 = "(a|b)";
final String exp2 = "((a|b)|c)";
final Node tree1 = Reader.parseExpression2(exp1);
final Node tree2 = Reader.parseExpression2(exp2);
final String t1 = tree1.toString();
final String t2 = tree2.toString();
System.out.println(":" + exp1 + ":" + t1 + ":");
System.out.println(":" + exp2 + ":" + t2 + ":");
System.out.println(exp1.compareToIgnoreCase(t1));
System.out.println(exp2.compareToIgnoreCase(t2));
System.out.println(exp1.equals(t1));
System.out.println(exp2.equals(t2));
Has the following output; (NB ":" - are used as delineators so I can ensure theres no extra whitespace)
:(a|b):(a|b):
:((a|b)|c):((a|b)|c):
-1
-1
false
false
Based on manually comparing the strings exp1 and exp2 to t1 and t2 respectively, they are exactly the same. But for some reason Java is insisting they are different.
This isn't the obvious mistake of using == instead of .equals() but I'm stumped as to why two seemingly identical strings are different. Any help would be much appreciated :)
Does one of your strings have a null character within it? These might not be visible when you use System.out.println(...).
For example, consider this class:
public class StringComparison {
public static void main(String[] args) {
String s = "a|b";
String t = "a|b\0";
System.out.println(":" + s + ":" + t + ":");
System.out.println(s.equals(t));
}
}
When I ran this on Linux it gave me the following output:
:a|b:a|b:
false
(I also ran it on Windows, but the null character showed up as a space.)
Well, it certainly looks okay. What I would do would be to iterate over both strings using charAt to compare every single character with the equivalent in the other string. This will, at a minimum, hopefully tell you the offending character.
Also output everything else you can find out about both strings, such as the length.
It could be that one of the characters, while looking the same, may be some other Unicode doppelganger :-)
You may also want to capture that output and do a detailed binary dump on it, such as loading it up into gvim and using the hex conversion tool, or executing od -xcb (if available) on the captured output. There may be an obvious difference when you get down to the binary examination level.
I have some suggestions
Copy each output and paste in Notepad (or any similar editor), then
copy them again and do something like this
System.out.println("(a|b)".compareToIgnoreCase("(a|b)"));
Print out the integer representation of each character. If it is a weird unicode, the int representation will be different.
Also what version of JDK are you using?