转自:https://segmentfault.com/a/1190000020864572

一、Lombok 简介

Lombok 是一款 Java 开发插件,使得 Java 开发者可以通过其定义的一些注解来消除业务工程中冗长和繁琐的代码,尤其对于简单的 Java 模型对象(POJO)。在开发环境中使用 Lombok 插件后,Java 开发人员可以节省出重复构建,诸如 hashCode 和 equals 这样的方法以及各种业务对象模型的 accessor 和 toString 等方法的大量时间。对于这些方法,Lombok 能够在编译源代码期间自动帮我们生成这些方法,但并不会像反射那样降低程序的性能。

二、Lombok 安装

2.1 构建工具

Gradle

build.gradle 文件中添加 lombok 依赖:

dependencies {
compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
}
Maven

在 Maven 项目的 pom.xml 文件中添加 lombok 依赖:

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
Ant

假设在 lib 目录中已经存在 lombok.jar,然后设置 javac 任务:

<javac srcdir="src" destdir="build" source="1.8">
<classpath location="lib/lombok.jar" />
</javac>

2.2 IDE

由于 Lombok 仅在编译阶段生成代码,所以使用 Lombok 注解的源代码,在 IDE 中会被高亮显示错误,针对这个问题可以通过安装 IDE 对应的插件来解决。这里不详细展开,具体的安装方式可以参考 Setting up Lombok with Eclipse and IntelliJ 这篇文章。

三、Lombok 详解

注意:以下示例所使用的 Lombok 版本是 1.18.10

3.1 @Getter and @Setter 注解

你可以使用 @Getter@Setter 注释任何类或字段,Lombok 会自动生成默认的 getter/setter 方法。

@Getter 注解
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Getter {
// 若getter方法非public的话,可以设置可访问级别
lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC;
AnyAnnotation[] onMethod() default {};
// 是否启用延迟初始化
boolean lazy() default false;
}
@Setter 注解
@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Setter {
// 若setter方法非public的话,可以设置可访问级别
lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC;
AnyAnnotation[] onMethod() default {};
AnyAnnotation[] onParam() default {};
}
使用示例
package com.semlinker.lombok;

