Java-入门学习
名称解释
- javaSE:是Java的基础。包含了基础的类库。主要用于程序开发。
- javaEE:扩展了javaSE,除了包含se的内容,还包含了web开发需要的一些基础包,例如selvlet等,他是一个抽象的规范,具体由应用服务器实现(如GlassFish、WildFly、WebLogic) 。主要用于web开发。
- SSM/SSH:架构已经过时,不建议学习
- Spring:是一个独立的框架,没有严格遵循"JavaEE规范",他替代并改进了JavaEE的许多部分,但是允许使用所有JavaEE技术。推荐学习
vscode设置
// java源码支持中文
"code-runner.executorMap": {
"java": "cd $dir && javac -encoding UTF-8 $fileName && java -Dfile.encoding=UTF-8 $fileNameWithoutExt",
},
第一个Java程序
public Test Hello {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
基础
// 一个程序只有一个这种入口
public static void main(String[] args) {
}
// println是print line的缩写
// 变量
StringBuilder sb = new StringBuilder();
// 编译器会根据赋值语句自动推断出变量sb的类型是StringBuilder
var sb = new StringBuilder();
// 实际上会自动变成:
StringBuilder sb = new StringBuilder();
构造方法
由于构造方法是如此特殊,所以构造方法的名称就是类名。构造方法的参数没有限制,在方法内部,也可以编写任意语句。但是,和普通方法相比,构造方法没有返回值(也没有
void
),调用构造方法,必须用new
操作符。类似python的init
// Person zaza = new Person("zaza", 18);
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
多构造方法
可以定义多个构造方法,在通过
new
操作符调用的时候,编译器通过构造方法的参数数量、位置和类型自动区分
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this.name = name;
this.age = 12;
}
public Person() {
}
}
方法重载
类似多个构造方法。方法重载的目的是,功能类似的方法使用同一名字,更容易记住,因此,调用起来更简单。泛型处理?
class Hello {
public void hello() {
System.out.println("Hello, world!");
}
public void hello(String name) {
System.out.println("Hello, " + name + "!");
}
public void hello(String name, int age) {
if (age < 18) {
System.out.println("Hi, " + name + "!");
} else {
System.out.println("Hello, " + name + "!");
}
}
}
静态字段
类似go的*类型,属于指针类型数据,多实例共享此数据。
虽然实例可以访问静态字段,但是它们指向的其实都是
Person class
的静态字段。所以,所有实例共享一个静态字段。
// 定义静态字段number:
public static int number;
静态方法
因为静态方法属于
class
而不属于实例,因此,静态方法内部,无法访问this
变量,也无法访问实例字段,它只能访问静态字段。
// 静态方法经常用于工具类。例如:
Arrays.sort()
Math.random()
遍历List
常见写法
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list = List.of("apple", "pear", "banana");
for (String s : list) {
System.out.println(s);
}
}
}
List和Array转换
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> list = List.of(12, 34, 56);
// toArray(T[]) 可以保证类型信息不丢失
Number[] array = list.toArray(new Number[list.size()]);
// 更简洁的方法:Integer[] array = list.toArray(Integer[]::new);
for (Number n : array) {
System.out.println(n);
}
}
初始化List对象并同时赋值
// java 8
private List<User> users = new ArrayList<User>() {{
add(new User(1, "zaza@163.com", "123456", "Zaza"));
add(new User(2, "yaya@163.com", "123456", "Yaya"));
add(new User(3, "xiaozhuang@163.com", "123456", "Xiaozhuang"));
}};
// java 11
private List<User> users = new ArrayList<>(List.of( // users:
new User(1, "bob@example.com", "password", "Bob"), // bob
new User(2, "alice@example.com", "password", "Alice"), // alice
new User(3, "tom@example.com", "password", "Tom"))); // tom
类
一个
.java
文件只能包含一个public
类,但可以包含多个非public
类。
classpath
在系统环境变量中设置
classpath
环境变量,不推荐;在启动JVM时设置
classpath
变量,推荐。更好的做法是,不要设置
classpath
!默认的当前目录.
对于绝大多数情况都够用了。
java -classpath .;C:\work\project1\bin;C:\shared abc.xyz.Hello
# 简写
java -cp .;C:\work\project1\bin;C:\shared abc.xyz.Hello
现在我们假设classpath
是.;C:\work\project1\bin;C:\shared
,当JVM在加载abc.xyz.Hello
这个类时,会依次查找:
- <当前目录>\abc\xyz\Hello.class
- C:\work\project1\bin\abc\xyz\Hello.class
- C:\shared\abc\xyz\Hello.class
不要把任何Java核心库添加到classpath中!JVM根本不依赖classpath加载核心库!
jar包
如果有很多.class
文件,散落在各层目录中,肯定不便于管理。如果能把目录打一个包,变成一个文件,就方便多了。
jar包就是用来干这个事的,它可以把package
组织的目录层级,以及各个目录下的所有文件(包括.class
文件和其他文件)都打成一个jar文件,这样一来,无论是备份,还是发给客户,就简单多了。
jar包实际上就是一个zip格式的压缩文件,而jar包相当于目录。如果我们要执行一个jar包的class
,就可以把jar包放到classpath
中:
java -cp ./hello.jar abc.xyz.Hello
java包运行原理
jar包还可以包含一个特殊的
/META-INF/MANIFEST.MF
文件,MANIFEST.MF
是纯文本,可以指定Main-Class
和其它信息。JVM会自动读取这个MANIFEST.MF
文件,如果存在Main-Class
,我们就不必在命令行指定启动的类名,而是用更方便的命令:
java -jar hello.jar
JavaBean
如果读写方法符合以下这种命名规范,那么这种
class
被称为JavaBean
:
// 读方法:
public Type getXyz()
// 写方法:
public void setXyz(Type value)
vscode插件
- Extension Pack for JavaPreview
- Doxygen Documentation Generator
- Todo Tree
jar包
方案一
# javac 变成成二进制class文件
# -d 指定生成class的根目录
# -verbose 打印模式
# -classpath 指定依赖包(需要完整路径) linux为冒号,windows为分号
javac -classpath /root/javaTest/lib/amqp-client-5.7.1.jar:/root/javaTest/lib/slf4j-api-1.7.26.jar:/root/javaTest/lib/slf4j-simple-1.7.26.jar -d ../bin/ -verbose com/zaza/ops/main/App.java ./com/zaza/ops/person/Student.java
# 打包(e参数直接指定入库main函数)
jar -cvfe hello.jar com.zaza.main.App -C bin/ .
# 查看class加载信息(-verbose:class)
# java -verbose:class -cp /root/javaTest/lib/amqp-client-5.7.1.jar -jar hello.jar
java -verbose:class -jar hello.jar
# 运行指定依赖的jar包(注意发布的时候需要将lib目录一同发布)
java -Xbootclasspath/a:lib/amqp-client-5.7.1.jar:lib/slf4j-api-1.7.26.jar:lib/slf4j-simple-1.7.26.jar -jar hello.jar
方案二(推荐)
不用包管理工具的最佳实践
# javac 变成成二进制class文件
# -d 指定生成class的根目录
# -verbose 打印 class 加载
# -classpath 指定依赖包(需要完整路径) linux为冒号,windows为分号
# 需要指定所有java源码依赖文件,否则报错
cd src && mkdir -pv ../bin/
# javac -verbose -classpath /root/javaTest/lib/amqp-client-5.7.1.jar:/root/javaTest/lib/slf4j-api-1.7.26.jar:/root/javaTest/lib/slf4j-simple-1.7.26.jar -d ../bin/ com/zaza/ops/*/*.java
javac -classpath /root/javaTest/lib/amqp-client-5.7.1.jar:/root/javaTest/lib/slf4j-api-1.7.26.jar:/root/javaTest/lib/slf4j-simple-1.7.26.jar -d ../bin/ com/zaza/ops/*/*.java
# 打包
# 根据需求创建入口函数和依赖包信息
# 其它信息会自动创建,如:Manifest-Version、Created-By
echo 'Main-Class: com.zaza.main.App' > Manifest.txt
echo 'Class-Path: lib/amqp-client-5.7.1.jar lib/slf4j-api-1.7.26.jar lib/slf4j-simple-1.7.26.jar' >> Manifest.txt
# m指定Manifest文件
jar -cvfm hello.jar Manifest.txt -C bin/ .
# 查看class加载信息(-verbose:class)
java -verbose:class -jar hello.jar
# 直接运行
java -jar hello.jar
# 添加参数运行
# java -Dlog4j2.formatMsgNoLookups=true -Xms512m -Xmx512m -jar hello.jar --logging.config=./log4j2-spring.xml
方案三(推荐)
建议使用 Maven 帮助我们管理构建(可以方便的打JAR包)
Maven
jar包构建
安装
D:\Program Files\maven
# 新建环境变量
# MAVEN_HOME,赋值 D:\Program Files\maven
# 编辑环境变量Path,追加
# %MAVEN_HOME%\bin
镜像配置
~/.m2/settings.xml
依赖包保存目录:~/.m2/repository
<settings>
<mirrors>
<mirror>
<id>aliyun</id>
<name>aliyun</name>
<mirrorOf>central</mirrorOf>
<!-- 国内推荐阿里云的Maven镜像 -->
<url>https://maven.aliyun.com/repository/central</url>
</mirror>
</mirrors>
</settings>
命名规则
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<groupId>com.qcloud</groupId>
<artifactId>cos_migrate_tool</artifactId> <!-- 不是很标准? -->
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<!-- 拥有父ID的,druid是apache下面的一个子项目 -->
<parent>
<groupId>org.apache</groupId>
<artifactId>apache</artifactId>
<version>21</version>
</parent>
<groupId>org.apache.druid</groupId>
<artifactId>druid</artifactId>
<!-- 拥有父ID的,druid是apache下面的一个子项目 -->
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<!-- 带版本信息? -->
<groupId>org.apache.spark</groupId>
<artifactId>spark-parent_2.12</artifactId>
创建项目
Maven Quickstart Archetype-实例指定了版本
建议使用命令:mvn archetype:generate -DarchetypeVersion=“1.4”,这样会使用最新版本的配置创建pom.xml
# 需要指定参数:-DarchetypeVersion="1.4",这样才会显式的生成 build 配置信息
# 否则生成的配置是老版本的:project created from Old (1.x) Archetype
# 优势:这样可以动态的调整编译插件的版本:maven-xxx-plugin
# 交互式创建:mvn archetype:generate -DarchetypeVersion="1.4"
# archetype建议使用默认版本(内容最精简,后续一步一步的配置,熟悉后生成自己的pom.xml即可)
mvn archetype:generate -DarchetypeVersion="1.4" -DarchetypeArtifactId="maven-archetype-quickstart" -DinteractiveMode="false" -DgroupId="com.zaza" -DartifactId="xstack-agent"
# jdk修改成1.8
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
# 改成
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
# vscode 创建(建议使用此方法创建):
# ctrl+shift+p 输入:>create java --> Maven --> 选择:maven-archetype-quickstart
# 这里pom.xml多了build编译的插件信息:maven-xxx-plugin (影响参数:-DarchetypeVersion="1.4")
# vscode 实际创建命令:
# mvn org.apache.maven.plugins:maven-archetype-plugin:3.1.2:generate -DarchetypeArtifactId="maven-archetype-quickstart" -DarchetypeGroupId="org.apache.maven.archetypes" -DarchetypeVersion="1.4" -DgroupId="com.example" -DartifactId="demo"
插件搜索
还可以查看每个插件的pom文件内容
“Latest Version” “Updated” 之间有一个版本数量点击进去,再点击对应的"Version"后,左上角就有:Apache Maven的dependency相关内容
Maven Central Repository Search
打包插件
打包:我们日常使用的以maven-assembly-plugin为最多,因为大数据项目中往往有很多shell脚本、SQL脚本、.properties及.xml配置项等,采用assembly插件可以让输出的结构清晰而标准化。
参考:https://github.com/tencentyun/cos_migrate_tool_v5/blob/master/pom.xml
<!-- 依赖信息:dependencies下不用配置 -->
<!-- 编译配置,注意不要配置到:build->pluginManagement下面了 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- <descriptor>src/main/assembly/assembly.xml</descriptor> -->
<finalName>${project.name}</finalName>
<descriptorRefs>
<!-- 将依赖的jar打入目标jar包,这样可以实现jar单包而不需要拷贝lib包 -->
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.zaza.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
log4j2插件
安装
使用最新版本,log4j出了远程执行的严重漏洞
Log4j – Maven, Ivy, Gradle, and SBT Artifacts (apache.org)
最佳实践
在开发阶段,始终使用Commons Logging接口来写入日志,并且开发阶段无需引入Log4j。如果需要把日志写入文件, 只需要把正确的配置文件和Log4j相关的jar包放入
classpath
,就可以自动把日志切换成使用Log4j写入,无需修改任何代码。
- log4j-jcl:commons-logging到log4j2的桥梁 (Commons Logging是一个第三方提供的库),默认common-logging会自动检查是否使用log4j
- JDK自带的Logging其实是一个鸡肋,竟然没有debug的日志级别,差评。。。
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<!-- 这个是依赖包:SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.17.1</version>
</dependency>
<!-- commons-logging到log4j2的桥梁 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jcl</artifactId>
<version>2.17.1</version>
</dependency>
</dependencies>
properties配置
Log4j – Configuring Log4j 2 (apache.org)
log4j 1.x 默认路径:src/main/resources/log4j.properties
log4j 2.x 默认路径:src/main/resources/log4j2.properties
status = error
dest = err
name = PropertiesConfig
property.filename = logs/rollingtest.log
filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %d [%-5p] [%t:%r] [%c:%x] [%F:%L] %m%n
appender.console.filter.threshold.type = ThresholdFilter
appender.console.filter.threshold.level = debug
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = ${filename}
# appender.rolling.filePattern = target/rolling2/test1-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.rolling.filePattern = logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.charset = UTF-8
# appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n ==> # 2022-01-11 04:10:43,304 ERROR c.e.App [main] 严重信息
# 2022-01-11 04:10:58 [INFO ] [main:1176] [com.example.App:[]] [App.java:16] 一般信息
appender.rolling.layout.pattern = %d [%-5p] [%t:%r] [%c:%x] [%F:%L] %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 2
appender.rolling.policies.time.modulate = true
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size = 100MB
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 10
logger.rolling.name = com.example.App
logger.rolling.level = debug
logger.rolling.additivity = false
logger.rolling.appenderRef.rolling.ref = RollingFile
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT
log4j2示例代码
package com.example;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Hello world!
*
*/
public class App {
private static final Log log = LogFactory.getLog(App.class);
public static void main(String[] args) {
log.info("一般信息");
log.warn("警示信息");
log.error("严重信息");
}
}
日志格式
# Log4j2 的日志格式
17:24:11.194 [main] ERROR com.zaza.app.App - 严重信息
# commons-logging 的日志格式
Jan 11, 2022 4:17:40 AM com.example.App main
SEVERE: 严重信息
SLF4J+Logback插件
- 从目前的趋势来看,越来越多的开源项目从Commons Logging加Log4j转向了SLF4J加Logback。 QOS.CH (Switzerland)-使用率对比
- Logback是由log4j创始人设计的另一个开源日志组件,官方网站: http://logback.qos.ch。
- SprintBoot 默认使用此方案
安装
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.10</version>
<!-- <scope>test</scope> 注意注释这行-->
</dependency>
logback配置
保存路径:src/main/resources/logback.xml
运行使用自定义配置:java -Dlogback.configurationFile =/path/to/config.xml
SpringBoot 日志 logback-spring.xml 配置技巧:使用 springProfile 分环境打印日志到不同目标-很不错
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- property :用来定义变量值 -->
<property name="PATTERN" value="[%d{yyyy-MM-dd HH:mm:ss SSS}] [%X] [%-5p] %logger{0}.%M\\(%L\\) - %msg%n" />
<property name="LOG_HOME" value="logs" />
<!-- 输出到控制台 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<!-- 输出到文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/log-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 日志保留天数 -->
<MaxHistory>100</MaxHistory>
<!-- 日志文件最大值 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder>
<charset>UTF-8</charset>
<pattern>${PATTERN}</pattern>
</encoder>
</appender>
<logger name="com.example.App"/>
<root level="trace">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration>
示例代码
package com.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Hello world!
*
*/
public class App {
final static Logger logger = LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
logger.trace("logback 成功了");
logger.debug("logback 成功了");
logger.info("logback 成功了");
logger.warn("logback {}", "成功了");
logger.error("logback 成功了");
}
}
mysql插件
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
rabbitmq插件
根据需求添加
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.14.0</version>
</dependency>
打jar包
# 代码规范校验
mvn checkstyle::check
# 关闭校验:<skip>${skipTests}</skip> 改成:<skip>true</skip>
# 打包
# mvn assembly:single
mvn package
Nexus私有仓库
常见地址
# 中央仓库客户端请求的时候,自动缓存
http://localhost:8081/repository/maven-central/
# 私有快照
http://localhost:8081/repository/maven-snapshots/
# 私有发布版本
http://localhost:8081/repository/maven-releases/
mvn配置
pom.xml
<project>
......
<distributionManagement>
<repository>
<id>zaza</id>
<name>Releases</name>
<url>http://localhost:8081/repository/maven-releases</url>
</repository>
<snapshotRepository>
<id>zaza</id>
<name>Snapshot</name>
<url>http://localhost:8081/repository/maven-snapshots</url>
</snapshotRepository>
</distributionManagement>
</project>
~/.m2/settings.xml
<settings>
<mirrors>
<mirror>
<id>zaza</id>
<name>zaza</name>
<mirrorOf>central</mirrorOf>
<!-- 国内推荐阿里云的Maven镜像 -->
<!-- <url>https://maven.aliyun.com/repository/central</url> -->
<url>http://localhost:8081/repository/maven-central/</url>
</mirror>
</mirrors>
<servers>
<server>
<id>zaza</id>
<username>admin</username>
<password>71382b73-942a-4328-99d2-0d83155fa83b</password>
</server>
</servers>
</settings>
发布
mvn deploy
# 快照版本 <version>1.0-SNAPSHOT</version>
# 正式版本 <version>1.0.0</version>
数据库连接池
JBoss 过时了
Druid或者HikariCP,建议Druid ? HikariCP?
spring
结构
- springframework 更名为 spring-core, spring-core 只依赖 Logging Bridge之spring-jcl
- spring 的 ioc 容器
- [spring 的 AOP
- web开发–spring-boot-starter-web
vscode扩展Spring Boot Extension Pack指定java版本
- Open Visual Studio Code
- CRTL + , to open the settings
- Search spring-boot.ls.java.home
- Select ‘Edit in settings.json’
- Your Java 11 installation → “spring-boot.ls.java.home”: “C:\Program Files\Java\jdk-17.0.2”
- Save and restart VS Code
- Prereq: Have a Java 11 installation
参考
- 原文作者:zaza
- 原文链接:https://zazayaya.github.io/2021/12/31/java-getting-started.html
- 说明:转载本站文章请标明出处,部分资源来源于网络,如有侵权请及时与我联系!