目录
流库
流
- 流与集合:
- 流不存储元素
- 流的操作不会修改其数据源
- 流的操作是惰性的(需要结果时才会执行)
- 产生集合中的元素流
- 顺序流:
words.stream()
- 并行流:
words.parallelStream()
- 流的创建:
- 将集合转换为流:
Stream<T> w = Stream.of(... ...)
- 用数组的一部分元素创建一个流:
Array.stream(array,from,to)
- 空流:
Stream<String> w = Stream.empty()
- 无限流:
- 常量流:
Stream<String> echos = Stream.generate(() -> "Echo")
- 序列流:
Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO,n -> n.add(BigInteger.ONE));
- 有限序列流:
Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO,n -> n.compareTo(limit) < 0,n -> n.add(BigInteger.ONE));
- 短流:
Stream.ofNullable(...) 用对象创建一个长度为1的流
- filter:
- map:将函数应用到每个元素上(也可以使用forEach)
map(s -> s.substring(0,1));
- flatmap:
codePoints("boat")返回值是流["b","o","a","t"]
- 包含流的流:
Stream<Stream<String>> result = words.stream().map(w -> codePoints(w))
- 摊平为单个流:
Stream<String> flatResult = words.stream().flatMap(w -> codePoints(w))
- 子流/组合流:
stream.limit(n) n个元素的子流
stream.skip(n) 丢弃前n个元素的子流
- 条件为真/假时获取元素:
stream.takeWhile(predicate) / stream.dropWhile(predicate)
- 组合流:
Stream.contact(stream1,stream2)
- 其它流:
stream.distinct() 剔除重复元素
stream.sorted(Comparator.comparing(String::length).reversed()) 流排序
stream.peek(...) 每次获取元素时,调用一次函数
约简
- 简单约简:
stream.count()
stream.max(String::compareToIgnoreCase) 返回Optional< T >
Optional类型
- Optional:包装器对象,包装了类型T的对象或null
- 获取Optional:不存在任何值的情况下产生替代值
optional.orElse(......)
optional.orElseGet(() -> ......)
optional.orElseThrow(IllegalStateException::new)
- 消费Optional:
optional.ifPresent(v -> Process v) 值存在,则被传递给函数
optional.ifPresentOrElse( v -> ProcessTrue v , v -> ProcessFalse v)
- 管道化Optional:
Optional<T> opt = optional.map(v -> Process v)
Optional<T> opt = optional.filter(Predicate)
- 可替代Optional:
Optional<T> opt = optional.or(Supplier)
- 创建Optional:
Optional.empty()
Optional.of(...)
- flatMap构建Optional:若s的方法f返回
Optional<T>,类型T具有返回Optional<U>的方法
- 不能调用
s.f().g()
- 组合:
s.f().flatMap(T::g)
- Optional转换为流:
- 将Optional对象转换为具有0个或1个元素的流:
optional.stream()
收集结果
- 创建泛型数组:
stream.toArray(String[]::new)
- Collectors类:
- 列表:
List<String> result = stream.collect(Collectors.toList());
- 集:
Set<String> result = stream.collect(Collectors.toSet());
TreeSet<String> result = stream.collect(Collectors.toCollection(TreeSet::new));
- 字符串:
String result = stream.collect(Collectors.joining());
- 约简结果:
Collectors.summarizing(Int|Long|Double)(...函数...) 返回 (Int|Long|Double)SummaryStatistics
- 收集到映射表:
Collectors.toMap(Person::getId,Person::getName)
- 群组和分区:
Map<String,List<Locale>> countryToLocales = locales.collect(Collectors.groupingBy(Locale::getCountry));
Locale::getCountry是群组的分类函数
- 下游收集器:
- 集:
Map<String,Set<Locale>> countryToLocaleSet = locales.collect(groupingBy(Locale::getCountry,Collectors.toSet()));
- 数字:counting、summing(Int|Long|Double)、maxBy、minBy、collectingAndThen、mapping
约简
//从前两个元素开始持续应用
List<Integer> values = ...;
Optional<Integer> sum = values.stream().reduce((x,y) -> x + y);
//幺元值:计算起点
Integer sum = values.stream().reduce(0,(x,y) -> x + y);
基本流
基本类型流
- IntStream/DoubleStream:
IntStream stream = IntStream.of(1,1,2,3,5);
//values --- int[]
IntStream stream = Arrays.stream(values,from,to)
IntStream.generate/IntStream.iterate
IntStream.range(0,100)/IntStream.rangeClosed(0,100)
- 对象流转换:mapToInt、mapToLong、mapToDouble
Stream<String> words = ...;
IntStream lengths = words.mapToInt(String::length);
- 基本类型流转换:
IntStream.boxed()
并行流
- 获取并行流:
Stream<String> parallel = words.parallelStream(); 集合->并行流
- 转化并行流:
Stream<String> parallel = wstream.parallel(); 顺序流->并行流
- 无排序处理:
stream.unordered()
I/O
输入输出流
- 读写字节
- java.io.InputStream
- java.io.OutputStream
- 输入输出流家族:
- 读写字节:InputStream/OutputStream
- 读写Unicode码元:Reader/Writer
- 组合输入/输出流过滤器:
- 文件输入输出流:
FileInputStream/FileOutputStream
FileInputStream fin = new FileInputStream("employee.dat")
- 构造器:
- 将字节组装到数据类型:
DataInputStream din = new DataInputStream(fin)
- 使用缓冲机制:
new BufferedInputStream(fin)
- 预览字节(可回推流):
new PushbackInputStream(fin)
- 文本输入与输出:(java虚拟机中统一以Unicode编码,输入输出需要进行转换)
- OutputStreamWriter/InputStreamReader:Unicode码元与字节流转换
- 文件文本输出:
PrintWriter out = new PrintWriter("employee.txt",StandardCharsets.UTF_8)
- 输出:
out.print()/println()/printf()
- 文件文本输入:
- Scanner类:
Scanner in = new Scanner(......)
- 文本读入字符串:
String content = Files.read(String path,charset)
- 按行读入:
List<String> lines = Files.readAllLines(path,charset)
String line = in.nextLine();
String[] tokens = line.split("\\|")
- 流对象(大文件):
Stream<String> lines = Files.lines(path,charset)
- 扫描器(分隔符):
in.useDelimiter("\\PL+"); --- 读入分隔符分隔的字符串(符号)
- 读入下一个符号:
String word = in.next()
- 获取包含所有符号的流:
Stream<String> words = in.tokens();
- 读写二进制:
- 对象输入/输出流与序列化:
- 对象序列化
- 打开ObjectOutputStream对象
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.dat"));
- 保存对象
out.writeObject(...对象实例...);
- 打开ObjectInputStream对象
ObjectInputStream in = new ObjectInputStream(new FileInputStream("employee.dat"));
- 以对象被写出时的顺序获得
Employee e = (Employee) in.readObject();
- 序列化类应声明Serializable接口(该接口没有任何方法需要实现)
文件
- Path:
- Path p = Paths.get("/home","harry","user.properties");
- p.resolve(q)
- toAbsolutePath方法产生给定路径的绝对路径
- 读写文件:
- 读取文本内容:
String content = Files.readString(path,charset)
- 行读取:
List<String> lines = Files.readAllLines(path,charset)
- 写入文本内容:
Files.writeString(path,content.charset);
- 追加内容:
Files.write(path,content.getBytes(charset),StandardOpenOption.APPEND);
- 写入行集合:
Files.write(path,lines,charset);
- 读写大文件:
Files.newInputStream(path)/Files.newOutputStream(path)处理
- 创建文件目录:
- 创建新目录:
Files.createDirectory(path)/Files.createDirectories(path)
- 创建空文件:
Files.createFile(path)
- 复制/移动/删除文件:
- 复制:
Files.copy(fromPath,toPath)
- 移动:
Files.move(fromPath,toPath)
- 输入流:
Files.copy(inputStream,toPath)/Files.copy(fromPath,outputStream)
- 删除:
Files.delete(path)
- 获取文件信息:
- exists/isHidden/isReadable/isWritable/isExecutable/isRegularFile/isDirectory/isSymbolicLink/size/getowner
- 目录:
- Files.list(...)方法返回目录中各项的Stream< Path >对象(不会进入子目录)
- Files.walk(...)与list方法类似,但会进入各子目录
- 访问目录中的所有成员:
Files.walkFileTree(Path.get("/"),new FileVistor<Path>() {......});
- ZIP文件系统:
- 建立文件系统:
FileSystem fs = FileSystem.newFileSystem(Paths.get(zipname),null);
- 从ZIP文档中复制文件:
Files.copy(fs.getPath(sourceName),targetPath);
- 内存映射文件:
- 高速存取文件
- 文件通道:
FileChannel channel = FileChannel.open(path,options)
- 获得ByteBuffer缓冲区:
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.Read_ONLY,0,length)
- FileChannel.MapMode.READ_ONLY 只读缓冲区
- FileChannel.MapMode.READ_WRITE 读写缓冲区
- FileChannel.MapMode.PRIVATE 对缓冲区的修改不会传播到文件中
- buffer.get()方法读取/buffer.put()方法写入
- 文件加锁机制:
- 锁定文件:
channel = FileChannel.open(path);
- 阻塞直至获得锁
FileLock lock = channel.lock();
- 阻塞则立即返回
FileLock lock = channel.trylock();
- 释放锁定:
try (FileLock lock = channel.lock()) { ...... }
正则表达式
XML
XML文档
网络
连接服务器
- 打开Socket:
Socket s = new Socket("time-a.nist.gov",13); 或 Socket s = new Socket()
- 设置Socket连接:
s.connect(new InetSocketAddress(host,post),timeout);
- 输入流:
InputStream inStream = s.getInputStream();
- 输出流:
OutputStream outStream = s.getOutputStream();
- 套接字超时:
s.setSoTimeout(10000);
- 超时异常:SocketTimeoutException
- 连接状态:
s.isConnected()
- 关闭状态:
s.isClosed()
- Internet地址:
- 返回主机InetAddress对象:
InetAddress address = InetAddress.getByName("time-a.nist.gov");
- 访问IP地址字节:
byte[] addressBytes = address.getAddress();
- 多地址访问:
InetAddress[] address = InetAddress.getAllByName(host);
- 本地主机地址:
InetAddress address = InetAddress.getLocalHost();
实现服务器
- 服务器Socket:
- 建立服务器:
ServerSocket s = new ServerSocket(8180);
- 建立服务器Socket:
Socket incoming = s.accept();
- 输入流:
InputStream inStream = incoming.getInputStream();
- 输出流:
OutputStream outStream = incoming.getOutputStream();
- 关闭SSocket:
incoming.close()
- 多客户端Socket:
- ThreadedEchoHandler类:
ThreadEchoHandler r = ThreadEchoHandler(incoming); Thread t = new Thread(r);
- 半关闭:
- 将输出流设置为流结束:
socket.shutdownOutput()
- 将输入流设置为流结束:
socket.shutdownInput()
- 可中断Socket:
- 当线程发生中断,操作不会陷入阻塞,而是抛出异常
- SocketChannel:
SocketChannel channel = SocketChannel.open(new InetSocketAddress(host,port));
Scanner in = new Scanner(channel,StandardCharsets.UTF_8); 或 OutputStream outstream = Channels.newOutputStream(channel);
URI
- URL/URI:
- 构建URL:
URL url = new URL(urlString);
- 获取资源:
InputStream inStream = url.openStream();
- URI:统一资源标识符 [scheme:]schemeSpecificPart[#fragment]
- 包含scheme:部分的称为绝对URI
- schemeSpecificPart以/开头称为透明URI
- schemeSpecificPart结构:[//authority][path][?query]
- URL是特殊的URI,包含了定位定位Web资源的足够信息
- URLConnection:
- 获得Connection对象:
URLConnection connection = url.openConnection();
- 设置请求属性
- HTTP请求头:
connection.setRequestProperty(key,value[Base64]);
- 连接远程资源:
connection.connect();
- 建立连接后可以查询头信息
- HTTP响应头:
Stringkey = connection.getHeaderFieldKey(n);
String value = connection.getHeaderField(n);
Map<String,List<String>> headerFields = connection.getHeaderFields();
- 访问资源:
InputStream instream = connection.getInputStream();
- 提交表单数据:
- GET
- http://host/path?query --- query为名字=值形式
- San Francisco, CA --- San+Francisco%2c+CA(%2c是,的UTF-8码值)
- &用作不同参数之间的连接符
- POST
URL url = new URL("http://host/path");
URLConnection connection = url.openConnection();
- 输出连接:
connection.setOutput(true);
- PrintWriter包装:
PrintWriter out = new PrintWriter(connection.getOutputStream(),StandardCharsets.UTF_8);
HTTP
- 获取客户端:
HttpClient client = HttpClient.newHttpClient();
- 构建器模式
HttpClient client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.ALWAYS)
.build();
- Get请求:
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://horstmann.com"))
.GET()
.build();
- POST请求:
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(url))
.header("Content-Type", "application/json")
//体发布器
.POST(HttpRequest.BodyPublishers.ofString(jsonString))
.build();
- 响应处理:
- 发送请求时,需规定客户端如何处理响应:
HttpResponse<String> reponse = client.send(request,HttpResponse.BodyHandlers.ofString());
- 响应头:
HttpHeaders responseHeaders = response.headers();
- headers对象转化为map:
Map<String,List<String>> headerMap = responseHeaders.map()
- 获取特定键的第一个值:
Optional<String> lastModified = headerMap.firstValue("......");
- 状态码:
int status = response.statusCode();
- 异步响应
//构建执行器
ExecutorService executor = Executors.newCachedThreadPool();
HttpClient client = HttpClient.newBuilder().executor(executor).build();
//异步响应
HttpRequest request = HttpRequest.newBuilder().uri(uri).GET().build();
client.sendAsync(request,HttpResponse.BodyHandlers.ofString())
.thenAccept(response -> ......);
数据库
JDBC
- 加载数据库驱动:
Class.forName("com.mysql.jdbc.Driver")
- 数据库URL:URL --- jdbc:subprotocol:other stuff
- 连接数据库:
String url = "jdbc:postgresql:COREJAVA";
String username = "dbuser";
String password = "secret";
Connection conn = DriverMannger.getConnection(url,username,password);
- JDBC语句:
- 执行SQL:
- 创建Statement:
Statement stat = conn.createStatement();
- SQL语句字符串:
String command = "...+...+...";
- 执行SQL:
stat.executeUpdate(command);
- 执行SELECT语句应使用executeQuery()方法
- 提交并获取结果集:
ResultSet rs = stat.executeQuery(......);
- SQL异常:
- SQLException异常链
- SQLWarning异常链
- 查询数据库:
- 预备语句:
String Query = "...+...+..."; 使用?代替变量
- 为变量指定值:
stat.setString(int,String)
- 可滚动结果集:
- Statement:
Statement stat = conn.createStatement(type,concurrency);
- 预备语句:
PreparedStatement stat = conn.prepareStatement(command,type,concurrency);
- 设置参数:
stat.setInt|Double|String|...(index,param)
- 滚动:
- 移动到下一行:
rs.next()
- 移动多行:
rs.relative(n)
- 移动到指定行号:
rs.absolute(n)
- 当前行行号:
rs.getRow()
- 获取当前行中列数据:
getArray/getString/getDouble/.............
- 以列的索引作为参数:
rs.getString(int colIndex)
- 以列的名字作为参数:
rs.getString(String colName)
- 不知道获取列的数据类型,可一律采用getString方法
- 可更新结果集:
- Statement:
Statement stat = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
- UPDATE:
rs.updateDouble("...",...); rs.updateRow();
- INSERT:
//移动至插入行
rs.moveToInsertRow();
rs.updateString("...",...);
rs.insertRow();
rs.moveToCurrentRow();
- 行集:不依赖数据库连接-javax.sql.rowset
- 获取行集:
RowSetFactory factory = RowSetProvider.newFactory();
CachedRowSet crs = factory.createCachedRowSet();
- 被缓存的行集:
ResultSet result = ......;
- 结果集填充到行集:
crs.populate(result);
- 分页:
crs.setPageSize(20); crs.nextPage();
- 写数据库:
crs.acceptChanges(conn);
元数据
- 元数据:描述数据库及其组成部分的数据
- DatabaseMetaData:
DatabaseMetaData meta = conn.getMetaData();
- 调用元数据:
- 返回数据库表结果集:
ResultSet mrs = meta.getTables(null,null,null,new String[] {"TABLE"});
- 结果集的每一行包含了数据库中一张表的详细信息
- ResultSetMetaData:
ResultSetMetaData meta = rs.getMetaData();
事务
- 事务:组合语句,确保所有语句都能顺利执行,否则回滚操作
- 事务编程:
- 关闭自动提交:
conn.setAutoCommit(false);
- 创建对象并提交:
Statement stat = conn.createStatement(); stat.executeUpdate(command);
conn.commit();
- 出现错误,调用:
conn.rollback();
- 批量更新:
stat.addBatch(command);
- 批量提交语句:
int[] counts = stat.executeBatch();
- 事务冲突:
- 脏读(脏数据):一个事务访问数据并修改且并未提交,则另一个事务读取的数据称为脏数据,如果前一事务回滚,后一事务读取的数据是不正确的
- 不可重复读:一个事务读取了一行数据,在事务结束前,另一事务访问了同一行并进行了修改,此时前一事务再次读取,结果会不同,称为不可重复读
- 幻读:一个事务读取了满足条件的所有行后,另一个事务插入了一行数据,前一事务再次进行同样的条件读取时,结果多了一行数据,称为幻读
- 事务隔离:
- Read Uncommitted:保证读取过程不会读到非法数据,但无法避免事务冲突
- Read Commited::保证一个事务不会读到另一个并行事务已修改但未提交的数据,避免了脏读
- Repeatable Read:避免了脏读和不可重复读(即看不到其它事务对已有记录的更新/修改)
- Serializable:最高级别事务隔离,串行化事务执行
- 隔离级别:
conn.setTransactionIsolation(param)
- TRANSACTION_NONE:不支持事务
- TRANSACTION_READ_UNCOMMITTED:指定可以发生脏读、不可重复读和幻读
- TRANSACTION_READ_COMMITTED:指定禁止脏读
- TRANSACTION_REPEATABLE_READ:指定禁止脏读和不可重复读
- TRANSACTION_SERIALIZABLE:指定禁止脏读、不可重复读和幻读
JDBC数据源和连接池
日期和时间
- 时间线:绝对时间
Instant start = Instant.now()
- 表示时间线上的某个时间点
- 时间差:
Duration time = Duration.between(start,end);
- 时间转换:
long millis = time.toMillis();
本地日期
- LocalDate:
LocalDate today = LocalDate.now();
LocalDate Birth = LocalDate.of(1903,6,14);
- LocalTime:
LocalTime now = LocalTime.now();
LocalTime time = LocalTime.of(22,30,10);
LocalTime plustime = time.plusHours(8);
时区时间
- ZonedDateTime:
ZonedDateTime skipped = ZonedDateTime.of(LocalDate.of(2013,3,31),LocalTime.of(2,30),ZoneID.of("Europe/Berlin"));
ZonedDateTime next = skipped.plus(Period.ofDays(7));
-不能使用Duration.ofDays(7)
- 时间格式化:
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss);
国际化
Locale
- Locale:
Locale us_en = Locale.forLanguageTag("en-US");
- 国别-语言 -> zh-CN
- 预定义Locale:Locale.CHINA/Locale.SIMPLIFIED_CHINESE
- 数字格式化:
- Locale:
Locale loc = Locale.GERMAN;
- Format:
NumberFormat fmt = NumberFormat.getCurrencyInstance(loc);
- getNumberInstance --- 数字格式化
- getCurrencyInstance --- 货币格式化
- getPercentInstance --- 百分比格式化
- 格式化:
String result = fmt.format(123.45d);
- 货币格式变更:
fmt.setCurrency(Currency.getInstance("EUR"));
- 日期格式化:
- 格式器:
FormatStyle style = ...;
- SHORT --- 7/16/69 --- 9:32 AM
- MEDIUM --- Jul 16,1969 --- 9:32:00 AM
- LONG --- July 16,1969 --- 9:32:00 AM EDT
- FULL --- Wednesday,July 16,1969 --- 9:32:00 AM EDT
DateTimeFormatter dtFmt = DateTimeFormatter.ofLocalizedDataTime(style).withLocale(locale);
- 排序和规范化:
- 比较器:
Comparator: Collator coll = Collator.getInstance(locale);
words.sort(coll);
资源包
- 命名:
- 国家相关:baseName_language_country
- 语言相关:basName_language
- 加载:
ResourceBundle resources = ResourceBundle.getBundle(baseName,currentLocale);
- 属性文件:
- .porperties : 如ProgramStrings_de_DE.properties
- 查找字符串:
String label = resources.getString("computeButton");
- 包类:提供字符串以外的资源
- 命名:ProgramResources_de_DE.java
- 加载:
ResourceBundle bundle = ResourceBundle.getBundle("ProgramResources",locale);
- 定位:
Color backgroundColor = (Color)bundle.getObject("backColor");
脚本/编译/注解
脚本
编译
- 调用编译器:
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
OutputStream outStream = ...;
OutputStream errStream = ...;
int result = compiler.run(null,outStream,errStream,"-sourcepath","src","Test.java");
- 发起编译任务:
- 捕获诊断消息:
DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
- 发起编译:
JavaCompiler.CompilationTask task = compiler.getTask(
errorWriter,
fileManager,
diagnostics,
options,
classes,
sources);
Boolean success = task.call();
注解
标准注解
- 编译注解:
- @Deprecated ---> 注解项为过时的
- @SuppressWarnings ---> 组织特定类型的警告信息
- @Override ---> 用在方法上,检查注解的方法是否真正覆盖了超类方法
- @Generated ---> 代码为工具所自动生成
- 资源注解:
- @PostConstruct/@PreDestory ---> 控制对象生命周期,标注方法在对象构建后或移除前,紧接着调用
- @Resource ---> 资源注入,对象构造时,容器注入该数据源的引用
- 元注解:
- @Target ---> 应用于注解,限制该注解应用于哪些项
- @Retention ---> 注解应该保留多长时间
- @Document ---> 指定该注解应该包含在注解项文档(javadoc)
- @Inherited ---> 应用于类,它的子类自动继承同样的注解
安全
数字签名
- 消息摘要:
- 指纹对象:
MessageDigest alg = MessageDigest.getInstance("SHA-1")
- 传递字节:
alg.update(bytes)
- 消息摘要:
byte[] hash = alg.digest();
加密
- 对称加密:AES
- 密码对象:
Cipher cipher = Cipher.getInstance(algorithName);
- 密钥初始化:
int mode = ...; Key key = ...;
cipher.init(mode,key);
- update()和doFinal()加密数据块
- 密钥生成:
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom();
keygen.init(random);
Key key = keygen.generateKey();
- 非对称加密:RSA
KeyPairGenerator pairgen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = new SecureRandom();
pairgen.intiialize(KEYSIZE,random);
KeyPair keypair = pairgen.generateKeyPair();
Key publicKey = kepPair.getPublic();
Key privateKey = keyPair.getPrivate();