@Getter
@Setter
public class GetterAndSetterDemo {
String firstName;
String lastName;
LocalDate dateOfBirth;
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class GetterAndSetterDemo {
String firstName;
String lastName;
LocalDate dateOfBirth; public GetterAndSetterDemo() {
} // 省略其它setter和getter方法
public String getFirstName() {
return this.firstName;
} public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
Lazy Getter

@Getter 注解支持一个 lazy 属性,该属性默认为 false。当设置为 true 时,会启用延迟初始化,即当首次调用 getter 方法时才进行初始化。

示例
package com.semlinker.lombok;

public class LazyGetterDemo {
public static void main(String[] args) {
LazyGetterDemo m = new LazyGetterDemo();
System.out.println("Main instance is created");
m.getLazy();
} @Getter
private final String notLazy = createValue("not lazy"); @Getter(lazy = true)
private final String lazy = createValue("lazy"); private String createValue(String name) {
System.out.println("createValue(" + name + ")");
return null;
}
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class LazyGetterDemo {
private final String notLazy = this.createValue("not lazy");
private final AtomicReference<Object> lazy = new AtomicReference(); // 已省略部分代码
public String getNotLazy() {
return this.notLazy;
} public String getLazy() {
Object value = this.lazy.get();
if (value == null) {
synchronized(this.lazy) {
value = this.lazy.get();
if (value == null) {
String actualValue = this.createValue("lazy");
value = actualValue == null ? this.lazy : actualValue;
this.lazy.set(value);
}
}
} return (String)((String)(value == this.lazy ? null : value));
}
}

通过以上代码可知,调用 getLazy 方法时,若发现 value 为 null,则会在同步代码块中执行初始化操作。

3.2 Constructor Annotations

@NoArgsConstructor 注解

使用 @NoArgsConstructor 注解可以为指定类,生成默认的构造函数,@NoArgsConstructor 注解的定义如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface NoArgsConstructor {
// 若设置该属性,将会生成一个私有的构造函数且生成一个staticName指定的静态方法
String staticName() default "";
AnyAnnotation[] onConstructor() default {};
// 设置生成构造函数的访问级别,默认是public
AccessLevel access() default lombok.AccessLevel.PUBLIC;
// 若设置为true,则初始化所有final的字段为0/null/false
boolean force() default false;
}
示例
package com.semlinker.lombok;

@NoArgsConstructor(staticName = "getInstance")
public class NoArgsConstructorDemo {
private long id;
private String name;
private int age;
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class NoArgsConstructorDemo {
private long id;
private String name;
private int age; private NoArgsConstructorDemo() {
} public static NoArgsConstructorDemo getInstance() {
return new NoArgsConstructorDemo();
}
}
@AllArgsConstructor 注解

使用 @AllArgsConstructor 注解可以为指定类,生成包含所有成员的构造函数,@AllArgsConstructor 注解的定义如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface AllArgsConstructor {
// 若设置该属性,将会生成一个私有的构造函数且生成一个staticName指定的静态方法
String staticName() default "";
AnyAnnotation[] onConstructor() default {};
// 设置生成构造函数的访问级别,默认是public
AccessLevel access() default lombok.AccessLevel.PUBLIC;
}
示例
package com.semlinker.lombok;

@AllArgsConstructor
public class AllArgsConstructorDemo {
private long id;
private String name;
private int age;
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class AllArgsConstructorDemo {
private long id;
private String name;
private int age; public AllArgsConstructorDemo(long id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
}
@RequiredArgsConstructorDemo 注解

使用 @RequiredArgsConstructor 注解可以为指定类必需初始化的成员变量,如 final 成员变量,生成对应的构造函数,@RequiredArgsConstructor 注解的定义如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface RequiredArgsConstructor {
// 若设置该属性,将会生成一个私有的构造函数且生成一个staticName指定的静态方法
String staticName() default "";
AnyAnnotation[] onConstructor() default {};
// 设置生成构造函数的访问级别,默认是public
AccessLevel access() default lombok.AccessLevel.PUBLIC;
}
示例
package com.semlinker.lombok;

@RequiredArgsConstructor
public class RequiredArgsConstructorDemo {
private final long id;
private String name;
private int age;
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class RequiredArgsConstructorDemo {
private final long id;
private String name;
private int age; public RequiredArgsConstructorDemo(long id) {
this.id = id;
}
}

3.3 @EqualsAndHashCode 注解

使用 @EqualsAndHashCode 注解可以为指定类生成 equals 和 hashCode 方法, @EqualsAndHashCode 注解的定义如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface EqualsAndHashCode {
// 指定在生成的equals和hashCode方法中需要排除的字段列表
String[] exclude() default {}; // 显式列出用于identity的字段,一般情况下non-static,non-transient字段会被用于identity
String[] of() default {}; // 标识在执行字段计算前,是否调用父类的equals和hashCode方法
boolean callSuper() default false; boolean doNotUseGetters() default false; AnyAnnotation[] onParam() default {}; @Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
@interface AnyAnnotation {} @Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude {} @Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {
String replaces() default "";
}
}
示例
package com.semlinker.lombok;

@EqualsAndHashCode
public class EqualsAndHashCodeDemo {
String firstName;
String lastName;
LocalDate dateOfBirth;
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class EqualsAndHashCodeDemo {
String firstName;
String lastName;
LocalDate dateOfBirth; public EqualsAndHashCodeDemo() {
} public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof EqualsAndHashCodeDemo)) {
return false;
} else {
EqualsAndHashCodeDemo other = (EqualsAndHashCodeDemo)o;
if (!other.canEqual(this)) {
return false;
} else {
// 已省略大量代码
}
} public int hashCode() {
int PRIME = true;
int result = 1;
Object $firstName = this.firstName;
int result = result * 59 + ($firstName == null ? 43 : $firstName.hashCode());
Object $lastName = this.lastName;
result = result * 59 + ($lastName == null ? 43 : $lastName.hashCode());
Object $dateOfBirth = this.dateOfBirth;
result = result * 59 + ($dateOfBirth == null ? 43 : $dateOfBirth.hashCode());
return result;
}
}

3.4 @ToString 注解

使用 @ToString 注解可以为指定类生成 toString 方法, @ToString 注解的定义如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface ToString {
// 打印输出时是否包含字段的名称
boolean includeFieldNames() default true; // 列出打印输出时,需要排除的字段列表
String[] exclude() default {}; // 显式的列出需要打印输出的字段列表
String[] of() default {}; // 打印输出的结果中是否包含父类的toString方法的返回结果
boolean callSuper() default false; boolean doNotUseGetters() default false; boolean onlyExplicitlyIncluded() default false; @Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude {} @Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {
int rank() default 0;
String name() default "";
}
}
示例
package com.semlinker.lombok;

@ToString(exclude = {"dateOfBirth"})
public class ToStringDemo {
String firstName;
String lastName;
LocalDate dateOfBirth;
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class ToStringDemo {
String firstName;
String lastName;
LocalDate dateOfBirth; public ToStringDemo() {
} public String toString() {
return "ToStringDemo(firstName=" + this.firstName + ", lastName=" +
this.lastName + ")";
}
}

3.5 @Data 注解

@Data 注解与同时使用以下的注解的效果是一样的:

  • @ToString
  • @Getter
  • @Setter
  • @RequiredArgsConstructor
  • @EqualsAndHashCode

@Data 注解的定义如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Data {
String staticConstructor() default "";
}
示例
package com.semlinker.lombok;

@Data
public class DataDemo {
private Long id;
private String summary;
private String description;
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class DataDemo {
private Long id;
private String summary;
private String description; public DataDemo() {
} // 省略summary和description成员属性的setter和getter方法
public Long getId() {
return this.id;
} public void setId(Long id) {
this.id = id;
} public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof DataDemo)) {
return false;
} else {
DataDemo other = (DataDemo)o;
if (!other.canEqual(this)) {
return false;
} else {
// 已省略大量代码
}
}
} protected boolean canEqual(Object other) {
return other instanceof DataDemo;
} public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $summary = this.getSummary();
result = result * 59 + ($summary == null ? 43 : $summary.hashCode());
Object $description = this.getDescription();
result = result * 59 + ($description == null ? 43 : $description.hashCode());
return result;
} public String toString() {
return "DataDemo(id=" + this.getId() + ", summary=" + this.getSummary() + ", description=" + this.getDescription() + ")";
}
}

3.6 @Log 注解

若你将 @Log 的变体放在类上(适用于你所使用的日志记录系统的任何一种);之后,你将拥有一个静态的 final log 字段,然后你就可以使用该字段来输出日志。

@Log
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
@CommonsLog
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

3.7 @Synchronized 注解

@Synchronized 是同步方法修饰符的更安全的变体。与 synchronized 一样,该注解只能应用在静态和实例方法上。它的操作类似于 synchronized 关键字,但是它锁定在不同的对象上。 synchronized 关键字应用在实例方法时,锁定的是 this 对象,而应用在静态方法上锁定的是类对象。对于 @Synchronized 注解声明的方法来说,它锁定的是 $LOCK$lock@Synchronized 注解的定义如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Synchronized {
// 指定锁定的字段名称
String value() default "";
}
示例
package com.semlinker.lombok;

public class SynchronizedDemo {
private final Object readLock = new Object(); @Synchronized
public static void hello() {
System.out.println("world");
} @Synchronized
public int answerToLife() {
return 42;
} @Synchronized("readLock")
public void foo() {
System.out.println("bar");
}
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class SynchronizedDemo {
private static final Object $LOCK = new Object[0];
private final Object $lock = new Object[0];
private final Object readLock = new Object(); public SynchronizedDemo() {
} public static void hello() {
synchronized($LOCK) {
System.out.println("world");
}
} public int answerToLife() {
synchronized(this.$lock) {
return 42;
}
} public void foo() {
synchronized(this.readLock) {
System.out.println("bar");
}
}
}

3.8 @Builder 注解

使用 @Builder 注解可以为指定类实现建造者模式,该注解可以放在类、构造函数或方法上。@Builder 注解的定义如下:

@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(SOURCE)
public @interface Builder {
@Target(FIELD)
@Retention(SOURCE)
public @interface Default {} // 创建新的builder实例的方法名称
String builderMethodName() default "builder";
// 创建Builder注解类对应实例的方法名称
String buildMethodName() default "build";
// builder类的名称
String builderClassName() default ""; boolean toBuilder() default false; AccessLevel access() default lombok.AccessLevel.PUBLIC; @Target({FIELD, PARAMETER})
@Retention(SOURCE)
public @interface ObtainVia {
String field() default "";
String method() default "";
boolean isStatic() default false;
}
}
示例
package com.semlinker.lombok;

@Builder
public class BuilderDemo {
private final String firstname;
private final String lastname;
private final String email;
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class BuilderDemo {
private final String firstname;
private final String lastname;
private final String email; BuilderDemo(String firstname, String lastname, String email) {
this.firstname = firstname;
this.lastname = lastname;
this.email = email;
} public static BuilderDemo.BuilderDemoBuilder builder() {
return new BuilderDemo.BuilderDemoBuilder();
} public static class BuilderDemoBuilder {
private String firstname;
private String lastname;
private String email; BuilderDemoBuilder() {
} public BuilderDemo.BuilderDemoBuilder firstname(String firstname) {
this.firstname = firstname;
return this;
} public BuilderDemo.BuilderDemoBuilder lastname(String lastname) {
this.lastname = lastname;
return this;
} public BuilderDemo.BuilderDemoBuilder email(String email) {
this.email = email;
return this;
} public BuilderDemo build() {
return new BuilderDemo(this.firstname, this.lastname, this.email);
} public String toString() {
return "BuilderDemo.BuilderDemoBuilder(firstname=" + this.firstname + ", lastname=" + this.lastname + ", email=" + this.email + ")";
}
}
}

3.9 @SneakyThrows 注解

@SneakyThrows 注解用于自动抛出已检查的异常,而无需在方法中使用 throw 语句显式抛出。@SneakyThrows 注解的定义如下:

@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.SOURCE)
public @interface SneakyThrows {
// 设置你希望向上抛的异常类
Class<? extends Throwable>[] value() default java.lang.Throwable.class;
}
示例
package com.semlinker.lombok;

public class SneakyThrowsDemo {
@SneakyThrows
@Override
protected Object clone() {
return super.clone();
}
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class SneakyThrowsDemo {
public SneakyThrowsDemo() {
} protected Object clone() {
try {
return super.clone();
} catch (Throwable var2) {
throw var2;
}
}
}

3.10 @NonNull 注解

你可以在方法或构造函数的参数上使用 @NonNull 注解,它将会为你自动生成非空校验语句。 @NonNull 注解的定义如下:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE})
@Retention(RetentionPolicy.CLASS)
@Documented
public @interface NonNull {
}
示例
package com.semlinker.lombok;

public class NonNullDemo {
@Getter
@Setter
@NonNull
private String name;
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class NonNullDemo {
@NonNull
private String name; public NonNullDemo() {
} @NonNull
public String getName() {
return this.name;
} public void setName(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked non-null but is null");
} else {
this.name = name;
}
}
}

3.11 @Clean 注解

@Clean 注解用于自动管理资源,用在局部变量之前,在当前变量范围内即将执行完毕退出之前会自动清理资源,自动生成 try-finally 这样的代码来关闭流。

@Target(ElementType.LOCAL_VARIABLE)
@Retention(RetentionPolicy.SOURCE)
public @interface Cleanup {
// 设置用于执行资源清理/回收的方法名称,对应方法不能包含任何参数,默认名称为close。
String value() default "close";
}
示例
package com.semlinker.lombok;

public class CleanupDemo {
public static void main(String[] args) throws IOException {
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
}
}

以上代码经过 Lombok 编译后,会生成如下代码:

package com.semlinker.lombok;

public class CleanupDemo {
public CleanupDemo() {
} public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream(args[0]); try {
FileOutputStream out = new FileOutputStream(args[1]); try {
byte[] b = new byte[10000]; while(true) {
int r = in.read(b);
if (r == -1) {
return;
} out.write(b, 0, r);
}
} finally {
if (Collections.singletonList(out).get(0) != null) {
out.close();
} }
} finally {
if (Collections.singletonList(in).get(0) != null) {
in.close();
}
}
}
}

3.11 @With 注解

在类的字段上应用 @With 注解之后,将会自动生成一个 withFieldName(newValue) 的方法,该方法会基于 newValue 调用相应构造函数,创建一个当前类对应的实例。 @With 注解的定义如下:

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface With {
AccessLevel value() default AccessLevel.PUBLIC; With.AnyAnnotation[] onMethod() default {}; With.AnyAnnotation[] onParam() default {}; @Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
public @interface AnyAnnotation {
}
}
示例
public class WithDemo {
@With(AccessLevel.PROTECTED)
@NonNull
private final String name;
@With
private final int age; public WithDemo(String name, int age) {
if (name == null) throw new NullPointerException();
this.name = name;
this.age = age;
}
}

以上代码经过 Lombok 编译后,会生成如下代码:

public class WithDemo {
@NonNull
private final String name;
private final int age; public WithDemo(String name, int age) {
if (name == null) {
throw new NullPointerException();
} else {
this.name = name;
this.age = age;
}
} protected WithDemo withName(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked non-null but is null");
} else {
return this.name == name ? this : new WithDemo(name, this.age);
}
} public WithDemo withAge(int age) {
return this.age == age ? this : new WithDemo(this.name, age);
}
}

3.12 其它特性

val

val 用在局部变量前面,相当于将变量声明为 final,此外 Lombok 在编译时还会自动进行类型推断。val 的使用示例:

public class ValExample {
public String example() {
val example = new ArrayList<String>();
example.add("Hello, World!");
val foo = example.get(0);
return foo.toLowerCase();
} public void example2() {
val map = new HashMap<Integer, String>();
map.put(0, "zero");
map.put(5, "five");
for (val entry : map.entrySet()) {
System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());
}
}
}

以上代码等价于:

public class ValExample {
public String example() {
final ArrayList<String> example = new ArrayList<String>();
example.add("Hello, World!");
final String foo = example.get(0);
return foo.toLowerCase();
} public void example2() {
final HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(0, "zero");
map.put(5, "five");
for (final Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());
}
}
}

