Reprint--Write high-quality code: 151 Suggestions for improving Java programs (1th: Common methods and guidelines in Java Development ___ recommended 16~20)

Source: Internet
Author: User
Tags object object

Read Catalogue

    • Recommendation 16: Variable business use scripting language
    • Recommendation 17: Use dynamic compilation with caution
    • Recommendation 18: Avoid instanceof unintended results
    • Recommendation 19: Assertions are definitely not chicken ribs
    • Recommendation 20: Do not replace only a class
Back to top recommendation 16: Variable business using scripting language

The Java world has been subjected to different languages, such as Php,ruby,groovy, JavaScript, and so on, these intruders have a common feature: all of the same language-----scripting language, they are in the run-time interpretation of execution. Why would a strong compiled language like Java require these scripting languages? That's because of the three major features of the scripting language, as follows:

    1. Flexible: Scripting languages are generally dynamic types that can be used directly without declaring variable types, and can be re-run for a different type of time.
    2. Convenient: scripting language is an explanatory language that does not need to be compiled into binary code, nor does it need to generate bytecode like Java. Its execution is dependent on the interpreter, so it is easy to change the code during run time without stopping the application;
    3. Simple: You can only say that some scripting languages are simple, such as groovy, and for programmers, there is no big hurdle.

These features of the scripting language are missing from Java, and the introduction of scripting languages makes Java more powerful, so JAVA6 begins to formally support scripting languages. But because of the scripting language, it's hard for Java developers to determine which language to support, so JSCP (Java Community ProCess) is smart enough to put forward the JSR233 specification, As long as the language that conforms to the specification can be run on the Java platform (it is supported by default for JavaScript).

Simply take a look at the following small example:

function formual (var1, var2) {     return var1 + var2 * factor;}

