网络编程、JDBC编程、函数式编程
网络编程
Socket
TCP:面向连接,可靠传输
UDP:不面向连接,不可靠传输
TCP编程
1)客户端使用Socket(InetAddress, port)打开Socket
2)服务器端用ServerSocket监听端口
3)服务器端用accept接收并返回Socket
4)双方通过Socket打开 InputStream / OutputStream 读写数据
5)flush()用于强制输出缓冲区
服务器端
public class TCPServer {
public static void main(String[] args) throws Exception{
ServerSocket socketSocket = new ServerSocket(9090);
System.out.println("TCP server ready...");
Socket socket = socketSocket.accept();
try(BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream(),
StandardCharsets.UTF_8))){
try(BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(),
StandardCharsets.UTF_8))){
String cmd = reader.readLine();
if("time".equals(cmd)){
writer.write(LocalDateTime.now().toString() + "\n");
writer.flush();
}else{
writer.write("Sorroy?\n");
writer.flush();
}
}
}
socket.close();
socketSocket.close();
}
}
客户端
public class TCPClient {
public static void main(String[] args) throws IOException {
InetAddress address = InetAddress.getLoopbackAddress();
try (Socket socket = new Socket(address, 9090)) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream(),
StandardCharsets.UTF_8))) {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(),
StandardCharsets.UTF_8))) {
writer.write("time\n");
writer.flush();
String response = reader.readLine();
System.out.println("Response: " + response);
}
}
}
}
}
// 所有IP地址
ServerSocket(int port)
ServerSocket(int port, int backlog)
// 指定IP地址
ServerSocket(int port, int backlog, InetAddress bindAddr)
// 例如:假设公网:101.77.99.88,内网:10.1.0.100
// 所有IP都可以访问
new ServerSocket(12345);
// 仅本机(127.0.0.1)可以访问
new ServerSocket(12345, 50, InetAddress.getLoopbackAddress());
// 仅公网IP可以访问
new ServerSocket(12345, 50, InetAddress.getByAddress(new byte[]{101, 77, 99, 88}));
// 仅内网IP可以访问
new ServerSocket(12345, 50, InetAddress.getByAddress(new byte[]{10, 1, 0, 100}));
TCP多线程
服务器端
public class TCPServer {
public static void main(String[] args) throws Exception {
@SuppressWarnings("resource")
ServerSocket socketSocket = new ServerSocket(9090);
System.out.println("TCP server ready...");
for (;;) {
Socket socket = socketSocket.accept();
System.out.println("Accept from " + socket.getRemoteSocketAddress());
TimeHandler handler = new TimeHandler(socket);
handler.start();
}
}
}
class TimeHandler extends Thread {
Socket socket;
public TimeHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run(){
try(BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream(),
StandardCharsets.UTF_8))){
try(BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(),
StandardCharsets.UTF_8))){
for(;;){
String cmd = reader.readLine();
if("q".equals(cmd)){
writer.write("bye!\n");
writer.flush();
}else if("time".equals(cmd)){
writer.write(LocalDateTime.now().toString() + "\n");
writer.flush();
}else {
writer.write("Sorroy?\n");
writer.flush();
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
this.socket.close();
} catch (IOException e){
e.printStackTrace();
}
}
}
}
客户端
public class TCPClient {
public static void main(String[] args) throws IOException, InterruptedException {
InetAddress address = InetAddress.getByName("localhost");
try (Socket socket = new Socket(address, 9090)) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream(),
StandardCharsets.UTF_8))) {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(),
StandardCharsets.UTF_8))) {
writer.write("time\n");
writer.flush();
String response = reader.readLine();
System.out.println("Response: " + response);
Thread.sleep(1000);
writer.write("q\n");
writer.flush();
response = reader.readLine();
System.out.println("Response: " + response);
}
}
}
}
}
1)服务器端使用无线循环
2)每次accept()返回后,创建新的线程来处理客户端请求
3)每个客户端请求对应一个服务线程
4)使用线程池可以提高运行效率
练习
请把多线程模型中每次创建一个新线程改为使用线程池实现
UDP编程
1)UDP不需要建立连接
2)UDP不保证可靠传输
3)客户端使用DatagramSocket.connect()指定远程地址和端口
4)服务器端用DatagramSocket(port)监听端口
5)双方通过 revice / send 读写数据
6)没有 IO 流数据
服务器端
public class UDPServer {
public LocalDateTime currentTime(){
return LocalDateTime.now();
}
public static void main(String[] args) throws Exception{
@SuppressWarnings("resource")
DatagramSocket ds = new DatagramSocket(9090);
System.out.println("UDP server ready...");
for(;;){
// receive:
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
ds.receive(packet);
byte[] data = packet.getData();
String s = new String(data, StandardCharsets.UTF_8);
System.out.println("Packet received from: " + packet.getSocketAddress() + " " + s);
// send:
String response = LocalDateTime.now().toString();
packet.setData(response.getBytes(StandardCharsets.UTF_8));
ds.send(packet);
}
}
}
客户端
public class UDPClient {
public static void main(String[] args) throws Exception{
InetAddress address = InetAddress.getLoopbackAddress();
try(DatagramSocket socket = new DatagramSocket()){
socket.connect(address, 9090);
byte[] data = "time".getBytes(StandardCharsets.UTF_8);
DatagramPacket packet = new DatagramPacket(data, data.length);
socket.send(packet);
System.out.println("Data was send.");
Thread.sleep(1000);
byte[] buffer = new byte[1024];
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
byte[] responseData = response.getData();
String responseText = new String(responseData, 0, response.getLength(), StandardCharsets.UTF_8);
System.out.println("Response: " + responseText);
}
}
}
发送Email
SMTP(Simple Mail Transport Protocol)
标准端口25,加密端口 465、587
使用javamail API发送Email:
1)确定SMTP服务器信息:域名、端口、使用明文、SSL、TLS
2)调用相关API发送Email
3)设置debug模式可以查看通信详细内容
// 1. 创建Session:
Session session = Session.getInstance(props, new Authenticator(){...});
// 2. 创建Message对象:
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("from@email.com"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("to@email.com"));
message.setSubject("RE:how to use JavaMail", "UTF-8");
message.setText("blablabla...", "UTF-8");
// 3. 发送邮件:
Transport.send(message);
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
发送文本邮件
/**
* 发送文本邮件
*/
public class SendMail {
/**
* 邮件服务器域名
*/
final String smtpHost;
/**
* 邮件服务器登陆名
*/
final String username;
/**
* 邮件服务器登陆密码
*/
final String password;
final boolean debug;
public SendMail(String smtpHost, String username, String password){
this.smtpHost = smtpHost;
this.username = username;
this.password = password;
this.debug = true;
}
public static void main(String[] args) throws Exception {
SendMail sender = new SendMail("smtp.sina.com", "javacourse001@sina.com", "java-12345678");
// 创建Session:
Session session = sender.createSSLSession();
// 创建Message:
Message message = createTextMessage(session, "javacourse001@sina.com", "javacourse001@163.com", "Java邮件测试",
"Hello, 这是一封javamail测试邮件!");
// 发送邮件:
Transport.send(message);
}
/**
* 创建SSL会话
* @return
*/
Session createSSLSession() {
Properties props = new Properties();
props.put("mail.smtp.host", this.smtpHost); // SMTP主机名
props.put("mail.smtp.port", "465"); // 主机端口号
props.put("mail.smtp.auth", "true"); // 是否需要用户认证
// 启动SSL:
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.port", "465");
Session session = Session.getInstance(props, new Authenticator() {
// 用户名+口令认证:
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(SendMail.this.username, SendMail.this.password);
}
});
session.setDebug(this.debug); // 显示调试信息
return session;
}
// /**
// * 创建TLS会话
// * @return
// */
// Session createTLSSession() {
// Properties props = new Properties();
// props.put("mail.smtp.host", this.smtpHost); // SMTP主机名
// props.put("mail.smtp.port", "587"); // 主机端口号
// props.put("mail.smtp.auth", "true"); // 是否需要用户认证
// props.put("mail.smtp.starttls.enable", "true"); // 启用TLS加密
// Session session = Session.getInstance(props, new Authenticator() {
// protected PasswordAuthentication getPasswordAuthentication() {
// return new PasswordAuthentication(SendMail.this.username, SendMail.this.password);
// }
// });
// session.setDebug(this.debug); // 显示调试信息
// return session;
// }
// /**
// * 创建Insecure会话
// * @return
// */
// Session createInsecureSession(String host, String username, String password) {
// Properties props = new Properties();
// props.put("mail.smtp.host", this.smtpHost); // SMTP主机名
// props.put("mail.smtp.port", "25"); // 主机端口号
// props.put("mail.smtp.auth", "true"); // 是否需要用户认证
// Session session = Session.getInstance(props, new Authenticator() {
// protected PasswordAuthentication getPasswordAuthentication() {
// return new PasswordAuthentication(SendMail.this.username, SendMail.this.password);
// }
// });
// session.setDebug(this.debug); // 显示调试信息
// return session;
// }
/**
* 创建文本的消息(Message)对象
* @param session 会话
* @param from 发送方邮件地址
* @param to 接收方邮件地址
* @param subject 邮件主题
* @param body 邮件正文
* @return
* @throws MessagingException
*/
static Message createTextMessage(Session session, String from, String to, String subject, String body)
throws MessagingException {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject, "UTF-8");
message.setText(body, "UTF-8");
return message;
}
}
发送HTML邮件
/**
* 发送HTML邮件
*/
public class SendMailWithHTML {
public static void main(String[] args) throws Exception {
SendMail sender = new SendMail("smtp.sina.com", "javacourse001@sina.com", "java-12345678");
Session session = sender.createSSLSession();
Message message = createHtmlMessage(session, "javacourse001@sina.com", "javacourse001@163.com", "Java HTML邮件",
"<h1>Hello</h1><p>这是一封<u>javamail</u>测试邮件!</p>");
Transport.send(message);
}
/**
* 创建HTML的消息(Message)对象
* @param session 会话
* @param from 发送方邮件地址
* @param to 接收方邮件地址
* @param subject 邮件主题
* @param body 邮件正文
* @return
* @throws MessagingException
*/
static Message createHtmlMessage(Session session, String from, String to, String subject, String body)
throws MessagingException {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject, "UTF-8");
message.setText(body, "UTF-8", "html");
return message;
}
}
发送带附件邮件
/**
* 发送附件邮件
*/
public class SendMailWithAttachment {
public static void main(String[] args) throws Exception {
SendMail sender = new SendMail("smtp.sina.com", "javacourse001@sina.com", "java-12345678");
Session session = sender.createSSLSession();
try (InputStream input = SendMailWithAttachment.class.getResourceAsStream("/javamail.jpg")) {
Message message = createMessageWithAttachment(session, "javacourse001@sina.com", "javacourse001@163.com",
"Hello Java邮件带附件测试", "<h1>Hello</h1><p>这是一封带附件的<u>javamail</u>测试邮件!</p>", "javamail.jpg", input);
Transport.send(message);
}
}
/**
* 创建带附件的消息(Message)对象
* @param session 会话
* @param from 发送方邮件地址
* @param to 接收方邮件地址
* @param subject 邮件主题
* @param body 邮件正文
* @param fileName 附件文件名
* @param input 输入流
* @return
* @throws MessagingException
* @throws IOException
*/
static Message createMessageWithAttachment(Session session, String from, String to, String subject, String body,
String fileName, InputStream input) throws MessagingException, IOException {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject, "UTF-8");
Multipart multipart = new MimeMultipart();
// 添加text:
BodyPart textpart = new MimeBodyPart();
textpart.setContent(body, "text/html;charset=utf-8");
multipart.addBodyPart(textpart);
// 添加image:
BodyPart imagepart = new MimeBodyPart();
imagepart.setFileName(fileName);
imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(input, "application/octet-stream")));
multipart.addBodyPart(imagepart);
message.setContent(multipart);
return message;
}
}
发送内嵌图片邮件
/**
* 发送内嵌图片的邮件
*/
public class SendMailWithInlineImage {
public static void main(String[] args) throws Exception {
SendMail sender = new SendMail("smtp.sina.com", "javacourse001@sina.com", "java-12345678");
Session session = sender.createSSLSession();
try (InputStream input = SendMailWithInlineImage.class.getResourceAsStream("/javamail.jpg")) {
Message message = createMessageWithInlineImage(session, "javacourse001@sina.com", "javacourse001@163.com",
"Hello Java HTML邮件内嵌图片测试",
"<h1>Hello</h1><p><img src=\"cid:img01\"></p><p>这是一封内嵌图片的<u>javamail</u>测试邮件!</p>", "javamail.jpg",
input);
Transport.send(message);
}
}
/**
* 创建内嵌图片的消息(Message)对象
* @param session 会话
* @param from 发送方邮件地址
* @param to 接收方邮件地址
* @param subject 邮件主题
* @param body 邮件正文
* @param fileName 附件文件名
* @param input 输入流
* @return
* @throws MessagingException
* @throws IOException
*/
static Message createMessageWithInlineImage(Session session, String from, String to, String subject, String body,
String fileName, InputStream input) throws MessagingException, IOException {
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject, "UTF-8");
Multipart multipart = new MimeMultipart();
// 添加text:
BodyPart textpart = new MimeBodyPart();
textpart.setContent(body, "text/html;charset=utf-8");
multipart.addBodyPart(textpart);
// 添加image:
BodyPart imagepart = new MimeBodyPart();
imagepart.setFileName(fileName);
imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(input, "image/jpeg")));
// 与HTML的<img src="cid:img01">关联:
imagepart.setHeader("Content-ID", "<img01>");
multipart.addBodyPart(imagepart);
message.setContent(multipart);
return message;
}
}
接收Email
POP3(Post Office Protocol version 3)
标准端口110,加密端口995
使用javamail接收Email:
1)确定SMTP服务器信息:域名、端口、使用明文、SSL、TLS
2)调用相关API接收Email
3)设置debug模式可以查看通信详细内容
// 1. 创建Session:
Session session = Session.getInstance(props, null);
// 2. 创建Store:
Store store = new POP3SSLStore(session, url);
// 3. 获取Folder:
Folder folder = store.getFolder("INBOX"); // INBOX:收件箱
// 4. 获取Message:
Message[] messages = folder.getMessage();
for(Message message : messages){
...
}
/**
* 接收邮件
*/
public class ReceiveMail {
final String popHost;
final String username;
final String password;
final boolean debug;
public ReceiveMail(String popHost, String username, String password) {
this.popHost = popHost;
this.username = username;
this.password = password;
this.debug = true;
}
public static void main(String[] args) throws Exception {
ReceiveMail receiver = new ReceiveMail("pop.163.com", "javacourse001@163.com", "javamail1234");
Folder folder = null;
Store store = null;
try {
store = receiver.createSSLStore();
folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
System.out.println("Total messages: " + folder.getMessageCount());
System.out.println("New messages: " + folder.getNewMessageCount());
System.out.println("Unread messages: " + folder.getUnreadMessageCount());
System.out.println("Deleted messages: " + folder.getDeletedMessageCount());
Message[] messages = folder.getMessages();
for (Message message : messages) {
printMessage((MimeMessage) message);
}
} finally {
if (folder != null) {
try {
folder.close(true);
} catch (MessagingException e) {
e.printStackTrace();
}
}
if (store != null) {
try {
store.close();
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
}
/**
* 创建SSL store
* @return
*/
public Store createSSLStore() throws MessagingException {
Properties props = new Properties();
props.setProperty("mail.store.protocol", "pop3");
props.setProperty("mail.pop3.port", "995"); // 主机端口号
props.setProperty("mail.pop3.host", this.popHost);// POP3主机名
// 启动SSL:
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.port", "995");
URLName url = new URLName("pop3", this.popHost, 995, "", this.username, this.password);
Session session = Session.getInstance(props, null);
session.setDebug(this.debug); // 显示调试信息
Store store = new POP3SSLStore(session, url);
store.connect();
return store;
}
// /**
// * 创建TLS store
// * @return
// */
// Session createTLSStore() {
// Properties props = new Properties();
// props.put("mail.smtp.host", this.popHost); // POP3主机名
// props.put("mail.smtp.port", "587"); // 主机端口号
// props.put("mail.smtp.auth", "true"); // 是否需要用户认证
// props.put("mail.smtp.starttls.enable", "true"); // 启用TLS加密
// Session session = Session.getInstance(props, new Authenticator() {
// protected PasswordAuthentication getPasswordAuthentication() {
// return new PasswordAuthentication(ReceiveMail.this.username, ReceiveMail.this.password);
// }
// });
// session.setDebug(this.debug); // 显示调试信息
// return session;
// }
// /**
// * 创建Insecure store
// * @return
// */
// Session createInsecureStore() {
// Properties props = new Properties();
// props.put("mail.smtp.host", this.popHost); // POP3主机名
// props.put("mail.smtp.port", "25"); // 主机端口号
// props.put("mail.smtp.auth", "true"); // 是否需要用户认证
// Session session = Session.getInstance(props, new Authenticator() {
// protected PasswordAuthentication getPasswordAuthentication() {
// return new PasswordAuthentication(ReceiveMail.this.username, ReceiveMail.this.password);
// }
// });
// session.setDebug(this.debug); // 显示调试信息
// return session;
// }
/**
* 打印消息
* @param msg
* @throws IOException
* @throws MessagingException
*/
static void printMessage(MimeMessage msg) throws IOException, MessagingException {
System.out.println("--------------------");
System.out.println("Subject: " + MimeUtility.decodeText(msg.getSubject()));
System.out.println("From: " + getFrom(msg));
System.out.println("To: " + getTo(msg));
System.out.println("Sent: " + msg.getSentDate().toString());
System.out.println("Seen: " + msg.getFlags().contains(Flags.Flag.SEEN));
System.out.println("Priority: " + getPriority(msg));
System.out.println("Size: " + msg.getSize() / 1024 + "kb");
System.out.println("Body: " + getBody(msg));
System.out.println("--------------------");
System.out.println();
}
/**
* 获取发送方邮件地址
* @param msg
* @return
* @throws IOException
* @throws MessagingException
*/
static String getFrom(MimeMessage msg) throws IOException, MessagingException {
Address[] froms = msg.getFrom();
return addressToString(froms[0]);
}
/**
* 获取接收方邮件地址
* @param msg
* @return
* @throws MessagingException
* @throws IOException
*/
static String getTo(MimeMessage msg) throws MessagingException, IOException {
// 使用 msg.getAllRecipients() 获取所有收件人
Address[] tos = msg.getRecipients(RecipientType.TO);
List<String> list = new ArrayList<>();
for (Address to : tos) {
list.add(addressToString(to));
}
return String.join(", ", list);
}
/**
* 邮件地址转换
* @param addr
* @return
* @throws IOException
*/
static String addressToString(Address addr) throws IOException {
InternetAddress address = (InternetAddress) addr;
String personal = address.getPersonal();
return personal == null ? address.getAddress()
: (MimeUtility.decodeText(personal) + " <" + address.getAddress() + ">");
}
/**
* 获取邮件优先级
* @param msg
* @return
* @throws MessagingException
*/
static String getPriority(MimeMessage msg) throws MessagingException {
String priority = "Normal";
String[] headers = msg.getHeader("X-Priority");
if (headers != null) {
String header = headers[0];
if ("1".equals(header) || "high".equalsIgnoreCase(header)) {
priority = "High";
} else if ("5".equals(header) || "low".equalsIgnoreCase(header)) {
priority = "Low";
}
}
return priority;
}
/**
* 获取邮件正文
* @param part
* @return
* @throws MessagingException
* @throws IOException
*/
static String getBody(Part part) throws MessagingException, IOException {
if (part.isMimeType("text/*")) {
return part.getContent().toString();
}
if (part.isMimeType("multipart/*")) {
Multipart multipart = (Multipart) part.getContent();
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
String body = getBody(bodyPart);
if (!body.isEmpty()) {
return body;
}
}
}
return "";
}
}
其他网络编程
HTTP编程
HTTP:HyperText Transfer Protocol
1)HTTP协议是一个基于TCP的请求/响应协议
请求和响应的结构分为header(必须)和body(可选)两部分
2)广泛用于浏览器、手机App与服务器的数据交互
3)Java提供了HttpURLConnection实现HTTP客户端
GET请求
URL url = new URL("http://www.example.com/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
int code = conn.getResponseCode();
try(InputStream input = conn.getInputStream()){
// 读取响应数据
}
conn.disconnect();
POST请求
URL url = new URL("http://www.example.com/login");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
byte[] postData = "loginName=test&password=123456".getBytes("UTF-8");
conn.setRequestProperty("Content-Type", "application/x-wwww-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(postData.length));
try(OutputStream output = conn.getOutputStream()){
output.write(postData);
}
int code = conn.getResponseCode();
try(InputStream input = conn.getInputStream()){
// 读取响应数据
}
conn.disconnect();
class Response {
final int code;
final byte[] data;
public Response(int code, byte[] data) {
this.code = code;
this.data = data;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(1024);
sb.append(code).append("\n");
String s = new String(data, StandardCharsets.UTF_8);
if (s.length() > 1024) {
sb.append(s.substring(0, 1024)).append("\n...");
} else {
sb.append(s);
}
return sb.toString();
}
}
public class HttpClient {
public static void main(String[] args) throws Exception {
Response resp = get("https://www.douban.com");
System.out.println(resp);
Map<String, String> postMap = new HashMap<>();
postMap.put("form_email", "test");
postMap.put("form_password", "password");
Response postResp = post("https://www.douban.com/accounts/login", "application/x-www-form-urlencoded",
toFormData(postMap));
System.out.println(postResp);
}
/**
* GET请求
* @param theUrl
* @return
*/
static Response get(String theUrl) {
System.err.println("GET: " + theUrl);
HttpURLConnection conn = null;
try {
URL url = new URL(theUrl);
conn = (HttpURLConnection) url.openConnection();
ByteArrayOutputStream responseBuffer = new ByteArrayOutputStream();
try (InputStream input = conn.getInputStream()) {
byte[] buffer = new byte[1024];
for (;;) {
int n = input.read(buffer);
if (n == (-1)) {
break;
}
responseBuffer.write(buffer, 0, n);
}
}
return new Response(conn.getResponseCode(), responseBuffer.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
/**
* POST请求
* @param theUrl
* @param contentType
* @param contentData
* @return
*/
static Response post(String theUrl, String contentType, String contentData) {
System.err.println("POST: " + theUrl);
HttpURLConnection conn = null;
try {
URL url = new URL(theUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
byte[] postData = contentData.getBytes(StandardCharsets.UTF_8);
conn.setRequestProperty("Content-Type", contentType);
conn.setRequestProperty("Content-Length", String.valueOf(postData.length));
try (OutputStream output = conn.getOutputStream()) {
output.write(postData);
}
ByteArrayOutputStream responseBuffer = new ByteArrayOutputStream();
try (InputStream input = conn.getInputStream()) {
byte[] buffer = new byte[1024];
for (;;) {
int n = input.read(buffer);
if (n == (-1)) {
break;
}
responseBuffer.write(buffer, 0, n);
}
}
return new Response(conn.getResponseCode(), responseBuffer.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
static String toFormData(Map<String, String> map) throws IOException {
List<String> list = new ArrayList<>(map.size());
for (String key : map.keySet()) {
list.add(key + "=" + URLEncoder.encode(map.get(key), "UTF-8"));
}
return String.join("&", list);
}
}
RMI
RMI:Remote Method Invocation
1)RMI远程调用是针对Java语言的一种远程调用
2)远程接口必须继承自Remote
3)远程方法必须抛出RemoteException
4)客户端调用RMI方法和调用本地方法类似
5)RMI方法调用被自动通过网络传输到服务器端
6)服务器端通过自动生成的stub类接收远程调用请求
Clock类
public interface Clock extends Remote{
LocalDateTime currentTime() throws RemoteException;
}
public class ClockImpl implements Clock {
@Override
public LocalDateTime currentTime() throws RemoteException {
return LocalDateTime.now();
}
}
服务器端
public class ClockServer {
public static void main(String[] args) throws Exception {
Clock impl = new ClockImpl();
Clock stub = (Clock) UnicastRemoteObject.exportObject(impl, 1099);
LocateRegistry.createRegistry(1099);
Registry registry = LocateRegistry.getRegistry();
registry.bind("Clock", stub);
System.out.println("Clock server ready.");
}
}
客户端
public class ClockClient {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.getRegistry(null); // null = "localhost"
Clock clock = (Clock) registry.lookup("Clock");
LocalDateTime dt = clock.currentTime();
System.out.println("RMI result: " + dt);
}
}
JDBC编程
关系型数据库:建立在关系模型上,基本结构是表,主键用于唯一标识记录,外键用于引用其他表的主键数据,通外键关联实现一对一、一对多和多对多关系
主流关系数据库:
1)商业:Oracle、SQL Server、DB2、Sybase
2)开源:MySQL、PostgreSQL
3)桌面:Access
MySQL
MySQL基本使用
// 1)进入MySQL命令行:
mysql> mysql -u root -p (输入密码)
// 2)切换到test数据库:
mysql> use test;
// 3)查看数据库表:
mysql> show tables;
// 4)创建表:
mysql> create table classes(
-> id bigint not null auto_increment,
-> name varchar(10) not null,
-> primary key (id)
->);
// 5)删除表:
mysql> drop table classes;
// 6)退出MySQL客户端:
mysql> exit
SQL语句
1)DDL(Data Definition Language):用于创建表、删除表、修改表结构
2)DQL(Data Query Language):用于查询记录
3)DML(Data Manipulation Language):用于添加、删除、更新记录
JDBC
获取数据库连接
String JDBC_URL = "jdbc:mysql://localhost:3306/test";
String JDBC_USER = "root";
String JDBC_PASSWORD = "xxxx";
Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
// 访问数据库
conn.close();
查询
使用Statement(不推荐)和PreparedStatement(推荐)进行查询
查询结果是ResultSet类型
更新
使用PreparedStatement的executeUpdate()进行更新
更新操作包括UPDATE、INSERT和DELETE语句
更新结果是int类型
public class JdbcTest {
static final String JDBC_URL = "jdbc:mysql://localhost:3306/test?useSSL=false&characterEncoding=utf8&serverTimezone=UTC";
static final String JDBC_USER = "root";
static final String JDBC_PASSWORD = "yw@910714";
/**
* 加载驱动获得数据库连接
*
* @return
* @throws SQLException
*/
static Connection getConnection() throws SQLException {
return DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
}
public static void main(String[] args) throws Exception {
testInsert();
testDelete();
testUpdate();
testSelect();
}
/***************************************** insert start ***********************************************/
static void testInsert() throws Exception {
List<Student> students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
insertWithAutoGenerateId(new Student(2, "Tim", "M"));
insertWithId(new Student(999, 2, "Bob", "M"));
System.out.println("-- after insert --");
students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
}
/**
* 添加学生(带id)
* @param std
* @throws SQLException
*/
static void insertWithId(Student std) throws SQLException {
try (Connection conn = getConnection()) {
try (PreparedStatement ps = conn
.prepareStatement("INSERT INTO students (id, class_id, name, gender) VALUES (?, ?, ?, ?)")) {
ps.setObject(1, std.id);
ps.setObject(2, std.classId);
ps.setObject(3, std.name);
ps.setObject(4, std.gender);
int n = ps.executeUpdate();
System.out.println(n + " inserted.");
}
}
}
/**
* 添加学生(带id)
* @param std
* @throws SQLException
*/
static void insertWithAutoGenerateId(Student std) throws SQLException {
try (Connection conn = getConnection()) {
try (PreparedStatement ps = conn.prepareStatement(
"INSERT INTO students (class_id, name, gender) VALUES (?, ?, ?)",
Statement.RETURN_GENERATED_KEYS)) {
ps.setObject(1, std.classId);
ps.setObject(2, std.name);
ps.setObject(3, std.gender);
int n = ps.executeUpdate();
System.out.println(n + " inserted.");
try (ResultSet rs = ps.getGeneratedKeys()) {
if (rs.next()) {
long id = rs.getLong(1);
std.id = id;
}
}
}
}
}
/***************************************** insert end ***********************************************/
/***************************************** delete start ***********************************************/
static void testDelete() throws Exception {
List<Student> students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
delete(students.get(students.size() - 1).id);
System.out.println("-- after delete --");
students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
}
/**
* 根据id删除学生
* @param studentId
* @throws SQLException
*/
static void delete(long studentId) throws SQLException {
try (Connection conn = getConnection()) {
try (PreparedStatement ps = conn.prepareStatement("DELETE FROM students WHERE id=?")) {
ps.setObject(1, studentId);
int n = ps.executeUpdate();
System.out.println(n + " deleted.");
}
}
}
/***************************************** delete end ***********************************************/
/***************************************** update start ***********************************************/
static void testUpdate() throws Exception {
List<Student> students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
Student std = students.get(0);
std.classId = 2;
std.name = "Alice";
std.gender = "F";
update(std);
System.out.println("-- after update --");
students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
}
/**
* 更新学生信息
* @param std
* @throws SQLException
*/
static void update(Student std) throws SQLException {
try (Connection conn = getConnection()) {
try (PreparedStatement ps = conn
.prepareStatement("UPDATE students set class_id=?, name=?, gender=? WHERE id=?")) {
ps.setObject(1, std.classId);
ps.setObject(2, std.name);
ps.setObject(3, std.gender);
ps.setObject(4, std.id);
int n = ps.executeUpdate();
System.out.println(n + " updated.");
}
}
}
/***************************************** update end ***********************************************/
/***************************************** select start ***********************************************/
static void testSelect() throws Exception {
// Test 1
List<Student> students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
// Test 2
for (int i = 1; i <= 4; i++) {
List<Student> list = getStudentsOfClass(i);
System.out.println("Students of class " + i + ":");
for (Student student : list) {
System.out.println(student);
}
}
// Test 3
for (int i = 1; i <= 4; i++) {
System.out.println("Students of class " + i + ": "
+ getNumOfStudents(i));
}
}
/**
* 查询所有学生信息
*
* @return
* @throws SQLException
*/
static List<Student> getAllStudents() throws SQLException {
try (Connection conn = getConnection()) {
try (PreparedStatement ps = conn
.prepareStatement("SELECT * FROM students")) {
try (ResultSet rs = ps.executeQuery()) {
List<Student> list = new ArrayList<>();
while (rs.next()) {
// long id = rs.getLong(1); 注意:如果使用索引,index从1开始
long id = rs.getLong("id");
long classId = rs.getLong("class_id");
String name = rs.getString("name");
String gender = rs.getString("gender");
Student std = new Student(id, classId, name, gender);
list.add(std);
}
return list;
}
}
}
}
/**
* 根据班级查询学生信息
*
* @param theClassId
* @return
* @throws SQLException
*/
static List<Student> getStudentsOfClass(long theClassId)
throws SQLException {
try (Connection conn = getConnection()) {
try (PreparedStatement ps = conn
.prepareStatement("SELECT * FROM students WHERE class_id=?")) {
ps.setObject(1, theClassId);
try (ResultSet rs = ps.executeQuery()) {
List<Student> list = new ArrayList<>();
while (rs.next()) {
// long id = rs.getLong(1); 注意:如果使用索引,index从1开始
long id = rs.getLong("id");
long classId = rs.getLong("class_id");
String name = rs.getString("name");
String gender = rs.getString("gender");
Student std = new Student(id, classId, name, gender);
list.add(std);
}
return list;
}
}
}
}
/**
* 根据班级查询班级学生数量
*
* @param classId
* @return
* @throws SQLException
*/
static long getNumOfStudents(long classId) throws SQLException {
try (Connection conn = getConnection()) {
try (PreparedStatement ps = conn
.prepareStatement("SELECT COUNT(*) num FROM students WHERE class_id=?")) {
ps.setObject(1, classId);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
// long num = rs.getLong(1); 注意:如果使用索引,index从1开始
long num = rs.getLong("num");
return num;
}
throw new RuntimeException("Empty result set.");
}
}
}
}
/***************************************** select end ***********************************************/
}
事物
数据库事务(Transaction)具有ACID特性:
Atomicity:原子性
Consistency:一致性
Isolation:隔离性
Durability:持久性
事务隔离级别:是由于数据库允许多个连接同时执行事务引起的,在Java中当一个线程使用数据库连接更新数据,而另一个线程可能也在使用数据库连接更新数据,那么就会出现问题。
1)脏读:Dirty Read
例如:对于A和B两个事务,当事务A修改(update)了一条数据,但是还没有提交;这时事务B读到了事务A没有提交的数据的结果。那么,当事务A回滚时,事务B读到数据就是脏数据。
2)非重复读:Non repeatable Read
事务B两次相同的查询条件查询出来的结果不一致,这是因为在事务B两次查询过程中,事务A对数据进行了修改
3)幻读:Phantom Read
事务B两次相同的查询条件查询出来的结果为空,看上去是查询不到记录;但实际上事务A在事务B两次查询过程中插入了一条数据。这个时候事务B用该查询条件修改(update)这条记录是会生效的,事务B再次进行查询的时候,会发现多出来这样一条记录。
隔离级别 | 脏读 | 非重复读 | 幻读 |
---|---|---|---|
Read Uncommitted | Y | Y | Y |
Read Commited | Y | Y | |
Repeatable Read | Y | ||
Serializable |
public static void main(String[] args) throws Exception {
List<Student> students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
// commmit tx:
Connection conn = null;
try {
conn = getConnection();
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
conn.setAutoCommit(false);
updateName(conn, students.get(0).id, "Bob");
updateName(conn, students.get(1).id, "Alice");
conn.commit();
System.out.println("commit ok.");
} catch (Exception e) {
e.printStackTrace();
conn.rollback();
} finally {
if (conn != null) {
try {
conn.setAutoCommit(true);
conn.close();
} catch (SQLException e) {
System.err.println(e);
}
}
}
System.out.println("-- after commit tx --");
students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
// rollback tx:
conn = null;
try {
conn = getConnection();
conn.setAutoCommit(false);
updateName(conn, students.get(0).id, "小明");
updateName(conn, students.get(1).id, "小红");
throw new RuntimeException("will rollback");
} catch (Exception e) {
conn.rollback();
} finally {
if (conn != null) {
try {
conn.setAutoCommit(true);
conn.close();
} catch (SQLException e) {
System.err.println(e);
}
}
}
System.out.println("-- after rollback tx --");
students = getAllStudents();
for (Student student : students) {
System.out.println(student);
}
}
static void updateName(Connection conn, long id, String name) throws SQLException {
try (PreparedStatement ps = conn.prepareStatement("UPDATE students SET name=? WHERE id=?")) {
ps.setObject(1, name);
ps.setObject(2, id);
ps.executeUpdate();
}
}
连接池
JDBC连接池接口定义:javax.sql.DataSource
可以复用Connection,避免反复创建新连接,提高运行效率
可以配置连接池的详细参数
常用JDBC连接池的实现:HikariCP、C3P0、BoneCP、Druid
以HikariCP为例,先引入maven依赖:
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.7.1</version>
</dependency>
public static void main(String[] args) throws Exception {
DataSource dataSource = createDataSource();
List<Thread> threads = new ArrayList<>();
for (int i = 1; i <= 4; i++) {
final int classId = i;
Thread t = new Thread() {
public void run() {
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
List<Student> list = getStudentsOfClass(dataSource, classId);
System.out.println("Students of class " + classId + ":");
for (Student student : list) {
System.out.println(student);
}
}
};
threads.add(t);
}
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
t.join();
}
// 关闭DataSource:
((HikariDataSource) dataSource).close();
}
/**
* 配置连接池
* @return
*/
static DataSource createDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(JDBC_URL);
config.setUsername(JDBC_USER);
config.setPassword(JDBC_PASSWORD);
config.addDataSourceProperty("connectionTimeout", "1000"); // 连接超时:1秒
config.addDataSourceProperty("idleTimeout", "60000"); // 空闲超时:60秒
config.addDataSourceProperty("maximumPoolSize", "10"); // 最大连接数:10
return new HikariDataSource(config);
}
static List<Student> getStudentsOfClass(DataSource dataSource, long theClassId) {
try (Connection conn = dataSource.getConnection()) {
System.err.println("Using connection: " + conn);
try (PreparedStatement ps = conn.prepareStatement("SELECT * FROM students WHERE class_id=?")) {
ps.setObject(1, theClassId);
try (ResultSet rs = ps.executeQuery()) {
List<Student> list = new ArrayList<>();
while (rs.next()) {
// long id = rs.getLong(1); 注意:如果使用索引,index从1开始
long id = rs.getLong("id");
long classId = rs.getLong("class_id");
String name = rs.getString("name");
String gender = rs.getString("gender");
Student std = new Student(id, classId, name, gender);
list.add(std);
}
return list;
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
函数式编程
把函数作为基本运算单元,函数可以作为变量,函数可以接收函数,函数可以返回函数
Lambda表达式
JDK8引入了Lambda语法,用于简化单抽象方法接口的实现
Lambda语法实现了类型自动推断
单抽象方法接口被称为函数式接口,标注为@FunctionalInterface
Thread t = new Thread(new Runnable(){
@Override
public void run(){
System.out.println("start new method ...");
}
});
t.start();
// 改为Lambda表达式
Thread t = new Thread(() -> {
System.out.println("start new method ...");
});
t.start();
方法引用
如果某个方法签名和接口恰好一致:
可以直接传入引用 String::compareTo
Functional Interface可以传入:
1)接口的实现类(代码较繁琐)
2)Lambda表达式
3)符合方法签名的静态方法
4)符合方法签名的实例方法(实例类型被看做第一个参数类型)
5)符合方法签名的构造方法(实例类型被看做返回类型)
class SortedBy{
static int name(String s1, String s2){
return s1.compareTo(s2);
}
static int ignoreCase(String s1, String s2){
return s1.toLowerCase().compareTo(s2.toLowerCase());
}
static int length(String s1, String s2){
int len1 = s1.length();
int len2 = s2.length();
if(len1 == len2){
return s1.compareTo(s2);
}
return len1 < len2 ? -1 : 1;
}
}
public class Main {
public static void main(String[] args) {
String[] array = "Java Apple lambda functional OOP".split(" ");
Arrays.sort(array, SortedBy::name);
System.out.println(Arrays.toString(array)); // [Apple, Java, OOP, functional, lambda]
Arrays.sort(array, SortedBy::ignoreCase);
// Arrays.sort(array, String::compareToIgnoreCase); // String内置方法
System.out.println(Arrays.toString(array)); // [Apple, functional, Java, lambda, OOP]
Arrays.sort(array, SortedBy::length);
System.out.println(Arrays.toString(array)); // [OOP, Java, Apple, lambda, functional]
}
}
练习
public static void main(String[] args) throws Exception{
String[] array = new String[]{"orange", "apple", "blackberry", "peer"};
ExecutorService executor = Executors.newCachedThreadPool();
// 忽略大小写异步排序:
Future<String[]> f = executor.submit(new Callable<String[]>(){
public String[] call(){
String[] copy = Arrays.copyOf(array, array.length);
Arrays.sort(copy, new Comparator<String>(){
@Override
public int compare(String s1, String s2){
return s1.toLowerCase().compareTo(s2.toLowerCase());
}
});
return copy;
}
});
System.out.println("Original: " + Arrays.toString(array));
System.out.println(" Sorted: " + Arrays.toString(f.get()));
executor.shutdown();
}
// 使用Lambda简化代码:
public static void main(String[] args) throws Exception{
String[] array = new String[]{"orange", "apple", "blackberry", "peer"};
ExecutorService executor = Executors.newCachedThreadPool();
// 忽略大小写异步排序:
Future<String[]> f = executor.submit(() -> {
String[] copy = Arrays.copyOf(array, array.length);
Arrays.sort(copy, (s1, s2) -> {
return s1.toLowerCase().compareTo(s2.toLowerCase());
});
return copy;
});
System.out.println("Original: " + Arrays.toString(array));
System.out.println(" Sorted: " + Arrays.toString(f.get()));
executor.shutdown();
}
// 使用方法引用简化代码:
public static void main(String[] args) throws Exception{
String[] array = new String[]{"orange", "apple", "blackberry", "peer"};
ExecutorService executor = Executors.newCachedThreadPool();
// 忽略大小写异步排序:
Future<String[]> f = executor.submit(() -> {
String[] copy = Arrays.copyOf(array, array.length);
Arrays.sort(copy, String::compareToIgnoreCase);
return copy;
});
System.out.println("Original: " + Arrays.toString(array));
System.out.println(" Sorted: " + Arrays.toString(f.get()));
executor.shutdown();
}
// 输出结果
// Original: [orange, apple, blackberry, peer]
// Sorted: [apple, blackberry, orange, peer]
Stream
java.io | java.util.stream | |
---|---|---|
存储 | 顺序读写的byte / char | 顺序输出的任意Java对象 |
用途 | 序列化至文件 / 网络 | 内存计算 / 业务逻辑 |
java.util.List | java.util.stream | |
---|---|---|
元素 | 已分配并存储在内存 | 未分配,实时计算 |
用途 | 操作一组已存在的Java对象 | 惰性计算 |
1)提供了一套新的流式处理的抽象序列
2)支持函数编程、链式操作
3)Stream可以表示无限序列,并且大多数情况下是惰性求值的
创建Stream的三种方式:
1)通过指定元素、现有数组、现有Collection创建
Stream.of(T... t)
Arrays.stream(array)
collection.stream()
2)通过Supplier创建无限序列
3)通过其他类的相关方法创建
基本类型的Stream有:IntStream、LongStream、DoubleStream
练习:请用Stream<BigInteger>表示一个斐波那契数列
Stream.map
map()方法
1)将一个Stream的每个元素映射成另一个元素并生成一个新的Stream
2)可以讲一种元素类型转换成另一种元素类型
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
@FunctionalInterface
public interface Function<T, R>{
// 将T类型转换为R类型:
R apply(T t);
}
例如
Stream<Integer> s = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> ss = s.map((n) -> n * n); // 1, 4, 9, 16, 25
Stream.filter
filter()方法
1)将一个Stream的每个元素进行测试,通过测试的元素被过滤后生成一个新的Stream
2)用于排除不满足条件的元素
Stream<T> filter(Predicate<? super T> predicate);
@FunctionalInterface
public interface Predicate<T>{
// 判断元素t是否符合条件
boolean test(T t);
}
例如
Stream<Integer> s = Stream.of(1, 2, 3, 4, 5);
Stream<Integer> ss = s.filter((n) -> n % 2 == 1); // 1, 3, 5
Stream.reduce
reduce()方法
1)将一个Stream的每个元素依次作用于BiFunction,并将结果合并
2)reduce是聚合方法 (例如 : Stream.of(1, 2, 6, 8, 9).count(); // 5)
3)聚合方法会立刻对Stream进行运算
Optional<T> reduce(BinaryOperator<T> accumulator);
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T, T, T>{
// Bi操作:两个输入,一个输出
T apply(T t, T u);
}
例如:离散值求和
Stream.of(1, 2, 6, 8, 9).reduce((acc, n) -> acc + n); // 26
计算过程
acc = 1 (取第一个元素初始化acc)
acc = acc + n = 1 + 2 = 3
acc = acc + n = 3 + 6 = 9
acc = acc + n = 9 + 8 = 17
acc = acc + n = 17 + 9 = 26
// 离散值求积
Stream.of(1, 2, 6, 8, 9).reduce((acc, n) -> acc * n); // 864
// 给定初始值求积
Stream.of(1, 2, 6, 8, 9).reduce(1000, (acc, n) -> acc * n); // 864000
其他操作
java.util.stream.Stream提供了许多实用的功能:
// 排序:
Stream<T> sorted() // 按元素默认大小排序(必须实现Comparable接口)
Stream<T> sorted(Comparator<? super T> cp) // 按指定Comparator比较的结果排序
// 去除重复元素:
Stream<T> distinct() // 返回去除重复元素的新Stream
// 截取:
Stream<T> limit(long) // 截取当前Stream的最多前N个元素
Stream<T> skip(long) // 跳过当前Stream的前N个元素
// 将两个Stream合并为一个Stream
Stream<Integer> s = Stream.concat(
Stream.of(1, 2, 3);
Stream.of(4, 5, 6);
);
// 如果Stream的元素是集合:
Stream<List<Integer>> s = Stream.of(
Arrays.asList(1, 2, 3);
Arrays.asList(4, 5, 6);
Arrays.asList(7, 8, 9);
);
// 转换为Stream<Integer>:
Stream<Integer> i = s.flatMap(list -> list.stream());
// 把一个Stream转换为可以并行处理的Stream:
Stream<String> s = ...
String[] result = s.parallel() // 变成一个可以并行处理的Stream
.sorted() // 可以进行并行排序
.toArray(String[]::new);
// 测试Stream的元素是否满足:
boolean allMatch(Predicate<? super T>) // 所有元素均满足测试条件
boolean anyMatch(Predicate<? super T>) // 至少有一个元素满足测试条件
1)转换操作:map、filter、sorted、distinct
2)合并操作:concat、flatMap
3)并行处理:parallel
4)聚合操作:reduce、count、max、min、sum、average
5)其他操作:allMatch、anyMatch、forEach
6)Stream转换为集合/数组类型:toArray、collect
练习:请用Stream API将用户输入的不规范的字符串转换为无前后空格,大写字母开头的规范字符串,并过滤掉空字符串和null,排序后返回。例如:用户输入
[“HELLO”, null, " “, “world”, " java”]
返回:[“Hello”, “Java”, “World”]
public static void main(String[] args) {
String[] array = {"HELLO", null, " ", "world", " java"};
Stream<String> stream = Arrays.stream(array)
.filter(s -> s != null && !s.trim().isEmpty())
.map(s -> s.toLowerCase().trim())
.map(s -> s.substring(0, 1).toUpperCase()+s.substring(1))
.sorted();
stream.forEach(System.out::println);
}