PMD规则

Design Rules

·  UseSingleton: If you have a class that has nothing but static methods, consider making it a Singleton. Note that this doesn't apply to abstract classes, since their subclasses may well include non-static methods. Also, if you want this class to be a Singleton, remember to add a private constructor to prevent instantiation.

翻译  使用单例:如果有一个类包含的只有静态方法,可以考虑做成单例的。注意这个规则不适用于抽象类,因为它们的子类可能包含非静态方法。还有,如果你想把一个类做成单例的,记得写一个私有的构造器以阻止外部实例化。

·  SimplifyBooleanReturns: Avoid unnecessary if..then..else statements when returning a boolean.

翻译  简化布尔量的返回:避免在返回布尔量时写不必要的if..then..else表达式。

代码示例:

public class Foo {

  private int bar =2;

  public boolean isBarEqualsTo(int x) {

    // this bit of code

    if (bar == x) {

     return true;

    } else {

     return false;

    }

    // 上面可以简化为:

    // return bar == x;

  }

}

·  SimplifyBooleanExpressions: Avoid unnecessary comparisons in boolean expressions - this complicates simple code.

翻译  简化布尔表达式:避免布尔表达式之间无用的比较——只会使代码复杂化

代码示例:

public class Bar {

 // 下面可以简化为: bar = isFoo();

 private boolean bar = (isFoo() == true);

 

 public isFoo() { return false;}

}

·  SwitchStmtsShouldHaveDefault: Switch statements should have a default label.

翻译  Switch表达式应该有default

·  AvoidDeeplyNestedIfStmts: Deeply nested if..then statements are hard to read.

翻译  避免深度嵌套的if表达式:深度嵌套的if..then表达式难以阅读

·  AvoidReassigningParameters: Reassigning values to parameters is a questionable practice. Use a temporary local variable instead.

翻译  避免给参数重新赋值:给传入方法的参数重新赋值是一种需要商榷的行为。使用临时本地变量来代替。

·  SwitchDensity: A high ratio of statements to labels in a switch statement implies that the switch statement is doing too much work. Consider moving the statements into new methods, or creating subclasses based on the switch variable.

翻译  密集的switchswitch表达式的case块中出现很高比例的表达式语句表明switch表达式做了太多的工作。考虑将表达式语句写进一个新的方法,或者创建基于switch变量的子类。

代码示例:

public class Foo {

 public void bar(int x) {

   switch (x) {

     case 1: {

       // lots of statements

       break;

     } case 2: {

       // lots of statements

       break;

     }

   }

 }

}

·  ConstructorCallsOverridableMethod: Calling overridable methods during construction poses a risk of invoking methods on an incompletely constructed object and can be difficult to discern. It may leave the sub-class unable to construct its superclass or forced to replicate the construction process completely within itself, losing the ability to call super(). If the default constructor contains a call to an overridable method, the subclass may be completely uninstantiable. Note that this includes method calls throughout the control flow graph - i.e., if a constructor Foo() calls a private method bar() that calls a public method buz(), this denotes a problem.

翻译  构造器调用了可重写的方法:在构造器中调用可被覆盖的方法可能引发在一个尚未构造完成的对象上调用方法的风险,而且是不易辨识的。它会使得子类不能构建父类或者自己强制重复构建过程,失去调用super()方法的能力。如果一个默认的构造器包含一个对可重写方法的调用,子类可能完全不能被实例化。注意这也包含在整个控制流图上的方法调用——例如:如果构造器Foo()调用了私有方法bar(),而bar()又调用了公开的方法buz(),这就会导致问题。

代码示例:

public class SeniorClass {

  public SeniorClass(){

      toString(); //may throw NullPointerException if overridden

  }

  public String toString(){

    return "IAmSeniorClass";

  }

}

public class JuniorClass extends SeniorClass {

  private String name;

  public JuniorClass(){

    super(); //Automatic call leads to NullPointerException

    name = "JuniorClass";

  }

  public String toString(){

    return name.toUpperCase();

  }

}

·  AccessorClassGeneration: Instantiation by way of private constructors from outside of the constructor's class often causes the generation of an accessor. A factory method, or non-privitization of the constructor can eliminate this situation. The generated class file is actually an interface. It gives the accessing class the ability to invoke a new hidden package scope constructor that takes the interface as a supplementary parameter. This turns a private constructor effectively into one with package scope, and is challenging to discern.