至此功能强大的 Lombok 工具就介绍完了。若你对于它的实现原理感兴趣的话,建议阅读猿码道大佬 十分钟搞懂Lombok使用与原理 这篇文章。

示例项目地址:Github - springboot2-lombok

四、参考资源

Lombok 学习指南的更多相关文章

  1. Civil 3D API二次开发学习指南

    Civil 3D构建于AutoCAD 和 Map 3D之上,在学习Civil 3D API二次开发之前,您至少需要了解AutoCAD API的二次开发,你可以参考AutoCAD .NET API二次开 ...

  2. 笔记——shell脚本学习指南

    <shell脚本学习指南>机械工业出版 ISBN 987-7-111-25504-8 第2章 2.4 初级陷阱 1.当今的系统,对#!这一行的长度限制从63到1024个字符都有,尽量不要超 ...

  3. 《Spring MVC学习指南》怎么样?答:书名具有很大的欺骗性

    2016年6月21日 最近,因为工作需要,我从网上买了一本<Spring MVC学习指南>,ISBN编号: 978-7-115-38639-7,定价:49.00元.此书是[美]Paul D ...

  4. [go语言学习指南]

    内部分享,根据自己的经验,收集汇总的go语言学习指南. 适合新手入门. 可以通过这里进行下载.

  5. Oracle学习指南

    Oracle学习指南 你走的那天,我决定不落泪,迎着风撑着眼帘用力不眨眼 创建数据库.创建用户.创建表空间.创建表.插入数据..... 1.用系统用户登录,任选系统用户 代码: >>sql ...

  6. 推荐10个很棒的AngularJS学习指南

    AngularJS 是非常棒的JS框架,能够创建功能强大,动态功能的Web app.AngularJS自2009发布以来,已经广泛应用于Web 开发中.但是对想要学习Angular JS 的人而言,只 ...

  7. 项目管理之道--纪我的新书《PMP项目管理认证学习指南(第4版)》出版并预祝大卖!

    新年伊始,我最新的项目管理书籍——<PMP项目管理认证学习指南(第4版)>也出版了,真是新年新气象啊!翻译英文书籍是一件任重道远的工作,除了要具备扎实的基本功,熟悉相关的领域外,还需要细致 ...

  8. Gulp学习指南之CSS合并、压缩与MD5命名及路径替换(转载)

    本文转载自: Gulp学习指南之CSS合并.压缩与MD5命名及路径替换

  9. Android Wear(手表)开发 - 学习指南

    版权声明:欢迎自由转载-非商用-非衍生-保持署名.作者:Benhero,博客地址:http://www.cnblogs.com/benhero/ Android Wear开发 - 学习指南 http: ...

