How to modify Java code while running in debug mode? - java

How can I enable this "Debugging in Runtime" Notch is talking about in this video in Eclipse?
As a test, I'd like to be able to edit the output of the following code and change it to "Hello Runtime Debugging" while it's running.
public class HelloWorld {
public static void main(String[] args) throws InterruptedException {
doIt();
}
private static void doIt() throws InterruptedException {
for (int i = 0; i < 1000; ++i) {
System.out.println("Hello World " + i);
Thread.currentThread().sleep(100);
}
}
}
EDIT: I modified the code, now I get the results I was looking for. Suraj Chandran's answer below explains it.
private static void doIt() throws InterruptedException {
for (int i = 0; i < 1000; ++i) {
print(i);
Thread.currentThread().sleep(100);
}
}
private static void print(int i) {
System.out.println("Hello Sir " + i);
}

Eclipse supports hot swapping code during debugging , out of the box.
While debugging, just change any code and save it, Eclipse will automatically transfer the modified code to the target VM.
Note that you can't make structural changes to the code, like adding new methods, changing method signature or adding new fields. But you can change the code within a method.
EDIT: Note that changing the code during deubgging will make that method re-execute form the beginning, resetting the local variables in that method.

You need to make sure that Project > Build Automatically is checked.
Otherwise it might not work.

After enable Project-> Build Automatically, hot swapping code in debug mode is ok to me

I may misunderstand the question, but if you run a program in Eclipse in debug mode (Run/Debug), you can edit the content of methods during the program runs (if JVM supports it). Regularly you can not change the imports, method signatures, class definitons, etc, just the content of the methods.

Related

AspectJ creates plenty of methods on pointcut

I am new to AOP (using AspectJ / ajc) and have searched / googled the internet high and low searching for an answer to my puzzle. Hopefully, someone here might have it.
As I was given to understand by the documentation, AspectJ is suppose to inject code. From my experience, however, it seems like it is mostly adding code (and simply makes an exchange of method calls).
For example, if I have the method:
private static int foo() {
System.out.println("Hello world");
return 1;
}
And I define the following around advice for it (with a dummy random in order to manipulate proceed() vs. some other return value):
pointcut foo() : call(int com.mytest.aspects.HelloWorld.foo(..));
int around() : foo() {
System.out.println("around()");
if (System.currentTimeMillis() % 2 == 0)
return proceed();
return 0;
}
I get the following after decompiling using jd-gui:
private static final int foo_aroundBody0()
{
return foo();
}
public static void main(String[] args)
{
foo_aroundBody1$advice(HelloAspect.aspectOf(), null);
}
private static final int foo_aroundBody1$advice(HelloAspect ajc$aspectInstance, AroundClosure ajc$aroundClosure)
{
System.out.println("around()");
if (System.currentTimeMillis() % 2L == 0L)
{
AroundClosure localAroundClosure = ajc$aroundClosure;return foo_aroundBody0();
}
return 0;
}
private static int foo()
{
System.out.println("Hello world");
return 1;
}
If that right? Am I perhaps doing something wrong?
I tried using ajc with my android application, but thanks to some jars and SDKs, I got to the dreaded "too many methods" problem.
I am using call pointcuts for most of the time, however it seems that these extra methods are added for each call, even if done within the same class and method, thus increasing my code size and method count significantly.
Any help understanding if this is correct and how it works will be greatly appreciated!
Your understanding is about correct. If you want to avoid too many methods being created, use execution() pointcuts instead of call() wherever possible, because then only one synthetic method per callee will be created, not per caller. I.e. if one method is called from 25 different places, only one additional method will be created instead of 25.
Furthermore you can avoid overhead by limiting the weaving scope of your aspects to the really needed joinpoints. Most aspects I see weave into way too many places. Also, if before() or after() is sufficient, avoid around().

How to use Caliper benchmark beta snapshot without maven?