翻译  存取器类生成:从一个具有私有构建器的类的外部实例化这个类通常会导致存取器的生成。工厂方法,或者非私有化的构造器可以避免这个情况。生成的类文件事实上是一个接口。它赋予访问类调用一个新的隐藏的包范围的构建器并把这个接口作为补充参数的能力。这样就把私有的构造器有效地转换为一个包范围的构建器,而且是不易觉察的。

代码示例:

public class Outer {

 void method(){

  Inner ic = new Inner();//Causes generation of accessor class

 }

 public class Inner {

  private Inner(){}

 }

}

·  FinalFieldCouldBeStatic: If a final field is assigned to a compile-time constant, it could be made static, thus saving overhead in each object at runtime.

翻译  final类型的域可以同时是static的:如果一个final类型的域在编译时被赋值为常量,它也可以是static的,那样就在每个对象运行时节省开支。

·  CloseResource: Ensure that resources (like Connection, Statement, and ResultSet objects) are always closed after use.

翻译  关闭资源:确保这些资源(譬如:Connection,Statement,ResultSet对象)总在使用后被关闭。

·  NonStaticInitializer: A nonstatic initializer block will be called any time a constructor is invoked (just prior to invoking the constructor). While this is a valid language construct, it is rarely used and is confusing.

翻译  非静态的初始化器:非静态的初始化块将在构造器被调用的时候被访问(优先于调用构造器)。这是一个有效的语言结构,但使用很少且易造成迷惑。

代码示例:

public class MyClass {

 // this block gets run before any call to a constructor

 {

  System.out.println("I am about to construct myself");

 }

}

·  DefaultLabelNotLastInSwitchStmt: By convention, the default label should be the last label in a switch statement.

翻译  switch表达式中default块应该在最后:按照惯例,default标签应该是switch表达式的最后一个标签。

·  NonCaseLabelInSwitchStatement: A non-case label (e.g. a named break/continue label) was present in a switch statement. This legal, but confusing. It is easy to mix up the case labels and the non-case labels.

翻译  switch表达式中没有case标签:在switch表达式中没有case,是合法的,但是容易造成迷惑。容易将case标签和非case标签混淆。

·  OptimizableToArrayCall: A call to Collection.toArray can use the Collection's size vs an empty Array of the desired type.

翻译  优化toArray调用:调用Collection.toArray时使用集合的规模加上目标类型的空数组作为参数。

代码示例:

class Foo {

 void bar(Collection x) {

   // A bit inefficient

   x.toArray(new Foo[0]);

   // Much better; this one sizes the destination array, avoiding

   // a reflection call in some Collection implementations

   x.toArray(new Foo[x.size()]);

 }

}

·  BadComparison: Avoid equality comparisons with Double.NaN - these are likely to be logic errors.

翻译  错误的比较:避免Double.NaN的相等性比较-这些可能是逻辑错误

·  EqualsNull: Inexperienced programmers sometimes confuse comparison concepts and use equals() to compare to null.

翻译  等于空:经验缺乏的程序员有时候会迷惑于相等性概念,拿equals()方法和null比较

·  ConfusingTernary: In an "if" expression with an "else" clause, avoid negation in the test. For example, rephrase: if (x != y) diff(); else same(); as: if (x == y) same(); else diff(); Most "if (x != y)" cases without an "else" are often return cases, so consistent use of this rule makes the code easier to read. Also, this resolves trivial ordering problems, such as "does the error case go first?" or "does the common case go first?".

翻译  令人迷惑的三种性:在if表达式伴随else子句时,避免在if测试中使用否定表达。例如:不要使用if (x != y) diff(); else same()这种表述,而应该使用if (x == y) same(); else diff(),大多数时候使用if(x!=y)形式时不包含else分句,所以一贯地使用此规则能让代码更易于阅读。此外,这也解决了一个细节的排序问题,比如“应该是判断为false的代码块在前面?”,还是“判断通过的代码块在前?”

·  InstantiationToGetClass: Avoid instantiating an object just to call getClass() on it; use the .class public member instead.

翻译  通过getClass实例化:避免通过访问getClass()实例化对象,使用.class这个公共属性代替。

·  IdempotentOperations: Avoid idempotent operations - they are have no effect.