随机推荐

  1. OpenCV 在VS2013的安装

    现在就介绍下如何在VS2013上配置openCV3.0的方法 如果是32位操作系统的:https://www.cnblogs.com/ssjie/p/4943439.html 1.下载openCV3. ...

  2. Python数据驱动DDT的应用

    在开始之前,我们先来明确一下什么是数据驱动,在百度百科中数据驱动的解释是:数据驱动测试,即黑盒测试(Black-box Testing),又称为功能测试,是把测试对象看作一个黑盒子.利用黑盒测试法进行 ...

  3. 标准C语言(5)

    无法预知的数字叫随机数,rand标准函数可以用来获得随机数,为了使用这个标准函数需要包含stdlib.h头文件 srand标准函数用来设置随机数种子,这个函数把一个整数作为种子使用不同的种子可以得到不 ...

  4. Mysql数据类型 来自官方手册5.6

    整形的取值范围:   定点数值(精确): 在MySQL中,NUMERIC被实现为DECIMAL,所以关于DECIMAL的以下说明同样适用于NUMERIC. MySQL以二进制格式存储DECIMAL值. ...

  5. Linux文件类型和文件相关命令

    文件类型 ll后可以看到文件详情: -:常规文件(内部类型是什么,用file命令) d:directory,目录文件 b:blobk device,块设备文件,支持以“block”为单位进行随机访问 ...

  6. Angular2 父子组件通信方式

    https://www.jb51.net/article/133868.htm 这次给大家带来Angular2 父子组件通信方式,使用Angular2 父子组件通信方式的注意事项有哪些,下面就是实战案 ...

  7. STM32CubeIDE查看内存使用情况

    按照下图操作 在右下角即可显示

  8. 【HDU6709】Fishing

    题目大意:有 N 条鱼,每条鱼都有钓鱼和烤鱼的时间,钓鱼的时间均相同,每条鱼都有自己的烤鱼时间,一次只能烤一条鱼,且不能间断.现要求通过某种顺序将所有的鱼钓上来并烤完,求最小的时间是多少. 题解: 对 ...

  9. python--Excel模块xlwings

    安装:pip install xlwings 基本操作: xlwings的特色: xlwings能够非常方便的读写Excel文件中的数据,并且能够进行单元格格式的修改 可以和matplotlib以及p ...

  10. mysql 递归查找所有子节点

    select dept_id from ( select t1.dept_id,t1.parent_id, if(find_in_set(parent_id, @pids) > 0, @pids ...