I have been asked to use Google's Caliper project to create a few microbenchmarks. I would very much like to use the annotation features of the newest beta snapshot, but aside from a few small examples I am having trouble finding good documentation on how to actually run the thing... There is a video tutorial up which instructs users on the new maven integration feature, which I was also asked NOT to use.
Right now I just have a small example stripped from one of theirs, modified with some other information I gleaned from another SO question:
public class Benchmarks {
public class Test {
#Param int size; // set automatically by framework
private int[] array; // set by us, in setUp()
#BeforeExperiment void setUp() {
// #Param values are guaranteed to have been injected by now
array = new int[size];
}
#Benchmark int timeArrayIteration(int reps) {
int dummy = 0;
for (int i = 0; i < reps; i++) {
for (int doNotIgnoreMe : array) {
dummy += doNotIgnoreMe;
}
}
return dummy;
}
}
//(Questionable practice here?)
public static void main (String args[]) {
CaliperMain.main(Test.class, args);
}
}
Running it gives me the message that I did not set a default value for size. I am having trouble tracking down where I should be putting it.
Removing "size" entirely by commenting out the #Param line and giving a hard value to the array declaration in setUp just leads to it deciding that there are "No Experiments to be done," which makes sense, I suppose.
If there are any up-to-date resources or tutorials that could point out what I am doing wrong (probably a whole lot, honestly) I would be very appreciative.
EDIT:
I have updated to this as per some advice:
public class Benchmarks {
#Param({"1", "10", "1000"}) int size; // set automatically by framework
private int[] array; // set by us, in setUp()
#BeforeExperiment void setUp() {
// #Param values are guaranteed to have been injected by now
array = new int[size];
}
#Benchmark int timeArrayIteration(int reps) {
int dummy = 0;
for (int i = 0; i < reps; i++) {
for (int doNotIgnoreMe : array) {
dummy += doNotIgnoreMe;
}
}
return dummy;
}
}
I am running through the beta snapshot and passing in the Benchmarks class as an argument. I receive the following:
Experiment selection:
Instruments: []
User parameters: {size=[1, 10, 1000]}
Virtual machines: [default]
Selection type: Full cartesian product
There were no experiments to be performed for the class Benchmarks using the instruments [allocation, runtime]
It doesn't seem to be detecting any Instruments. I am not passing any in, as it's mentioned in the documentation that it simply uses default allocation, runtime (which is fine for my purposes).
DOUBLE EDIT: Found that problem, stupid mistake. Will do a quick write-up once I confirm it.
Running it gives me the message that I did not set a default value for size.
Parameters are set either from default values:
#Param({"1", "10", "1000"}) int size;
Or by passing values via the the -D flag. E.g.: -Dsize=1,10,1000. Enums and booleans get special treatment in that it uses all possible values without having to list them in the annotation.
Removing "size" entirely by commenting out the #Param line and giving a hard value to the array declaration in setUp just leads to it deciding that there are "No Experiments to be done," which makes sense, I suppose.
The issue is likely that that your benchmark is an inner class and needs a reference to the enclosing class (though this should have been an error). Either make your benchmark class a top-level class (recommended) or make it static.
Also, there is no particular need to include the main method. Invoking CaliperMain with your benchmark class as the first parameter is equivalent.
Running it gives me the message that I did not set a default value for size.
That's very simple:
#Param({"1", "10", "1000"}) int size;
Removing "size" entirely by commenting out the #Param line and giving a hard value to the array declaration in setUp just leads to it deciding that there are "No Experiments to be done," which makes sense, I suppose.
No, it doesn't. Without any params, each benchmark method is to be run exactly once. See the other answer for the solution.
There's a quite some Javadoc, e.g., on #Param. Actually, not so much has changed. Annotations have replaced conventions (now you don't need the time prefix), params stayed the same, setup uses an annotation instead of inheritance.

Java error "Value of local variable is not used"