翻译  幂等性操作:避免幂等性操作-它们不起任何作用

幂等性操作,同样的操作无论执行多少次,其结果都跟第一次执行的结果相同。

代码示例:

public class Foo {

 public void bar() {

  int x = 2;

  x = x;

 }

}

·  SimpleDateFormatNeedsLocale: Be sure to specify a Locale when creating a new instance of SimpleDateFormat.

翻译  SimpleDateFormat类需要本地参数:确保在创建SimpleDateFormat类的实例时指定了Locale参数

·  ImmutableField: Identifies private fields whose values never change once they are initialized either in the declaration of the field or by a constructor. This aids in converting existing classes to immutable classes.

翻译  不变域:识别出一旦被声明就赋值或通过构造器赋值后就从不改变的私有域,它们将存在的类变成了不变类。这样的域可以是final

代码示例:

public class Foo {

  private int x; // could be final

  public Foo() {

      x = 7;

  }

  public void foo() {

     int a = x + 2;

  }

}

·  UseLocaleWithCaseConversions: When doing a String.toLowerCase()/toUpperCase() call, use a Locale. This avoids problems with certain locales, i.e. Turkish.

翻译  大小写转换时使用Locale:当访问String.toLowerCase()/toUpperCase()时使用Locale参数,这样可以避免某些特定的本地化问题,比如土耳其语

·  AvoidProtectedFieldInFinalClass: Do not use protected fields in final classes since they cannot be subclassed. Clarify your intent by using private or package access modifiers instead.

翻译  避免在final类中使用protected域:因为final类型的class不能被继承,所以不要使用protected域,通过使用private或包访问符来代替以修正你的意图。

·  AssignmentToNonFinalStatic: Identifies a possible unsafe usage of a static field.

翻译  给一个非finalstatic类型赋值:识别出一个非安全的static域使用

代码示例:

public class StaticField {

   static int x;

   public FinalFields(int y) {

    x = y; // unsafe

   }

}

·  MissingStaticMethodInNonInstantiatableClass: A class that has private constructors and does not have any static methods or fields cannot be used.

翻译  在不可实例化类中缺少静态方法:一个具有私有构造器且没有任何静态方法或静态变量的类不能被使用

·  AvoidSynchronizedAtMethodLevel: Method level synchronization can backfire when new code is added to the method. Block-level synchronization helps to ensure that only the code that needs synchronization gets it.

翻译  避免方法级的同步:当为一个同步的方法加入新代码时可能发生意外。块级别的同步可以确保内含真正需要同步的代码。

·  MissingBreakInSwitch: A switch statement without an enclosed break statement may be a bug.

翻译  switch块中缺少breakswitch表达式缺少内含的break块可能是bug

·  UseNotifyAllInsteadOfNotify: Thread.notify() awakens a thread monitoring the object. If more than one thread is monitoring, then only one is chosen. The thread chosen is arbitrary; thus it's usually safer to call notifyAll() instead.

翻译  使用notifyAll代替notify: Thread.notify()唤醒监控对象的线程。如果多余一个线程在监控中,只会有一个被选择。这个线程的选择是随机的,因此调用notifyAll()代替它更安全。

·  AvoidInstanceofChecksInCatchClause: Each caught exception type should be handled in its own catch clause.

翻译  避免在catch块中使用instanceof:每个产生的异常类型都应该在自己的catch块中被处理。

·  AbstractClassWithoutAbstractMethod: The abstract class does not contain any abstract methods. An abstract class suggests an incomplete implementation, which is to be completed by subclasses implementing the abstract methods. If the class is intended to be used as a base class only (not to be instantiated direcly) a protected constructor can be provided prevent direct instantiation.

翻译  抽象类没有抽象方法:抽象类没有包含抽象方法,抽象类建议未完成的方法实现,这个方法在子类中被完成。如果类意图被用作基础类(不被直接实例化),一个protected的构造器就能提供对直接实例化的阻止。

·  SimplifyConditional: No need to check for null before an instanceof; the instanceof keyword returns false when given a null argument.

翻译  简化条件:在使用instanceof之间不需要null校验,当给予一个null作为参数时,instanceof返回false

·  CompareObjectsWithEquals: Use equals() to compare object references; avoid comparing them with ==.

翻译  对象相等性比较:使用equals()比较对象的引用,避免使用”==”来比较

