I currently work on a Java project which has many main methods. Now, I do some refactoring, which affects all main methods. However, some of the main methods are actually called directly from other methods. I think this is bad style and it actually makes the refactoring harder. Thus, I want to be able to identify all places where a main method is called. Currently, I use my IDE tools to find all references to a given main method, however this is tedious and it is easy to forget to check this for one of the main methods.
My question is, whether there is some checkstyle rule or Eclipse compiler warnings setting that produces a warning whenever a main method is called directly. I was unable to find one.
If you are concerned that people may have formatted the "main" methods in variety of ways, and that you may miss some of them when you use "pattern matching" ...
Could "javap -public MyClass.class" work for you? When I tried it on ...
public class Main1 {
public
static
void
main
(
String
[]
args
)
{
System.out.println("Main1: Hello World");
}
}
It produced the following output:
Compiled from "Main1.java"
public class Main1 {
public Main1();
public static void main(java.lang.String[]);
}
Admittedly, it doesn't 'detect' if this 'main' is calling another 'main', it will be helpful just in finding all the 'main's.
Source derived from Post: Java Program to disassemble Java Byte Code
As #Jeutnarg suggested in the comments:
[...] you could use Eclipse's Java search. Search for 'main', only searching for 'Method' with Limit to 'References' with Search in 'Sources' with a scope of your project.
This is what I ended up doing and it actually worked much better than I expected.
Related
I have never really understood why code such as that given below is valid and would really appreciate it if someone helped me out.
public class A{
int x;
int y;
void hello() {
System.out.println("Hello World");
}
public static void main(String[] args) {
A my_instance = new A();
my_instance.hello();
}
}
OUTPUT:
Hello World
Question: Why are we allowed to create an instance of A inside one of its own static methods?
I understand that static methods belong to the class and not any particular instance, but does this mean that under the hood the compiler first analyzes everything that's not static and makes that code available to static methods?
See if these points help you.
1. Execution of a Java program starts with a special method public static void main(String[] args). Since Java is an object oriented language, everything has to be inside class, and this special method main() is no exception. That's why it is inside a class, namely A here.
2.
It just seems wrong to me that I can create an instance of something that I'm still in the process of building
This idea of yours is wrong. When the program is running, everything is built already (surely you know the compilation comes before running), so the notion in the process of building doesn't make any sense when the program is already up and running. And if you associate your statement in the process of building to the building of instance of A, then again that would be wrong, since the main() method is static, so doesn't require an instance of A to exist in order for it to be invoked. In fact, main() is invoked before JVM instantiates any other class in your application.
3.
The main(String[] args) being the starting point of execution, it must be allowed to instantiate some class. Now, your class A is a class just like any other, hence main() can instantiate that too.
Some more reading here:
Why is the Java main method static?
Why make a class create an instance of itself?
It works because you can create an object in any context. It works because if it didn't work you could never create an object. Static members are made available on class initialization, not "available to non-static code first" but to anything, static or not, after class initialization completes. main doesn't even run until after class initialization. At that point all the power of the class is available to static and non-static code alike, and that includes the power to create objects. It works because the JLS says that's how it works.
JVM takes care of the execution of static members , in this case , static method in such a way JVM designed .Because , we need to create a object from a static members
It seems contrary to the programmer because it seems as though an instance of the class is "willing" itself into existence, if you are reading the code as a procedural script. But this isn't a line after line procedure that you are looking at. This is code that is being compiled, then run.
Also yes, in the real world cups don't become cups, and clouds don't become clouds by internal calls that "will themselves" into existence, at least not as far as we can tell. But this is programming, and you are allowed to create these kinds of situations. Kind of like looking at the place where the snake bites it's tail, right? You'll get used to it.
Sometimes the answer is technical, and sometimes in programming you need to respect the abstraction process. Stand too close to a Monet and it looks like a bunch of dots.
tl;dr : How to add method to existing class without replacing this class?
Description:
When I run following command in JShell:
public class TestClass {}
following output is printed:
created class TestClass
Running this command once more gives following output:
modified class TestClass
Let's create class with one method, as below:
public class TestClass {
public static void testMethod1() {
System.out.println("In testMethod1");
}
}
It's worth to mention that the output is slightly different from previous class overwriting:
replaced class TestClass
Running testMethod1 ends successfully and In testMethod1 is printed in console.
Now I want to add new method to existing TestClass without loosing testMethod1. So I run following snippet:
public class TestClass {
public static void testMethod2() {
System.out.println("In testMethod2");
}
}
...and testMethod1 is lost, because whole TestClass has been replaced.
How can I add new method to existing class without overwriting it? What if I have written like 10 methods? Am I supposed to write down existing methods next to new method that I want to add to class?
Shouldn't JShell prompt user about class to be replaced in form of warning?
Any hints or help is appreciated.
JShell cannot do this and I do not think it would be what most people want. If you want to regularly merge into existing code, you probably want to use an editor that keeps the source code intact and compile your source from scratch. JShell would need to keep track of all kinds of source code information in addition to the compiled byte code to allow for what you want. For example, what would happen if you added a method that already was implemented as a bridge method as result of defining a generic method?
The reason the message differs with replaced or modified is because of JShells use of HotSwap which can only be applied when a class does not change its shape, i.e. declares the same methods and fields with the same signatures.
How can I add a new method to existing class without overwriting it?
You can perform this using the
/edit
which opens up a Jshell edit pad, where you can add your new method and Accept to update the class definition in your case. The jshell commands also illustrates several other attributes to edit multiple snippets using their name or id. Adding a screenshot for how to do this:
What if I have written like 10 methods? Am I supposed to write down existing methods next to new method that I want to add to class?
Such a use case seems more looking out for an IDE rather than the REPL based jshell and is clearly mentioned as a Non Goal on the JEP#222 jshell: The Java Shell (Read-Eval-Print Loop)
Out of scope are graphical interfaces and debugger support. The JShell API is intended to allow JShell functionality in IDEs and other
tools, but the jshell tool is not intended to be an IDE.
Shouldn't JShell prompt user about class to be replaced in form of warning?
Would second #Elliot as mentioned in the comments, Apparently it doesn't for now.
Though this sounds an interesting ask IMHO but would have to be equally weighed against the thoughts of implementing it, along with not bring down the performance of the tool. The answer by #Rafael provides a hint about maintaining such overhead.
I had tried using System.setProperty in main method with no issues, but when I switched to TestNG as part of my Selenium learning, I realized we cannot write System.setProperty at Class level. It should be either at method level or be in a static block. I just want to understand what is the feature of Java that is compelling us to do this.
public class NewTest {
public String baseUrl = "http://newtours.demoaut.com/";
static {
System.setProperty("webdriver.chrome.driver","D:\\paths\\chromedriver.exe");
}
WebDriver driver = new ChromeDriver();
#Test
public void f1() {
...}
}
Writing this outside of static block shows compilation error like
"Multiple markers at this line, Syntax error"
I just want to understand what is the feature of Java that is compelling us to do this.
The 'feature of Java' is that you can only write methods and declarations at class level, and System.setProperty() is neither: it is a method call.
a basic class need method to perform any action
note - same way you can't call System.out.println("");
Calling System.setProperty() in a static block is occurring at the class level. What is perhaps surprising you is that this only happens once per program - the first time your NewTest class is referenced. static fields and blocks are guaranteed to be executed exactly once per JVM invocation, and that's a feature. If you want your code to be run more often than that you don't want to use static statements.
JUnit and similar testing frameworks provided dedicated mechanisms for running setup code before each class or method that's invoked. See #Before and #BeforeClass, along with this question for more specifics about how to implement this behavior in JUnit.
If #Before/#BeforeClass don't address your question please edit it with more context to clarify what you're trying to accomplish. Including code samples of what you've tried - and why it hasn't worked - is particularly helpful.
Currently, my "main() class" file looks a bit like the following code. Rather than clutter up this example code with //comments for discussion, I have simply labelled four code lines with numbers (1 to 4), and these numbers refer to questions that appear after the code. Thank you.
// package myPackage; // **1**
import myOtherPackage.*;
class mainProject{ // **2**
// **3**
private int myVar;
mainProject(){
myVar = 0;
}
public static void main(String args[]){
// Keep main() looking fairly simple?
// Perhaps just have some "essentials" here, such as error handling?
new mainProject().start(); // **4**
}
private void start(){
// The project gets going here..
}
}
1 Unlike other class files in my project, I have not assigned a package name for my "main() class" file. Is this a bad design choice?
2 Is there a good naming convention for the "main class"? Is it helpful to incorporate the word "main" in to this class name? Would something roughly like "mainProject" be a good idea?
3 Various coding constructs can appear inside the main class file. For example, local variables, constructors, the main() method, and local methods. Do they have a "best order" in which they appear in this file?
4 Is it worthwhile to keep the main() method looking fairly "lean and simple"? In this example, I have just called a local private method called start(), which is intended to get the project started.
Ok, here is how I do it in my professional projects.
For 1. every class should have a package. Main or no main makes no difference. Package is the way java organizes your classes at runtime in form of namespaces. So if you stop giving packages then you may end up with two class files with same name in the same folder or jar and when that happens, JVM picks the first class it finds by the name on the classpath. That may not exactly be the one you want.
For 2. main (speciallypublic static void main(String[] args) is a specific and standard signature that Java needs. Any runnable program, a program that produces an output and can be executed needs a main method with this signature. I will try to explain the signature and that maybe will help you understand why it's like that.
It's public because you want the JVM runtime code to execute the method. Using private or protected won't allow the JVM code to see your method.
It's static because without static the JVM code would need an instance of your class to actually access the method. Remember that static methods and fields can be accessed by just using the class name. However non static members need a valid live object to reach them.
It's void because main does not return anything to its caller. It's like any method having a void return type.
And it's called main because the Java creators thought to give it that name. JVM runtime code which executes this method needs to know about the name of your method which will kick off the execution. Now, if I name it anything then it's impossible for the JVM code to make a wild guess. So name standardization called for a standard name and Java creators stuck to main.
String[] is actually a string array containing the command line arguments that you pass to your program. args is the name of the argument and ironically this is the only thing that you can change to any name you want.
For naming the main class, I usually prefer the names like MyProjectLauncher or MyProjectBootstrap where myProject is the name of your project like tomcat or bigben or anything you like.
For 3. standard convention is:
public class MyClass{
//private members
//protected members
//constructors
//private methods
//protected methods
//public methods
//hashcode and equals
//toString overrides
}
You can pick what you need and drop what you need. Public methods also include the getters and setter for your variables if you use them.
For 4. When designing classes you need to keep in mind scalability and manageability of code. It's very common to have a main class and a few classes at start of the project and then when they grow into oversized kangaroos of thousands of lines then refactor code to adjust it. What you should do is create classes based on functionality, service helpers or actions. Keep main separate in a different class. Just use main to initialize a few things, parse command line options and delegate to start or initialize method which does the remaining things to kick off your program.
Hope this helps.
1 yes you should always use packages. But dont use camelcase in them... So myotherpackage rather than myOtherpackage.
2 yes, it is good convention to incorporate the word main, e.g. MyApplicationMain. Remember class names start with a caps letter.
3 yes, the common order would be statics, members, constructors, methods, much like you have already
4 yes! This enables better testing and you should not use a static context for any longer than you need to.
If you add a package and take on board my tips for caps letters, i think what you have above is absolutely fine.
Usually, it is good to define your own packages in order to avoid naming clashes with any other classes on your classpath. This also applies to the main class. Imagine what would happen if somewhere else in your dependencies there is a class whose creator used the same approach of leaving it in the default package. So yes, put iinto a package.
The naming is left at your latitude, but Java coding conventions definitely urge you to capitalize the name of the class. So, Main or MainProject or EntryPoint would be better choices.
I think you refer to fields and methods as members of the class. Please note that local variables and local methods have a totally different meaning (they're not members of the class itself). The usual ordering is static fields, instance fields, static methods constructors, instance methods. I don't think there is a strong convention, but these are the habits.
It is worthwhile keeping any method clean and simple ;)
ALWAYS use a package. No matter what. This is your namespace!
Don't use camelCase in your package names.
Avoid to import whole packages.*, better import a single package.Clazz.
Class names should ALWAYS be UpperCaseAndCamelCase.
Leave a space between the class or method name and the opening braket {, it improves readability.
The rest seems to be ok. It is more or less a matter of pragmatism. Your code has to fulfill the purpose it was written for and also needs to be testable and readable (by others).
All these criteria will form a ruleset for you or your team.
What if someone else has a main class with the same name? Its better to place it in a package for all but the simplest test programs.
Incorporating "Main" in the class name is a good idea because it quickly tells the reader the purpose of the class, but "mainClass" should be "MainClass" according to java language conventions
The usual order is variables, constructors, and methods in whatever order is reasonable
Yes, keep the main method small and easily readable. The logic in it should mostly just be related to parameters passed to the program, and even that should be factored out when it gets to be too large.
1 packages should definitely be used. It is better for maintenance purposes, if your project gets larger with time then there could be exact same syntax for main used. the package name should be meaningful as well and provide concise containment for relevant functionality classes.
2 yes, it is good to include the word main in the class name and should start with capital letter.
3 commonly the order is variables, constructors, methods.
4 keep the main concise and simple. the lesser code it has the better as you already have done.
Okay, so a java source file must have at least one public class and the file should be called "class-name.java". Fair enough.
Hence, if I have a class, then the following would compile:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!"); // Display the string.
}
}
But what bugs me is that if I remove the 'public' access modifier from the above code, the code still compiles. I just don't get it. Removing it, the code looks like:
class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!"); // Display the string.
}
}
In the above code, since I removed the public access modifier, my class has default or package access, i.e. it can't be accessed from the outside world, only from within the package.
So my question is, how does the above code compile ? The file HelloWorld.java in this case does not have a public HelloWorld class (only a package-private HelloWorld.class) and thus to my understanding should not compile.
a java source file must have at least one public class and the file should be called class-name.java
Incorrect, a top level class does not have to be declared public. The JLS states;
If a top level class or interface type is not declared public, then it may be accessed only from within the package in which it is declared.
See http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#104285 section 6.6.1.
You can place non-public class in a file, and it's not a bug but feature.
Your problem is on level of packaging, not compile. Because you can compile this file with non-public class, but you can't call it from outside, so it's not working as application base class
Like this:
// [+] single file: SomeWrapper.java
public class SomeWrapper {
ArrayList<_PrivateDataType> pdt;
}
// [-] single file: SomeWrapper.java
// [+] single file: _PrivateDataType.java
class _PrivateDataType {
// members, functions, whatever goes here
}
// [-] single file: _PrivateDataType.java
A main method is just like any other method. The only difference is that it may be invoked from the command line with the java command. Even if the main method is not visible from the command line, the class can still be used like any other Java class, and your main method may be invoked by another class in the same package. Therefore i makes sense that it compiles.
In Java main function are not special in any sense. There just exists a terminal command that is able to invoke static methods called main...
There are valid usages for a non public classes. So the compiler does not give error when you try to compile the file.
That's nothing to wonder about. I suppose this behavior is similar to the one of some C/C++-compiler.
Code like "void main() { /.../ }" will be compiled correctly by those compilers, although it is not standards-compliant code. Simply said, the compiler exchanges the "void" with "int".
I think a similar behavior is implemented by the java compiler.
When you do not specify the access modifier of the class (or its field or method), it is assigned "default" access. This means it is only accessible from within the same package (in this case, the default package).
The website Javabeginner.com has an article on the subject - you should become familiar with access modifiers in Java, either from this site, or others.