I am really new to java (started learning 2 days ago). Sorry if this is a stupid question. I am trying to learn how to use rt.exec & similar methods so I tried to make a very simple program which runs calc.exe. This is the code:
public class main {
{
try {
Runtime rt = Runtime.getRuntime() ;
Process p = rt.exec("calc.exe") ;
}
catch(Exception exc){/*handle exception*/}
}
}
I get the error " The value of local variable p is not used".
And if I try to compile this is what I get:
I think it's easy to fix but I don't know how. Would be nice if someone helped.
Well, the error "The value of local variable p is not used.", Is not actually an error. It's your IDE (Eclipse), warning you that you aren't actually reading that variable, so you aren't receiving any input from it.
And the other problem with your class is, you don't have a main method. Like this,
public class main {
public static void main(String[] args) {
try {
Runtime rt = Runtime.getRuntime() ;
Process p = rt.exec("calc.exe") ;
} catch(Exception exc){
/*handle exception*/
}
}
}
And by the way, you should always start a class name with a captial letter. So public class main, should actually be public class Main
You get that error because you don't have the main method that is used to start the java program:
public class main {
public static void main(String[] args) {
try {
Runtime rt = Runtime.getRuntime() ;
Process p = rt.exec("calc.exe") ; // here, eclipse is WARINING(so you can ignore it) you that that the variable p is never used(it's just a warning)
} catch(Exception exc) {
/*handle exception*/
// never do this, always put at least a System.out.println("some error here" + e); so you don't ignore a potential exception
}
}
I believe what you have is not an error but a warning; eclipse (and other IDEs/compilers) will tell you that, although you assigned a value to the variable p, you did not use it anywhere. It tells you this because this is sometimes an error; mostly when you assign a value to a variable, you later use that variable in some way.
You can eliminate the error by changing that particular statement to just
rt.exec("calc.exe")
since you are not required to assign a value from the call to exec.
There is no such thing as a stupid qiestion(only misplaced ones, in the worst case).
The "Editor does not contain a main type" refers to the fact that you have not defined a main method. All java programs require a main method, as such:
public static void main(String [] args){
<code>
}
This is where you must place your code.
The "Value not used" is just a warning; it tells you that your variable p only exists within the try-block. You can declare your p-variable before the try - that way, you can use it outside the try-scope(the scope of a variable refers to where it exists, in this case, only inside the try-block).
If you want to use your p, this is what you're after:
public class Main {
public static void main(String[] args) {
Process p;
try {
Runtime rt = Runtime.getRuntime();
p = rt.exec("calc.exe");
} catch(Exception exc) {/*handle exception*/}
}
}
[EDIT]: Note that it is part of the java coding convention to use Capital letters for the first letter of a class, e.g. Main.java(not main.java)
The use of the variable is not in issue here. That error appears because JVM needs a method with the signature to know where to start execution.
public static void main( String args[] ){ //TODO: Stuff here }
Introduce a method with this signature in your class, and it shall clear that error.
Alternatively, you may embed your code in a static block as below - but this method is not to be recommended.
static {
// TODO: Your code here
}
Error "The value of local variable p is not used" due to the fact that nowhere in the code, you do not use the variable p.
To remove the error - it is necessary to remove the variable "p".
To run the calculator, you must use the code:
public class MainClass {
public static void main(String args[]) throws IOException {
Runtime.getRuntime().exec("cmd /c calc.exe");
}
}
This and all other comments translated by Google Translate
you are not using main how can you compile please use main method.
Ans second one is use p local variable in your method.other wise declare p variable starting of method.

a java static method

I have a class like this
public class StockCodes
{
public static boolean loaded = false;
public static long lastUpdate = 0;
private static long freq = 1000 * 60 * 60 * 24;
public static HashMap<String, Stock> stockMap = new HashMap<String, Stock>();
public static ArrayList<Stock> getCodes()
{
long now = System.currentTimeMillis();
if ((StockCodes.loaded) && ((now - StockCodes.lastUpdate) < freq))
{
System.out.println(StockCodes.loaded);
return stockList;
}
else
{
HttpFetcher fetcher = new HttpFetcher();
....
log.info("Load " + stockList.size() + " Stocks");
StockCodes.loaded = true;
StockCodes.lastUpdate = now;
return stockList;
}
}
public static void main(String[] args)
{
StockCodes.getCodes();
}
}
When I run the java application , it outputs "true". Telling us the stockcodes have loaded.
But when i debug the java appliction, it goes into the else. I do not understand why it runs in this way, especially why it outputs "true" the first time i run the application. Could someone else give me some help ,thank you ~
With the code given above, the control by default should always go in the else block and print nothing. You can verify it.
Not if you have some more places where you call the getCodes() method, then it will differ. Having said this, please verify if there is no other place with a call to getCodes(). ie its invoked single time via main()
The getCodes() function essentially caches the result if the function has been run more than once. The first getCodes() will not print "true", but all subsequent calls will
Run from the command line
public static void main(String[] args)
{
StockCodes.getCodes();
}
this should output nothing to STDOUT.
Your if statement is clean. When I have one of these type of mistakes I go the old fashion route. I put a series of
System.out.println
statements in that section of the code to track where you code is going when it not in debug mode. It is clunky but it works.
When I run your code it goes through the else whether I run in debug mode or regular.
I think you lost a line of your code. Did you have
System.out.println(StockCodes.loaded);
in your else branch also? If you did, and you had it located below your line StockCodes.loaded = true; then it will be printing true for you.
I suggest you use more detailed debugging, something like System.out.println("In the if branch"); and below that in the else branch, a line like System.out.println("In the else branch"); I think you are tricking yourself by having too little output.

how to get the command line arguments from another class with java

so suppose I have a java package....
it's got the main class with the main method
and then it's got a whole bunch of other classes.....
my question is, is it possible to get the args that was passed into the main method from these other classes that are not part of the main class but in the same package...
No, not portably, there may be some trickery based on the JVM implementation but I've never seen it, and it would be a very bad idea to rely on it even if it existed.
If you want those values elsewhere, the main function needs to make them available somehow.
An easy way to do this (not necessarily the best way) is to simply store away the strings as the first thing in main and provide a means for getting at them:
Scratch2.java:
public class Scratch2 {
// Arguments and accessor for them.
private static String[] savedArgs;
public static String[] getArgs() {
return savedArgs;
}
public static void main(String[] args) {
// Save them away for later.
savedArgs = args;
// Test that other classes can get them.
CmdLineArgs cla = new CmdLineArgs();
cla.printArgs();
}
}
CmdLineArgs.java:
public class CmdLineArgs {
public void printArgs() {
String[] args = Scratch2.getArgs();
System.out.println ("Arg count is [" + args.length + "]");
for (int i = 0; i < args.length; i++) {
System.out.println ("Arg[" + i + "] is [" + args[i] + "]");
}
}
}
And, when run with the arguments a b c, this outputs:
Arg count is [3]
Arg[0] is [a]
Arg[1] is [b]
Arg[2] is [c]
The system-properties on some (?) JRE-implementations provide the system-property "sun.java.command" to get the programm-name and parameters that were used to start the program. Like "myjar.jar param1 param2 ...".
While this value doesn't even belong to the set of properties that are mentioned in the documentation, it is present in both Oracle-JRE v1.8 and OpenJRE v1.8 (tested).
I couldn't find any documentation whether this value is supported by default though (best I could find was the list in the System#getProperties() docs). Any clarification on this would be welcome. Handle with care!!!
If you don't care about OS portability, read /proc/self/cmdline or the equivalent for your OS.
See http://en.wikipedia.org/wiki/Procfs
As paxdiablo said, your main class would have to store these parameters and then either distribute or make available to needed ones. Often a good idea would be to let another class do the parsing of these parameters, and provide an object of this class instead of the raw command line to whoever needs it.
I'm kind of a newb at this, but you should be able to store the string[] args to a private instance variable, then make an accessor method for it.
E.g.,
public class test {
private String[] myArgs = new String[10];
public static void main(String[] args) {
myArgs = args;
}
public String[] getArgs() {
return myArgs;
}
}
Not sure if it will work, but that's the idea.

Categories