·  PositionLiteralsFirstInComparisons: Position literals first in String comparisons - that way if the String is null you won't get a NullPointerException, it'll just return false.

翻译  把字面量放在比较式的前面:在字符串比较时,将字面量放在前面-这种方法能够避免当字符串为空时的空指针异常,只是返回false

·  UnnecessaryLocalBeforeReturn: Avoid unnecessarily creating local variables

翻译  return之前不必要的本地变量:避免创建不必要的本地变量

代码示例:

public class Foo {

    public int foo() {

      int x = doSomething();

      return x;  // instead, just 'return doSomething();'

    }

  }

·  NonThreadSafeSingleton: Non-thread safe singletons can result in bad state changes. Eliminate static singletons if possible by instantiating the object directly. Static singletons are usually not needed as only a single instance exists anyway. Other possible fixes are to synchronize the entire method or to use an initialize-on-demand holder class (do not use the double-check idiom). See Effective Java, item 48.

翻译  非线程安全的单例:非线程安全的单例可以导致错误的状态转换。如果可能通过直接实例化消除静态的单例.因为事实上只存在一个实例,所以静态单例一般是不需要的。另外的解决办法是同步实际的方法或者使用一个按需实例化的持有类(不要使用双重检查机制)。请参阅:Effective Java,48章。

代码示例:

private static Foo foo = null;

//multiple simultaneous callers may see partially initialized objects

public static Foo getFoo() {

    if (foo==null)

        foo = new Foo();

    return foo;

}

·  UncommentedEmptyMethod: Uncommented Empty Method finds instances where a method does not contain statements, but there is no comment. By explicitly commenting empty methods it is easier to distinguish between intentional (commented) and unintentional empty methods.

翻译  不含注释的空方法:不含注释的空方法就是说一个方法内部没有任何程序代码也没有注释。通过明确的注释空方法能够容易的区分有潜在意向的和无意向的空方法。

·  UncommentedEmptyConstructor: Uncommented Empty Constructor finds instances where a constructor does not contain statements, but there is no comment. By explicitly commenting empty constructors it is easier to distinguish between intentional (commented) and unintentional empty constructors.

翻译  不含注释的空构造器:不含注释的空构造器就是说一个构造器内部没有任何程序代码也没有注释。通过明确的注释空构造器能够容易的区分有潜在意向的和无意向的空构造器

·  AvoidConstantsInterface: An interface should be used only to model a behaviour of a class: using an interface as a container of constants is a poor usage pattern.

翻译  避免常量接口:接口仅仅是应该用来建模类的行为的:使用接口作为常量的容器是一种劣质的用法。

·  UnsynchronizedStaticDateFormatter: SimpleDateFormat is not synchronized. Sun recomends separate format instances for each thread. If multiple threads must access a static formatter, the formatter must be synchronized either on method or block level.

翻译  不要同步静态的DateFormat类:SimpleDateFormat是非同步的。Sun公司建议对每个线程单独的format实例。如果多线程必须访问一个静态formatterformatter必须在方法或块级别同步。

代码示例:

public class Foo {

    private static final SimpleDateFormat sdf = new SimpleDateFormat();

    void bar() {

        sdf.format(); // bad

    }

    synchronized void foo() {

        sdf.format(); // good

    }

}

·  PreserveStackTrace: Throwing a new exception from a catch block without passing the original exception into the new exception will cause the true stack trace to be lost, and can make it difficult to debug effectively.

翻译  保留追踪栈:在一个catch块中抛出一个新的异常却不把原始的异常传递给新的异常会导致真正的追踪信息栈丢失,而且导致难以有效的调试。

代码示例:

public class Foo {

    void good() {

        try{

            Integer.parseInt("a");

        } catch(Exception e){

            throw new Exception(e);

        }

    }

    void bad() {

        try{

            Integer.parseInt("a");

        } catch(Exception e){

            throw new Exception(e.getMessage());

        }

    }

}

·  UseCollectionIsEmpty: The isEmpty() method on java.util.Collection is provided to see if a collection has any elements. Comparing the value of size() to 0 merely duplicates existing behavior.

翻译  使用集合类的isEmpty方法:java.util.Collection类的isEmpty方法提供判断一个集合类是否包含元素。不要是使用size()0比较来重复类库已经提供的方法。

