从0-1认识Java
简介
Java是面向对象编程。
Java语言基础包括数据类型和运算符、控制结构、数组、类和对象、异常处理、枚举和注解等;面向对象包括封装性、继承性、多态性、接口与抽象类、泛型与集合、多线程与并发编程等;
-
Java技术体系所包含的内容

-
Java语言发展状况

开发环境配置
下载JDK
下载地址 :www.oracle.com/technetwork/java/javase/downloads
-
Java术语

设置JDK
-
安装jdk
-
设置环境变量
-
测试: javac -version
-
JDK目录树

IDE使用
IntelliJ IDEA
新建项目
编辑区
运行
基本语法
一个简单的Java应用程序
public class FirstSample{
public static void main(String[] args) {
System.out.println("We will not use 'Hello, World!'");
}
}
注释
// 单行注释
/*
* 多行注释
*/
/**
* 文档注释
*/
Java基础知识
变量
// 变量初始化
int vacationDays = 12;
// 常量
final double CM_PER_INCH = 2.54;
运算符
// 加减乘除
+、-、*、/、+=
// 取模,自增、自减
%、i++、i--
// 位运算符
&、|、^、~
// 逻辑运算符
&&、||、!
数学函数
// 平方根、幂运算
double y = Math.sqrt(x);
double y = Math.pow(x,a);
// 三角函数
Math.sin
Math.cos
Math.tan
// 常量
Math.PI
Math.E
数值类型之间的转换

强制类型转换
double x = 9.997;
int nx = (int) x;
运算符优先级

类型
数据类型
整型
浮点类型
char类型
boolean类型
枚举
enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE };
注:若整型和浮点型精度不能满足要求,BigInteger类实现了任意精度的整数运算,BigDecimal类实现了任意精度的浮点数运算。
字符串
// 定义、初始化
String greeting = "Hello";
// 子串
String s = greeting.substring(0, 3)
// 拼接:+号连接2个字符串
String expletive = "Expletive";
String PG13 = "deleted";String message = expletive + PG13;
// 拼接:+号连接字符串与非字符串的值,后者被转化成为字符串
int age = 13;
String rating = "PC" + age;
// 将多个字符串用一个定界符分隔:静态join()方法
String all = String.join("/","S","M","L","XL");
String类对象为不可变字符串,没有提供用于修改字符串的方法,优点是:编译器可让字符串共享。
// 检测字符串是否相等
s.equals(t)
"Hello".equals(greeting)
API文档https://docs.oracle.com/javase/8/docs/api/
控制流程
条件语句
Demo:

if (yourSales >= 2 * target){
performance = "Excellent";
bonus = 1000;
}else if (yourSales >= 1.5 * target){
performance = "Fine";
bonus = 500;
}else if (yourSales >= target){
performance = "Satisfactory";
bonus = 100;
}else{
System.out.println("You're fired");
}
循环
-
while循环
格式:
// 先检测循环条件
while (condition) statement
// 至少执行一次,再检测循环条件
do statement while (condition);
Demo:

while(balance < goal){
balance += payment;
double interest = balance * interestRate / 100;
balance += interest;
years++;
}
-
for循环
格式:
// for循环
for(initialization; boolean_expression; update) statement
// foreach
for (variable : collection) statement
Demo:

for (int i = 1; i <= 10; i++)
System.out.println(i);
Demo:遍历数组
String[] names = new String[10];
for (int i = 0; i < 10; i++) names[i]="";
异常
-
Java程序运行期间可能出现的错误:
-
-
文件包含了错误信息
-
网络连接出现问题
-
无效的数组下标
-
使用没有被赋值的对象引用
-
……
-
-
如果出现错误而使某些操作没有完成,程序应该:
-
-
返回到一种安全状态,并能够让用户执行一些其他的命令
-
或允许用户保存所有操作的结果,并以妥善的方式终止程序
-
异常处理的任务:将控制权从错误产生的地方转移给能够处理这种情况的错误处理器
-
Java中的异常层次结构

