JavaSE(十二)网络编程、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

在这里插入图片描述

发送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 UncommittedYYY
Read CommitedYY
Repeatable ReadY
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.iojava.util.stream
存储顺序读写的byte / char顺序输出的任意Java对象
用途序列化至文件 / 网络内存计算 / 业务逻辑
java.util.Listjava.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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
JavaSE网络编程采用的是基于TCP/IP协议的网络模型。这个模型包括客户端和服务器端两部分。客户端通过套接字(Socket)与服务器建立连接,服务器则监听客户端的连接请求并进行响应。 在Java中,可以使用Socket类和ServerSocket类来实现网络编程。Socket类用于建立客户端与服务器之间的通信连接,而ServerSocket类则用于创建服务器端的套接字,监听并接受客户端的连接请求。 客户端通过创建Socket对象,指定服务器的IP地址和端口号,然后通过Socket对象的方法与服务器进行通信。服务器端通过创建ServerSocket对象,指定服务器要监听的端口号,并通过accept()方法接受客户端的连接请求。一旦建立了连接,客户端和服务器端就可以通过输入流和输出流来进行数据的传输。 网络模型是基于TCP/IP协议的,因此可以使用Java的InputStream和OutputStream来进行数据的读写。客户端可以通过InputStream从服务器端接收数据,通过OutputStream向服务器端发送数据。服务器端则可以通过InputStream接收客户端发送的数据,通过OutputStream向客户端发送数据。 总结来说,JavaSE网络编程采用的是基于TCP/IP协议的网络模型,通过Socket和ServerSocket来实现客户端和服务器端之间的通信。通过InputStream和OutputStream来进行数据的读写。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [JavaSE——网络编程](https://blog.csdn.net/yzl1293346757/article/details/126192384)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [JavaSE学习——网络编程](https://blog.csdn.net/Demon_and_Angle_/article/details/126387829)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

讲文明的喜羊羊拒绝pua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值