public class Foo {

           void good() {

              List foo = getList();

                 if (foo.isEmpty()) {

                      // blah

                 }

          }

//下面是不推荐的方式

          void bad() {

              List foo = getList();

                      if (foo.size() == 0) {

                            // blah

                      }

                }

      }

·  ClassWithOnlyPrivateConstructorsShouldBeFinal: A class with only private constructors should be final, unless the private constructor is called by a inner class.

翻译  类只包含私有的构造器应该是final的:一个类只包含私有的构造器应该是final的,除非私有构造器被一个内部类访问。

public class Foo {  //Should be final

    private Foo() { }

}

·  EmptyMethodInAbstractClassShouldBeAbstract: An empty method in an abstract class should be abstract instead, as developer may rely on this empty implementation rather than code the appropriate one.

翻译  一个抽象类中的空方法也应该是抽象的:一个抽象类中的空方法也应该是抽象的,因为开发者有可能会信任这个空的实现而不去编写恰当的代码。

·  SingularField: This field is used in only one method and the first usage is assigning a value to the field. This probably means that the field can be changed to a local variable.

翻译  单数的域:域变量只在一个方法中被使用并且第一次使用时对这个域赋值。这种域可以改写为本地变量。

public class Foo {

    private int x;  //Why bother saving this?

    public void foo(int y) {

     x = y + 5;

     return x;

    }

}

·  ReturnEmptyArrayRatherThanNull: For any method that returns an array, it's a better behavior to return an empty array rather than a null reference.

翻译  返回空的数组而不要返回null:对于任何返回数组的方法,返回一个空的数组是一个比返回null引用更好的做法。

·  AbstractClassWithoutAnyMethod: If the abstract class does not provides any methods, it may be just a data container that is not to be instantiated. In this case, it's probably better to use a private or a protected constructor in order to prevent instantiation than make the class misleadingly abstract.

翻译  没有任何方法的抽象类:如果抽象类没有提供任何的方法,它可能只是一个不可被实例化的数据容器,在这种状况下,更好的方法是使用私有的或受保护的构造器以阻止实例化可以让类避免带有欺骗性的抽象。

·  TooFewBranchesForASwitchStatement: Switch are designed complex branches, and allow branches to share treatment. Using a switch for only a few branches is ill advised, as switches are not as easy to understand as if. In this case, it's most likely is a good idea to use a if statement instead, at least to increase code readability.

翻译  switch表达式带有太少的分支:switch表达式是被设计为处理复杂分支的,并且允许分支共享处理逻辑。对于较少分支的情况使用switch是不明智的,因为这样代码不易理解。因此,更好的主意是使用if表达式来代替,这样至少可以增加代码可读性。

Java Logging Rules

·  MoreThanOneLogger: Normally only one logger is used in each class.

翻译   多于一个日志记录器:一般而言一个日志记录器只用于一个类中。

·  LoggerIsNotStaticFinal: In most cases, the Logger can be declared static and final.

翻译   日志记录器不是static final的:大多数情况下,日志记录器应该被定义为static和final的

·  SystemPrintln: System.(out|err).print is used, consider using a logger.

翻译   SystemPrintln:如果发现代码当中使用了System.(out|err).print,应考虑使用日志记录代替

·  AvoidPrintStackTrace: Avoid printStackTrace(); use a logger call instead.

翻译   避免使用PrintStackTrace:避免使用printStackTrace();使用日志记录器代替。

String and StringBuffer Rules

·  AvoidDuplicateLiterals: Code containing duplicate String literals can usually be improved by declaring the String as a constant field.

翻译   避免重复的字面量:代码包含重复的字符串常常可以重构为将此字符串声明为常量

·  StringInstantiation: Avoid instantiating String objects; this is usually unnecessary.

翻译   字符串初始化:避免初始化字符串对象;这是不必要的。

·  StringToString: Avoid calling toString() on String objects; this is unnecessary.

翻译   String.toString():避免对字符串对象调用toString()方法,这是不必要的

·  InefficientStringBuffering: Avoid concatenating non literals in a StringBuffer constructor or append().

翻译   低效的StringBuffering:避免在StringBuffer的构造器或append()方法中连接非字面量类型

·  UnnecessaryCaseChange: Using equalsIgnoreCase() is faster than using toUpperCase/toLowerCase().equals()