This is a simple scripting language function, and you might be wondering: factor (factor) where does this variable come from? It is from the context, similar to a running environment variable. The JS is saved in C:/model.js, and the next step is to invoke the JavaScript formula, as follows:

 1 Import java.io.FileNotFoundException; 2 Import Java.io.FileReader; 3 Import Java.util.Scanner; 4 5 Import Javax.script.Bindings; 6 Import javax.script.Invocable; 7 Import Javax.script.ScriptContext; 8 Import Javax.script.ScriptEngine; 9 Import javax.script.scriptenginemanager;10 Import javax.script.scriptexception;11 public class Client16 {Publi         c static void Main (string[] args) throws filenotfoundexception,14 Scriptexception, nosuchmethodexception {15         Get a JavaScript execution engine for scriptengine engine = new Scriptenginemanager (). Getenginebyname ("JavaScript"); 17 Build context variable Bindings bind = Engine.createbindings (), Bind.put ("factor", 1); 20//bind context, function So the current engine range is engine.setbindings (bind, scriptcontext.engine_scope); Scanner input =new Scanner (system.in); 2 3 while (Input.hasnextint ()) {int first = Input.nextint (); int second = Inpu T.nextint (); SySTEM.OUT.PRINTLN ("Input parameter is:" +first+ "," +second "), 28//Execute JS code engine.eval (" New FileReader "(" C:/model.js ")); 30//Whether the method can be called if (engine instanceof invocable) {invocable in = (invocable ) engine;33//Execute JS function in double result = (double) in.invokefunction ("formula", First, Sec ond); System.out.println ("Operation result:" + result.intvalue ()); 36}37}38 39}40}

The previous code uses the scanner class to accept two digits entered by the keyboard, and then calls the formula function of the JavaScript script to calculate its results, noting that the current JVM will run until a non-int number is entered, which is an online change to the simulated generation system. The results of the operation are as follows:

The input parameter is; The result is: 3

At this point, to keep the JVM running, let's modify the formula function with the following code:

function formual (var1, var2) {     return var1 + var2-factor;}

Among them, multiplication sign into a minus sign, the calculation formula has undergone a major change. Go back to the JVM and continue typing, and the results are as follows:

Input parameters: Operation result is: 2

Modify the JS code, the JVM does not restart, the input parameters have not changed, just change the script function can produce different effects. This is where the scripting language is most advantageous for system design: It can be released at any time without deployment, and this is where our javaer love it most----even if changes are made, we can provide uninterrupted business services.

Java6 not only provides a code-level script built-in, but also provides a jrunscript command tool that maximizes performance in batch processing, and does not require the JVM to interpret the scripting language and can run scripts directly from the tool. Think about it. What a great temptation it is! And this tool can be cross-operating, and script porting is easier.

Back to top tip 17: Use dynamic compilation with caution

Dynamic compilation has always been the dream of Java, starting from JAVA6 to support dynamic compilation, you can run the runtime directly compiled. java files, execute. class, and get the relevant input and output, and even listen to related events. However, we would most like to set a piece of code, directly compiled, and then run, that is, the aerial compiler Execution (on-the-fly), see the following code:

 1 Import java.io.IOException; 2 Import Java.lang.reflect.Method; 3 Import Java.net.URI; 4 Import java.util.ArrayList; 5 Import Java.util.Arrays; 6 Import java.util.List; 7 8 Import Javax.tools.JavaCompiler; 9 Import javax.tools.javafileobject;10 Import javax.tools.simplejavafileobject;11 Import JAVAX.TOOLS.STANDARDJAVAFILEMANAGER;12 Import javax.tools.toolprovider;13 public class Client17 {public static V OID Main (string[] args) throws Exception {+//Java source code * String SOURCESTR = "public class Hello {public String SayHello (string name) {return \ "hello,\" +name+\ "!\";}} ";         18//class name and filename, string clsname = "Hello"; 20//Method Name: String methodName = "SayHello"; 22 Current compiler Javacompiler CMP = Toolprovider.getsystemjavacompiler ();//Java standard File Manager standar Djavafilemanager fm = Cmp.getstandardfilemanager (NULL, null,26 null); Java file object FileObject JFO = new StringjAvaobject (Clsname, SOURCESTR); 29//compile parameters, similar to Options30 list<string> Optionslis in Javac <options> t = new arraylist<string> (); 31//The place where the compiled file is stored, note: Here is the Optionslist.addall for Eclipse tool (Arrays.aslist ("         -D ","./bin ")); 33//unit to be compiled list<javafileobject> Jfos = arrays.aslist (JFO); 35//Set compilation environment 36         Javacompiler.compilationtask task = Cmp.gettask (NULL, FM, null,37 optionslist, NULL, Jfos); 38 Compile successfully if (Task.call ()) {40//Generate object in a few of the objects obj = Class.forName (clsname). Newinstan CE (); class<? Extends object> cls = Obj.getclass (); 43//Call SayHello method Methods M = Cls.getmethod (MethodName, String.class); string str = (string) m.invoke (obj, "Dynamic compilation"); System.out.println ( STR)}48}50}51 class Stringjavaobject extends Simplejavafileobject {53//source code PRIVAte String content = ""; 55 56//class name followed by Java specification and file Stringjavaobject public (string _javafilename, String _content) { _createstringjavaobjecturi (_javafilename), kind.source); content = _content;60}61 62/  /generates a URL resource path _createstringjavaobjecturi (String name) {64//note, no package name is set here. Uri.create ("string:///" + name + Kind.SOURCE.extension); 66}67 68//Text file code @Override70 public charsequ  Ence Getcharcontent (Boolean ignoreencodingerrors) throws IOException {content;73

The above code is more, can be used as a dynamically compiled template program. As long as the local static compilation can achieve tasks, such as compilation parameters, input and output, error monitoring, etc., dynamic compilation can be achieved.

Dynamic compilation of Java provides multiple channels for the source. For example, it could be a string, a text file, a bytecode file, and a plaintext code or bytecode stored in a database. Summarize a sentence, as long as the Java specification can be dynamically loaded at run time, its implementation is to implement the Javafileobject interface, rewrite getcharcontent, Openinputstream, Openoutputstream, or the implementation of the JDK has provided two simplejavafileobject, Forwardingjavafileobject, the specific code can refer to the previous example.

Dynamic compilation, while a good tool, allows us to control the compilation process more freely, but it is still less used in the projects we are currently contacting. The reason is simple, static compilation has been able to help us deal with most of the work, even the whole work, even if the need for dynamic compilation, there are good alternatives, such as JRuby, groovy and other seamless scripting language. In addition, when we use dynamic compilation, we need to pay attention to the following points:

    1. use caution in the framework : for example, to use dynamic compilation in struts, dynamically implement a class that, if inherited from Actionsupport, wants it to be an action. Can do, but debug is difficult, for example, in spring, write a dynamic class, in order to inject it into the spring container, it takes the Boss Kung Fu.
    2. do not use in projects that require high performance : If you provide a feature on the Web interface that allows you to upload a Java file and then run it, that means: "My machine doesn't have a password and everyone can see it," which is a very typical injection vulnerability, Just upload a malicious Java program to get all your security work destroyed.
    3. record the dynamic compilation process : It is recommended to record the source files, the target file, the compilation process, the execution process and other logs, not only for the diagnosis, or for security and audit, for the Java Project, the aerial compilation and operation is not reassuring, leaving these basis can be good to optimize the program.
Back to top tip 18: Avoid instanceof unintended results

Instanceof is a simple two-dollar operator, it is used to determine whether an object is an implementation of a class, its operation is similar to >=, = =, very simple, we look at the paragraph program, the code is as follows:

 1 Import java.util.Date;         2 3 public class Client18 {4 public static void main (string[] args) {5///String object is an instance of object True 6 Boolean B1 = "String" instanceof Object; 7//String object is an instance of string True 8 Boolean b2 = new string () instanceof string;  9//Object object is an instance of String False10 Boolean b3 = new Object () instanceof string;11//unboxing type is an instance of a boxed type Compilation does not pass a Boolean b4 = ' A ' instanceof character;13//null object is an instance of string False14 boolean b5 = null ins Tanceof string;15//Converted empty object is an instance of String False16 boolean b6 = (String) null instanceof string;17/ /Date Whether the instance of string is compiled without the B7 = new Date () instanceof string;19//Determines whether a string object is an instance of Date in a generic type Fals E20 Boolean B8 = new Genericclass<string> (). Isdateinstance ("");}23}24 class genericclass<t& Gt {26//determines if the date type is a public boolean isdateinstance (T t) {instanceof-return T-date; 29}30 31} 

For such a program, INSTANCEOF's application scenario basically appears, and the problem arises: which statements in this program are not compiled, we explain one by one:

  1. "String" instanceof object: The return value is true, which is normal, "string" is a string, and the string inherits the object, which of course returns true.
  2. New String () instanceof string: The return value is true, there is no problem, the object of a class is of course an instance of it.
  3. New Object () instanceof string: The return value of False,object is the parent class whose object is of course not an instance of the String class. Note that this sentence can actually be compiled through, as long as the instanceof keyword left and right two operands have inheritance or implementation of the relationship, it can be compiled through.
  4. ' A ' instanceof Character: This sentence compilation does not pass, why? Because ' a ' is a char type, which is a basic type, not an object, instanceof can only be used for object judgments and cannot be used for basic types of judgments.
  5. Null instanceof String: The return value is false, which is a instanceof-specific rule, and if the operand is null, the result is a direct return of false, which is no longer the class of the right operand. This is very advantageous to our program, and when using the instanceof operator, it is not necessary to care about whether the class being judged (that is, the left operand) is null, unlike the Equals and ToString methods we often use.
  6. (string) null instanceof String: The return value is false, do not see there is a coercion type conversion that the result is true, no, NULL is a universal type, that is, it can be no type, even if the type conversion is a null.
  7. New Date () instanceof String: compilation does not pass, because the Date class and String do not inherit or implement the relationship, so at compile time directly error, the instanceof operator left and right operand must have inheritance or implementation relationship, otherwise the compilation will fail.
  8. New Genericclass<string> (). Isdateinstance (""): compilation does not pass, non-also, compiled by, the return value of False,t is a String type, there is no inheritance or implementation relationship between date, why "t instanceof Date "will compile through?" That's because Java generics are for encoding services, when the code is translated into bytecode, T is already an object type, the passed argument is a string type, that is, the surface type of T is object, the actual type is string, then "T instanceof Date" is equivalent to " Object instanceof Date ", so it's normal to return false.
Back to top tip 19: Assertion is definitely not chicken

In defensive programming, it is common to use assertions (assertion) to make judgments about parameters and environments, to prevent programs from generating logical anomalies due to improper judgment or input errors, assertions exist in many languages, C, C + +, Python has different assertion representations. In Java, assertions use the Assert keyword, which has the following basic usage:

assert< Boolean Expressions >

assert< Boolean expression >: < error message >

When the Boolean expression is false, it runs out of the Assertionerror error and comes with an error message. The syntax for assert is simple and has the following two features:

(1), Assert is not enabled by default

We know that the assertion is for the debugger service, the purpose is to be able to quickly and easily check the program exceptions, but Java is not enabled by default, to enable the compile, run-time with the relevant keywords, this does not say, if necessary, you can refer to the Java specification.

(2), assert run out of the exception assertionerror is inherited from the error

After the assertion fails, the JVM throws a Assertionerror error, which inherits from the error, noting that this is a mistake, unrecoverable, which means that this is a serious problem that the developer must pay attention to and resolve.

Assert is an assertion, but it cannot be equivalent to If...else ... This condition determines that it is not available in the following two cases:

(1), in the public method of external

We know that the core point of defensive programming is that all external factors (input parameters, environment variables, contexts) are "evil", there are evil origins that attempt to destroy the program, and in order to resist it, we have to examine the procedures everywhere. Montreal multiplication, do not meet the conditions, do not perform follow-up procedures to protect the correctness of subsequent procedures, everywhere multiplication no problem, but it is not possible to use assertions to do input verification, especially public methods. Let's look at an example:

1 public class Client19 {2 public     static void Main (string[] args) {3         System.out.println (Stringutils.encode (null ));; 4     } 5} 6  7 class stringutils{8 public     static String encode (String str) {9         assert    str! = null: "Encrypted word string is null "; */         * Cryptographic processing */11         return str;12     }14}

The Encode method makes null assumptions about the input parameters, and if it is empty, throws a assertionerror error, but there is a serious problem with this program, encode is a public method, which marks it when it is publicly available, Any class can be called as long as it can pass a string parameter (following the contract), but the Client19 class calls the Encode method according to the rules and the contract, but obtains a assertionerror error message, who destroys the contract agreement? ---is the encode method itself.

(2), in the case of the execution of logic code

Assert support is optional and can be run at development time, but in a production environment The system does not need it to run (to improve performance), so logic code cannot be executed in an Assert's Boolean expression, otherwise it will produce different logic because of different environments, for example:

public void dosomething (list list, Object element) {        assert List.remove (Element): "Delete element" + element + "failed";        /* Business processing */    }

This code in the assert enabled environment without any problems, but the input into the build environment, will not enable the assertion, and this method is completely finished, the list of delete action will never execute, so will never error or abnormal, because there is no execution!

Assert assert cannot be used in either of these cases, and when can I use assert? Bottom line: The area of code that cannot be reached by normal execution logic can prevent an assert. There are three specific cases:

    1. Placing an assert as an input parameter in a private method: The Assert check input parameter can be placed in a private method, because the consumer of the private method is the author himself, the caller and the callee of the private method is a contractual relationship, or there is no contractual relationship, and the constraints are controlled by the author himself, So with assert, you can better prevent yourself from making mistakes or inadvertently making mistakes.
    2. An area that cannot be reached in Process control: this is similar to the JUnit fail method, whose symbolic meaning is that the execution of the program is wrong here, for example:
public void DoSomething () {        int i = 7;        while (i > 7) {/            * Business processing */        }        Assert false: "This means error";    }

3. Set up a program probe: We may define two variables in a program, substituting two different business meanings, but there is a fixed relationship, for example: VAR1=VAR2 * 2, then we can set up a "pile" in the program, assert the relationship between the two, if not satisfied that the program has already experienced an exception , the business is no longer necessary to run.

Back to top recommendation 20: Do not replace only one class

We often define a constant interface (or constant class) in the system to encompass the constants involved in the system, simplifying the code, making it easy to develop, and using a similar approach in many open source projects, such as in Struts2, Org.apache.struts2.StrutsConstants is a constant class that defines configuration-related constants in the Struts framework, while org.apache.struts2.StrutsConstants is a constant interface that defines the key to OGNL access Word.

About constant interfaces (classes) Let's look at an example and first define a constant class:

public class Constant {    //define human life limit public    static final int max_age=150;}

This is a very simple constant class that defines the maximum age of the human being, and we refer to this constant, the code is as follows:

public class client{public    static void Main (string[] args) {        System.out.println ("Human life limit is:" +constant.max_age );    }}

Easy to run results, so omitted. The current code is written in the "smart" IDE tool, which goes back to the original era, which is returning to the age of writing code in Notepad, and then see what happens (why, here's the answer)

Modify the constant constant class, the human life limit increases, the maximum live to 180, the code is as follows:

public class Constant {    //define human life limit public    static final int max_age=180;}

Then recompile, Javac Constant, execute after compilation: Java Client, guess what the age of the output is?

The result of the output is: "Human life limit is 150", unexpectedly did not change to 180, too strange, this is why?

The reason for this is that for the base type of the final adornment and the string type, the compiler will consider it to be stable (immutable Status) so that it compiles the values directly into the bytecode at compile time, avoiding references at runtime (Run-time Reference). To improve the efficiency of code execution. For our example, the client class writes "150" in the compile-time bytecode, which is a constant, not an address reference, so no matter how you modify the constant class, the output is still the same as long as you do not recompile the client class.

For a Final decorated class (that is, a non-primitive type), the compiler considers it to be not a stable state (Mutable Status), and a reference relationship is established at compile time (this type is also called soft Final). If the constant introduced by the client class is a class or instance, it will also output the most recent value without recompiling.

Do not underestimate this knowledge, fine pits can also trip elephants, such as in a Web project, the developer modified a final type of value (basic type) Considering the risk of re-release is large, or the approval process is too cumbersome, anyway, to be lazy, So directly replaced by the class file, the application server automatically restarts, and then a simple test, everything OK, can run a few days later found that business data is not on, some classes (referencing the relationship of the class) used the old value, some classes (inheritance relationship of the class) using the new value, and no clue, Let people helpless, in fact, the root of the problem lies in this.

There is a small question that does not explain why our example is not running in IDE tools such as Eclipse. That's because automatic compilation in the IDE doesn't reproduce the problem, and if you modify the constant class, the IDE tool automatically compiles all the reference classes, "smart" masks the problem, but the potential risk is still there, and I remember that Eclipse should have a portal set up for automatic compilation. You are interested to try it yourself.

 Note: The use of class file substitution is prohibited when publishing an application, and the overall War pack release is Surefire plan. But I think that special cases should be treated in a special way, and we cannot generalize them.

Reprint--Write high-quality code: 151 Suggestions for improving Java programs (1th: Common methods and guidelines in Java Development ___ recommended 16~20)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.