抛出异常
抛出一个已经存在的异常类:
1)找到一个合适的异常类。
2)创建这个类的一个对象。
3)将对象抛出。
String readData(Scanner in) throws EOFException{
...
while (. . .) {
if (!in.hasNext()) { // EOF encountered
if (n < len)
throw new EOFException();
}
...
}
return s;
}
捕获异常
捕获异常:
try{
code
more code
more code
}catch (ExceptionType e){
handler for this type
}
捕获多个异常:
try{
code that might throw exceptions
}catch (FileNotFoundException e){
emergency action for missing files
}catch (UnknownHostException e){
emergency action for unknown hosts
}catch (IOException e){
emergency action for all other I/O problems
}
捕获后再次抛出:改变异常类型
{
access the database
}catch (SQLException e){
throw new ServletException ("database error: " + e.getMessage());
}
断言
作用:对条件进行检测,如果结果为false,抛出AssertionError异常。断言只应该用于在测试阶段确定程序内部的错误位置。
格式:
assert条件;
assert条件:表达式;
注解
-
注解类型
-
-
内建注解
-
-
@Override注解:表示该方法是重写父类的某方法
-
@Deprecated注解:表示已过时
-
@SuppressWarnings注解:阻止编译器警告
-
-
元注解
-
-
@Target注解:指定被其修饰的注解能用于修饰哪些程序元素
-
@Retention注解:描述了被其修饰的注解是否被编译器丢弃或者保留在class文件中
-
@Documented注解:指定被其修饰的注解将被JavaDoc工具提取成文档
-
@Inherited注解:指定被其修饰的注解将具有继承性
-
-
自定义注解
-
-
定义:public @interface AnnotationTest{}
-
-
-
读取注解信息
java.lang.reflect包提供了对读取运行时注解的支持,通过反射获取AnnotatedElement对象,调用以下3个方法可访问注解信息:
getAnnotation():获取指定类型的注解
getAnnotations():获取所有注解
isAnnotationPresent():那段是否包含指定类型的注解
-
D em o:
public class MyAnnotation{
//获取MyAnnotation类的getObjectInfo()方法的所有注解
Annotation[] arr=Class.forName("MyAnnotation").getMethod("getObjectInfo"). getAnnotations();
//遍历所有注解
for(Annotation an:arr){
System.out.println(an);
}
}
常用操作
数据驱动测试,每种数据源适合的场景:
1)测试数据的存放:推荐使用CSV或Excel作为数据源。
2)配置数据的存放:推荐使用Properties或YAML作为数据源。
3)跨项目共享测试数据或配置数据:推荐使用数据库作为数据源。
JUnit参数化测试
-
Demo:
pom.xml:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.6.0</version>
</dependency>
代码:
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class LoginForJUnit {
@ParameterizedTest
@ArgumentsSources(@ArgumentsSource(ArgumentsProviderClass.class))
void testCase_001(String url, String username, String password) throws InterruptedException {
ChromeDriver driver = new ChromeDriver();
driver.get(url);
driver.findElementByCssSelector("input[type='text']").sendKeys(username);
driver.findElementByCssSelector("input[type='password']").sendKeys(password);
driver.findElementByClassName("el-button").click();
TimeUnit.SECONDS.sleep(3);
assertEquals(username, driver.findElementByCssSelector("#nav > div:nth-child(2) > span").getText());
driver.quit();
}
static Stream<Arguments> methodSource() {
return Stream.of(
Arguments.of("http://localhost:9002/login", "zhangsan", "zhangsan123456"),
Arguments.of("http://localhost:9002/login", "lisi", "lisi123456")
);
}
@ParameterizedTest
@EnumSource(value = Role.class, names = {"GUEST", "USER"})
void testCase_002(Role role) {
assertNotNull(role);
}
enum Role {GUEST, USER, ADMIN}
}
文件读写
Demo:使用CSV文件进行数据驱动测试
Github: xiaoliuzi20180524/selenium-webdriverhttps://github.com/xiaoliuzi20180524/selenium-webdriver/tree/master/chapter9/src/main/java/com/data/demo
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @description 利用CSV文件做数据驱动测试
* @author rongrong
* @version 1.0
* @date 2020/6/27 13:22
*/
public class TestCSVData {
/**
* 读取csv文件
*
* @param filePath
* @return返回list集合
*/
public List<Map<String, String>> getCSVData(String filePath) {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
;
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(filePath);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader br = new BufferedReader(inputStreamReader);
//通过for循环遍历,将读取的每一行数据使用逗号进行分割并保存到map中
for (String line = br.readLine(); line != null; line = br.readLine()) {
Map<String, String> map = new HashMap<String, String>();
String key = line.split(",")[0];
String value = line.split(",")[1];
map.put("userName", key);
map.put("passWord", value);
//再将map对象放到list集合中
list.add(map);
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
@DataProvider
public Object[][] testCSVData() {
//读取csv文件数据,调用getCSVData()方法来获得测试的数据
List<Map<String, String>> result = getCSVData("d:\\data.csv");
Object[][] files = new Object[result.size()][];
//通过for循环遍历list,每一行的数据都会通过构造函数来进行初始化赋值
for (int i = 0; i < result.size(); i++) {
files[i] = new Object[]{result.get(i)};
}
return files;
}
@Test(dataProvider = "testCSVData")
public void testCSVData(Map<String, String> param) {
System.out.println(param.get("userName") + "\t" + param.get("passWord"));
}
}
MySQL
Demo:使用数据库作为数据源
Github: xiaoliuzi20180524/selenium-webdriverhttps://github.com/xiaoliuzi20180524/selenium-webdriver/tree/master/chapter9/src/main/java/com/data/demo
package com.data.demo;
import org.testng.annotations.Test;
import java.util.Map;
/**
* @description 读取mysql数据库
* @author rongrong
* @version 1.0
* @date 2020/6/27 14:22
*/
public class TestDbData extends DbDataHeleper {
@Test(dataProvider = "dbDataMethod")
public void testmethod1(Map<?, ?> param) {
System.out.println(param.get("username") + "\t" + param.get("passWord") + "\t" + param.get("remark"));
}
}
package com.data.demo;
import org.testng.annotations.DataProvider;
import java.sql.*;
import java.util.*;
/**
* @description 读取mysql数据库
* @author rongrong
* @version 1.0
* @date 2020/6/27 14:22
*/
public class DbDataHeleper {
static Connection conn = null;
public static String driverClassName = "com.mysql.jdbc.Driver";
public static String url = "jdbc:mysql://127.0.0.1:3306/demo?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull";
public static String username = "root";
public static String password = "root";
/**
* 执行sql
*
* @param jdbcUrl 数据库配置连接
* @param sql sql语句
* @return
*/
public static List<Map<String, String>> getDataList(String jdbcUrl, String sql) {
List<Map<String, String>> paramList = new ArrayList<Map<String, String>>();
Map<String, String> param = new HashMap<String, String>();
Statement stmt = null;
try {
// 注册 JDBC 驱动
Class.forName(driverClassName);
// 打开链接
conn = DriverManager.getConnection(jdbcUrl, username, password);
// 执行查询
stmt = conn.createStatement();
ResultSet rs = null;
rs = stmt.executeQuery(sql);
String columns[] = {"username", "passWord", "remark"};
// 展开结果集数据库
while (rs.next()) {
Map<String, String> map = new LinkedHashMap<String, String>();
for (int i = 0; i < columns.length; i++) {
String cellData = rs.getString(columns[i]);
map.put(columns[i], cellData);
}
paramList.add(map);
}
// 完成后关闭
rs.close();
stmt.close();
conn.close();
} catch (SQLException se) {
// 处理 JDBC 错误
System.out.println("处理 JDBC 错误!");
} catch (Exception e) {
// 处理 Class.forName 错误
System.out.println("处理 Class.forName 错误");
} finally {
// 关闭资源
try {
if (stmt != null) stmt.close();
if (conn != null) conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
return paramList;
}
@DataProvider
public Object[][] dbDataMethod() {
String sql = "SELECT * FROM `account`;";
List<Map<String, String>> result = getDataList(url, sql);
Object[][] files = new Object[result.size()][];
for (int i = 0; i < result.size(); i++) {
files[i] = new Object[]{result.get(i)};
}
return files;
}
}
Redis
Demo1:jmeter中使用java获取Redis中的值
Demo2:缓存中间件Redis性能测试
场景:
(1)分别设置value值大小为64B、128B、256B、512B,往Redis集群和Redis单机写入500万条记录。
(2)并发分别设置80、160、320、500、1000、2000、3000、4000、5000、6000、8000对拥有500万条记录的Redis集群和Redis单机进行读取的测试。



集合

集合类存放于java.util包中,Java集合定义了两种基本的数据结构,一种是Collection,用来表示一组对象的集合;另一种则是Map,用来表示对象间的一系列映射或关联关系。Set、List和Queue等接口都是Collection的子接口。
Collection<E>是参数化接口,用来表示一组泛型对象的集合
ArrayList
ArrayList是Java中最常用的List实现类,通过数组实现,可存储一组不唯一、有序的对象。
特点:长度可变且可以存储任何类型的数据
优点:遍历元素和随机访问元素的效率较高
-
ArrayList常用方法

LinkedList
LinkedList使用链表结构存储数据,适合数据的动态插入和删除,但随机访问和遍历速度较慢。可作为堆栈、队列和双向队列使用。

HashSet
可存储一组唯一、无序的对象。

HashMap
Map接口存储一组成对的键(key)——值(value)对象,提供key到value的映射,通过key来检索。Map接口中的key不要求有序,不允许重复。value同样不要求有序,但允许重复。
优点:查询指定元素效率高

线程安全问题
ArrayList、LinkedList、HashSet、HashMap都是非线程安全的,在多个线程场景中使用这些基础容器会出现线程安全问题。多线程场景可考虑使用基于非阻塞算法的JUC高并发容器类。
线程不安全
|
高并发容器方案
|
ArrayList
|
CopyOnWriteArrayList:读多写少的场景
|
HashSet
|
CopyOnWriteArraySet:核心操作基于CopyOnWriteArrayList实现
|
TreeSet
|
ConcurrentSkipListSet:线程安全的有序集合
|
HashMap
|
ConcurrentHashMap
|
TreeMap
|
ConcurrentSkipListMap
|