翻译   不必要的大小写转换:使用equalsIgnoreCase()比将字符串大小写转换一致后再比较要快。

·  UseStringBufferLength: Use StringBuffer.length() to determine StringBuffer length rather than using StringBuffer.toString().equals("") or StringBuffer.toString().length() ==.

翻译   使用StringBuffer的length()方法:使用StringBuffer对象的length()方法来计算StringBuffer对象的长度,而不是使用StringBuffer.toString().equals("") or StringBuffer.toString().length() ==.等方法

·  AppendCharacterWithChar: Avoid concatenating characters as strings in StringBuffer.append.

翻译   用char类型连接字符:在使用StringBuffer的append()方法连接字符时,避免使用string类型。

·  ConsecutiveLiteralAppends: Consecutively calling StringBuffer.append with String literals

翻译   连续的字面量连接:连接字符串时连续的调用StringBuffer的append()方法

·  UseIndexOfChar: Use String.indexOf(char) when checking for the index of a single character; it executes faster.

翻译   使用indexOf(字符):当你检测单个字符的位置时使用String.indexOf(字符),它执行的很快。不要使用indexOf(字符串)

·  InefficientEmptyStringCheck: String.trim().length() is an inefficient way to check if a String is really empty, as it creates a new String object just to check its size. Consider creating a static function that loops through a string, checking Character.isWhitespace() on each character and returning false if a non-whitespace character is found.

翻译   低效的空字符串检查:用String.trim().length()来判断字符串是否空是低效的做法,因为它会创建一个新的字符串对象然后判断大小。考虑创建一个静态的方法循环String,用isWhitespace()检查每个字符如果遇到非空白字符就返回false

·  InsufficientStringBufferDeclaration: Failing to pre-size a StringBuffer properly could cause it to re-size many times during runtime. This rule checks the characters that are actually passed into StringBuffer.append(), but represents a best guess "worst case" scenario. An empty StringBuffer constructor initializes the object to 16 characters. This default is assumed if the length of the constructor can not be determined.

翻译   不充分的StringBuffer声明:如果不能在事前声明合适大小的StringBuffer容量可能导致运行期不断地重新分配大小。本规则检查字符事实上传递给StringBuffer.append(),但是表明了在最坏情况下的最好的预测。空参数的StringBuffer构造器默认将对象初始化为16个字符的容量。这个默认情况是在构造长度无法确定的情况下假定的。

·  UselessStringValueOf: No need to call String.valueOf to append to a string; just use the valueOf() argument directly.

翻译   无用的valueOf方法:调用append()方法时不需要把参数用valueOf()转换一次,直接将非String类型的值作为参数放在append()里面。

·  StringBufferInstantiationWithChar: StringBuffer sb = new StringBuffer('c'); The char will be converted into int to intialize StringBuffer size.

翻译   StringBuffer使用字符初始化:StringBuffer sb = new StringBuffer('c');字符c会转换为int值,作为StringBuffer的初始化大小参数。

·  UseEqualsToCompareStrings: Using '==' or '!=' to compare strings only works if intern version is used on both sides

翻译   使用equals方法比较字符串:使用‘==’或‘!=’比较字符串大小只是比较两边的常量池的引用。

·  AvoidStringBufferField: StringBuffers can grow quite a lot, and so may become a source of memory leak (if the owning class has a long life time).

翻译   避免在类中使用StringBuffer属性:StringBuffer类型变量可以变得非常庞大,所以可能造成内存泄漏。(如果宿主类有很长的生命期)

Braces Rules

·  IfStmtsMustUseBraces: Avoid using if statements without using curly braces.

翻译  if块必须用括号:避免使用if块时不使用花括号{}

·  WhileLoopsMustUseBraces: Avoid using 'while' statements without using curly braces.

翻译  while循环必须使用括号:避免使用while块时不使用{}

·  IfElseStmtsMustUseBraces: Avoid using if..else statements without using curly braces.

翻译  if…else…块必须使用括号:避免使用if…else…块时不使用{}

·  ForLoopsMustUseBraces: Avoid using 'for' statements without using curly braces.

翻译  for循环必须使用括号:避免在for循环时不使用{}



参考:PMD规则之Design Rules

PMD规则之Java Logging Rules

PMD规则之Braces Rules


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值