java基础复习08
java基础复习
网络编程入门
5.6、软件结构
-
C/S结构︰全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。
-
B/S结构︰全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。
-
网络编程:就是在一定的协议下,实现两台计算机的通信的程序。
-
网络通信协议∶通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须I同时遵守才能完成数据交换。
-
TCP/IP协议﹔传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议来完成自己的需求。
网络通信协议分类
-
UDP:用户数据报协议(User Datagram Protocol)。UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
-
TCP∶传输控制协议(Transmission Control Protocol)。TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过"三次握手""。
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
- 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接。
网络编程三要素
-
协议∶计算机网络通信必须遵守的规则。
-
IP地址:指互联网协议地址 ( Internet Protocol Address),俗称IP。IP地址用来给一个网络中的计算机设备做唯一的编号。假如我们把"个人电脑"比作"一台电话"的话,那么"TP地址"就相当于"电话号码"。
- IPv4∶是一个32位的二进制数,通常被分为4个字节,表示成a.b.c.d的形式,例如192.168.65.100。其中a. b. c、d都是0~255之间的十进制整数,那么最多可以表示42亿个.
- IPV6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成 ABCD:EF01:2345:6789:ABCD:EF01:2345:6789,号称可以为全世界的每一粒沙子编上一个网址,这样就解决了网络地址资源数量不够的问题。
-
端口号:用两个字节表示的整数,它的取值范围是065535。其中,01023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
5.7、TCP通信程序
服务器端必须明确两件事情:
- 多个客户端同时和服务器进行交互,服务器必须明确和哪个客户端进行的交互
- 在服务器端有一个方法叫accept客户端获取到请求的客户端对象
- 多个客户端同时和服务器进行交互,就需要使用多个IO流对象
- 服务器是没有IO流的,服务器可以获取到请求的客户端对象Socket
- 使用每个客户端Socket中提供的IO流和客户端进行交互
- 服务器使用客户端的字节输入流读取客户端发送的数据
- 服务器使用客户端的字节输出流给客户端回写数据
简单记 :服务器使用客户端的流和客户端交互
表示客户端的类:
- java.net . Socket :此类实现客户端套接字(也可以就叫“套接字"")。套接字是两台机器间通信的端点。
- 套接字:包含了IP地址和编口号的网络单位
构造方法:
- Socket(String host, int port)创建一个流套接字并将其连接到指定主机上的指定端口号。
参数:
- String host:服务器主机的名称/服务器的IP地址
- int port:服务器的端口号
成员方法:
- Outputstream getOutputstream() 返回此套接字的输出流。
- InputStream getInputStream() 返回此套接字的输入流。
- void close() 关闭此套接字。
客户端实现步骤:
1、创建一个客户端对象.Socket,构造方法绑定服务器的IP地址和端口号
2、使用Socket对象中的方法getoutputstream()获取网络字节输出流Outputstream对象
3、使用网络字节输出流Outputstream对象中的方法write ,给服务器发送数据
4、使用Socket对象中的方法getInputStream()获取网络字节输入流Inputstream对象
5、使用网络字节输入流InputStream对象中的方法read ,读取服务器回写的数据
6、释放资源.(Socket)
注意:
- 客户端和服务器端进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象
- 当我们创建客户端对象Socket的时候,就会去请求服务器和服务器经过3次握手建立连接通路
- 这时如果服务器没有启动,那么就会抛出异常
如果服务器已经启动,那么就可以进行交互了
- 这时如果服务器没有启动,那么就会抛出异常
public class TcpClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 8888);
OutputStream os = socket.getOutputStream();
os.write("你好服务器".getBytes());
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
socket.close();
}
}
表示服务器的类:
- java.net. ServerSocket :此类实现服务器套接字。
构造方法:
- ServerSocket(int port) 创建绑定到特定端口的服务器套接字。
服务器端必须明确一件事情,必须得知道是哪个客户端请求的服务器所以可以使用accept方法获取到请求的客户端对象Socket
成员方法:
- Socket occept()侦听并接受到此套接字的连接。
服务器的实现步骤:
1、创建服务器ServerSocket对象和系统要指定的端口号
2、使用ServerSocket对象中的方法accept,获取到请求的客户端对象Socket
3、使用Socket对象中的方法getInputstream()获取网络字节输入流InputStream对象
4、使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据
5、使用Socket对象中的方法getOutputstream()获取网络字节输出流OutputStream对象
6、使用网络字节输出流OutputStream对象中的方法write ,给客户端回写数据
7、释放资源(Socket ,Serversocket)
public class TcpServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
Socket socket = server.accept();
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
OutputStream os = socket.getOutputStream();
os.write("收到!谢谢".getBytes());
socket.close();
server.close();
}
}
5.8、文件上传案例
- 原理:客户端读取本地的文件,把文件上传到服务器,服务器在把上传的文件保存到服务器的硬盘上
1、客户端使用 本地的字节输入流 读取要上传的文件
2、客户端使用网络字节输出流,把读取到的文件上传到服务器
3、服务器使用网络字节输入流,读取客户端上传的文件
4、服务器使用 本地字节输出流 ,把读取到的文件,保存到服务器的硬盘上
5、服务器使用网络字节输出流给客户端回写一个"上传成功”
6、客户端使用网络字节输入流,读取服务器回写的数据
7、释放资源
注意:
-
客户端和服务器和本地硬盘进行读写,需要使用自己创建的字节流对象(本地流)
-
客户端和服务器之问进行读写,必须使用Socket中提供的字节流对象(网络流)
文件上传的原理:就是文件的复制
- 明确:
- 数据源
- 数据目的地
客户端实现步骤:
1、创建一个本地字节输入流FileInputstream对象.,构造方法中绑定要读取的数据源
2、创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
3、使用Socket中的方法getOutputstream,获取网络字节输出流Outputstream对象
4、使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
5、使用网络字节输出流OutputStream对象中的方法write ,把读取到的文件上传到服务器
6、使用Socket中的方法getInputStream,获取网络字节输入流Inputstream对象
7、使用网络字节输入流Inputstream对象中的方法read读取服务回写的数据
8、释放资源(FileInputStream , Socket )
public class TcpClient {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("F:\\练习\\1.png");
Socket socket = new Socket("127.0.0.1", 8889);
OutputStream os = socket.getOutputStream();
int len =0;
byte[] bytes = new byte[1024];
while ((len= fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//为解决read方法的阻塞问题,可以写一个结束标记。void shutdownOutput(禁用此套接字的输出流)
//对于TCP套接字,任何以前写入的数据都将被发送,并且后跟TCP的正常连接终止序列。
socket.shutdownOutput();
InputStream is = socket.getInputStream();
while ((len= is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
fis.close();
socket.close();
}
}
服务器实现步骤:(假设服务器硬盘为d :\\upLoad\\1.jpg)
1、创建一个服务器ServerSocket对象,和系统要指定的端口号
2、使用ServerSocket对象中的方法accept,获取到请求的客户端socket对象
3、使用socket对象中的方法getInputStream ,获取到网络字节输入流InputStream对象
4、判断d : \\upLoad文件夹是否存在,不存在则创建
5、创建一个本地字节输出流FileOutputstream对象,构造方法中绑定要输出的目的地
6、使用网络字节输入流Inputstream对象中的方法read,读取客户端上传的文件
7、使用本地字节输出流FileoutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
8、使用Socket对象中的方法getOutputstream,获取到网络字节输出流outputstream对象
9、使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功”
10、释放资源(FileOutputstream, Socket,serversocket)
public class TcpServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8889);
/* 优化:让服务器一直处于监听状态(死循环accept方法)
有一个客户端上传文件,就保存一个文件
*/
while (true){
Socket socket = server.accept();
/* 优化:使用多线程技术,提高程序的效率
有一个客户端上传文件,就开启一个线程,完成文件的上传
*/
new Thread(new Runnable() {
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
File file = new File("D:\\upLoad");
if (!file.exists()){
file.mkdirs();
}
/* 优化:自定义一个文件的命名规则:防止同名的文件被覆盖
规则:域名+毫秒值+随机数
*/
String filename = "itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
//FileOutputStream fos = new FileOutputStream(file + "\\1.png");
FileOutputStream fos = new FileOutputStream(file + "\\"+filename);
int len = 0;
byte[] bytes = new byte[1024];
while ((len= is.read(bytes))!=-1){
fos.write(bytes,0,len);
}
socket.getOutputStream().write("上传成功".getBytes());
fos.close();
socket.close();
}catch (IOException e){
System.out.println(e);
}
}
}).start();
}
//server.close();
}
}
5.9、函数式接口
函数式接口在Java中是指: 有且仅有一个抽象方法的接口。
函数式接口,即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。只有确保接口中有且仅有一个抽象方法,Java中的Lambda才能顺利地进行推导。
- "语法糖"是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实底层的实现原理仍然是迭代器,这便是"语法糖"。从应用层面来讲,Java中的Lambda可以被当做是匿名内部类的"语法糖”,但是二者在原理上是不同的。
FunctionalInterface注解,作用:可以检测接口是否是一个函数式接口
@FunctionalInterface
public interface MyFunctionalInterface {
public abstract void method();
}
//函数式接口的使用:一般可以作为方法的参数和返回值类型
public class Demo {
public static void show(MyFunctionalInterface myInter){
myInter.method();
}
public static void main(String[] args) {
//调用show方法,方法的参数是一个接口,所以可以传递接口的实现类对象
show(new MyFunctionalInterfaceImpl());
//调用show方法,方法的参数是一个接口,所以我们可以传递接口的匿名内部类
show(new MyFunctionalInterface() {
@Override
public void method() {
System.out.println("使用匿名内部类重写接口中的抽象方法");
}
});
//调用show方法,方法的参数是一个函数式接口,所以我们可以Lambda表达式
show(()->{
System.out.println("使用Lambda表达式重写接口中的抽象方法");
});
//简化Lambda表达式,只有一行语句可以省略中括号和分号
show(()-> System.out.println("使用Lambda表达式重写接口中的抽象方法"));
}
}
6.0、函数式编程
Lambda的延迟执行
有些场景的代码执行后,结果不一定会被使用,从而造成性能浪费。而Lambda表达式是延迟执行的,这正好可以作为解决方案,提升性能。
@FunctionalInterface
public interface MessageBuilder {
//定义一个拼接消息的抽象方法,返回被拼接的消息
public abstract String builderMessage();
}
/*
使用Lambda优化日志案例
Lambda的特点:延迟加载
Lambda的使用前提,必须存在函数式接口
*/
public class DemoLambda {
//定义一个显示日志的方法,方法的参数传递日志的等级和MessageBuilder接口
public static void showLog(int level,MessageBuilder mb){
//对日志的等级进行判断,如果是1级,则调用MessageBuilder接口中的builderMessage方法
if (level==1){
System.out.println(mb.builderMessage());
}
}
public static void main(String[] args) {
//定义三个日志信息
String msg1="Hello";
String msg2="World";
String msg3="Java";
//调用showLog方法,参数MessageBuilder是一个函数式接口,所以可以传递Lambda表达式
showLog(1,()->{
return msg1+msg2+msg3;
});
/*
使用Lambda表达式作为参数传递,仅仅是把参数传递到showLog方法中只有满足条件,日志的等级是1级
才会调用接口MessageBuilder中的方法builderMessage
才会进行字符串的拼接
如果条件不满足,日志的等级不是1级
那么MessageBuilder接口中的方法builderMessage也不会执行所以拼接字符串的代码也不会执行
所以不会存在性能的浪费
*/
}
}
使用Lambda作为参数和返回值
/*
例如java.Lang.Runnable接口就是一个函数式接口,
假设有一个startThread方法使用该接口作为参数,那么就可以使用Lambda进行传参。
这种情况其实和Thread类的构造方法参数为Runnable没有本质区别。
*/
public class DemoRunnable {
//定义一个方法startThread,方法的参数使用函数式接口Runnable
public static void startThread(Runnable run){
//开启多线程
new Thread(run).start();
}
public static void main(String[] args) {
//调用startThread方法,方法的参数是一个接口,那么我们可以传递这个接口的匿名内部类
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->线程启动了");
}
});
//调用startThread方法,方法的参数是一个接口,那么我们可以传递Lambda表达式
startThread(()->{
System.out.println(Thread.currentThread().getName()+"-->线程启动了");
});
//优化Lambda表达式
startThread(()-> System.out.println(Thread.currentThread().getName()+"-->线程启动了"));
}
}
使用Comparator函数接口作为方法的返回值
public class DemoComparator {
/*
如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式。
当需要通过一个方法来获取一个java.util.Comparator接口类型的对象作为排序器时,就可以调该方法获取。
*/
public static Comparator<String> getComparator(){
//方法的返回值类型是一个接口,那么我们可以返回这个接口的匿名内部类
// return new Comparator<String>() {
// @Override
// public int compare(String o1, String o2) {
// return o2.length()-o1.length(); //按照字符串的降序排序
// }
// };
//方法的返回值类型是一个函数式接口,所以我们可以返回一个Lambda表达式
// return (String o1, String o2)->{
// return o2.length()-o1.length();
// };
//优化Lambda表达式
return (o1,o2)-> o2.length()-o1.length();
}
public static void main(String[] args) {
String[] array={"aaa","b","cccc","dddddddd"};//创建字符串数组
System.out.println(Arrays.toString(array));//输出数组
Arrays.sort(array,getComparator());//调用sort方法进行排序
System.out.println(Arrays.toString(array));//[dddddddd, cccc, aaa, b]
}
}
6.1、常用函数接口
Supplier接口
java.util.function.Supplier
Supplier
public class DemoSupplier {
public static String getString(Supplier<String> sup){
return sup.get();
}
public static void main(String[] args) {
//调用getString方法方法的参数Supplier是一个函数式接口,所以可以传递Lambda表达式
String s = getString(()->{
return "胡歌";
});
System.out.println(s);
//优化Lambda表达式
String s2 = getString(()-> "霍建华");
System.out.println(s2);
}
}
练习:求数组元素最大值
public class DemoTest {
public static int getMax(Supplier<Integer> sup){
return sup.get();
}
public static void main(String[] args) {
int[] array = {100,0,127,-50,33};
int maxValue = getMax(()->{
int max = array[0];
for (int i: array){
if (i>max){
max=i;
}
}
return max;
});
System.out.println("数组中最大值为"+maxValue);
}
}
Consumer接口
java.util.function.Consumer
Consumer接口是一个消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据至于具体怎么消费(使用),需要自定义(输出,计算...)
public class DemoConsumer {
public static void method(String name, Consumer<String> con){
con.accept(name);
}
public static void main(String[] args) {
//调用method方法,传递字符串姓名,方法的另一个参数是Consumer接口,是一个函数式接口,所以可以传递Lambda表达式
method("赵丽颖",(String name)->{
//对传递的字符串进行消费
//直接输出字符串
System.out.println(name);//赵丽颖
//将字符串翻转输出
String reName = new StringBuffer(name).reverse().toString();
System.out.println(reName);//颖丽赵
});
}
}
Consumer接口的默认方法andThen
作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,在对数据进行消费
public class DemoAndThen {
public static void method(String s, Consumer<String> con1,Consumer<String> con2){
// con1.accept(s);
// con2.accept(s);
con1.andThen(con2).accept(s);//con1连接con2,先执行con1消费数据,在执行con2消费数据
}
public static void main(String[] args) {
//调用method方法,传递一个字符串,两个Lambda表达式
method("hello",
(t)->{
//消费方式,把字符串转换为大写输出
System.out.println(t.toUpperCase());
},
(t)->{
//消费方式,把字符串转换为小写输出
System.out.println(t.toLowerCase());
});
}
}
练习:打印数组信息
public class Demo02Test {
public static void printInfo(String[] array, Consumer<String> con1,Consumer<String> con2){
//遍历字符串数组
for (String message : array) {
con1.andThen(con2).accept(message);
}
}
public static void main(String[] args) {
String[] array={"迪丽热巴,18","古力娜扎,20","马尔扎哈,22"};
//消费方式:对message进行切割,获取姓名,按照指定的格式输出
printInfo(array,
(message)->{
String name = message.split(",")[0];
System.out.print("姓名:"+name);
},
(message)->{
String age = message.split(",")[1];
System.out.println("。年龄:"+age);
});
}
}
Predicate接口
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用java.util.function.Predicate
Predicate接口中包合一个抽象方法:booleon test(T t):用来对指定数据类型数据进行判断的方法
public class Demo01Predicate {
public static boolean checkString(String s, Predicate<String> pre){
return pre.test(s);
}
public static void main(String[] args) {
String s = "abcde";
//调用checkString方法对字符串进行校验,参数传递字符串和Lambda表达式
// boolean b =checkString(s,(String str)->{
// //对参数传递的字符串进行判斯,判断字符串的长度是否大于5,并把判断的结果返回
// return str.length()>5;
// });
//优化Lambda
boolean b =checkString(s,str->str.length()>5);
System.out.println(b);
}
}
Predicate接口中有一个方法and,表示并且关系,也可以用于连接两个判断条件
练习:判断字符串是否大于5,字符串中是否含有a字符
public class Demo02Predicate_and {
/*
定义一个方法,方法的参数,传递一个字符串传递两个Predicate接口
一个用于判断字行串的长度是否大于5,—个用于判断字符串中是否包含a,两个条件必须同时满足
*/
public static boolean checkString(String s, Predicate<String> pre1,Predicate<String> pre2){
//return pre1.test(s)&& pre2.test(s);
return pre1.and(pre2).test(s);//等价于上一行代码
}
public static void main(String[] args) {
String s ="abcdef";
boolean b = checkString(s, (String str)->{
return str.length()>5;
},(String str)->{
return str.contains("a");
});
System.out.println(b);
}
}
Predicate接口中有一个方法or ,表示或者关系,也可以用于连接两个判断条件
public class Demo03Predicate_or {
public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2){
//return pre1.test(s)|| pre2.test(s);
return pre1.or(pre2).test(s);//等价于上一行代码
}
public static void main(String[] args) {
String s ="abcdef";
boolean b = checkString(s, (String str)->{
return str.length()>5;
},(String str)->{
return str.contains("a");
});
System.out.println(b);
}
}
Predicate接口中有一个方法negate,也表示取反的意思
public class Demo04Predicate_negate {
public static boolean checkString(String s, Predicate<String> pre){
//return !pre.test(s);
return pre.negate().test(s);
}
public static void main(String[] args) {
String s ="abc";
boolean b=checkString(s,(String str)->{
return str.length()>5;
});
System.out.println(b);
}
}
练习:筛选性别为女,名字为4个字的信息
public class Demo05Test {
public static ArrayList<String> filter(String[] arr, Predicate<String> pre1,Predicate<String> pre2){
//定义一个ArrayList集合,存储过滤之后的信息
ArrayList<String> list = new ArrayList<>();
//遍历数组,获取数组中的每一条信息
for (String s: arr){
//使用Predicate接口中的方法test对获取到的字符串进行判断
boolean b = pre1.and(pre2).test(s);
//对得到的布尔值进行判断
if (b){
//条件成立,两个条件都满足,把信息存储到ArrayList集合中
list.add(s);
}
}
return list;
}
public static void main(String[] args) {
String[] array = {"迪丽热巴,女","古力娜扎,女","马尔扎哈,男","赵丽颖,女"};
ArrayList<String> list=filter(array,(String s)->{
return s.split(",")[1].equals("女");
},(String s)->{
return s.split(",")[0].length()==4;
});
for (String s:list){
System.out.println(s);
}
}
}
Function接口
java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。
Function 接口中最主要的抽象方法为:R apply(T t),根据类型T的参数获取类型R的结果。
public class Demo01Function {
public static void change(String s, Function<String,Integer> fun){
Integer in = fun.apply(s);
System.out.println(in);
}
public static void main(String[] args) {
String s ="1234";
change(s,(String str)->{
return Integer.parseInt(str);
});
}
}
Function接口中有一个默认的andThen方法,用来进行组合操作。
练习:把string类型的"123",转换为Inteter类型,把转换后的结果加10,把增加之后的Integer类型的数据,转换为String类型
public class DemoFunction_andThen {
public static void change(String s, Function<String,Integer> fun1,Function<Integer,String> fun2){
String ss =fun1.andThen(fun2).apply(s);
System.out.println(ss);
}
public static void main(String[] args) {
String s ="123";
change(s,(String str)->{
return Integer.parseInt(str)+10;
},(Integer i)->{
return i+"";
});
}
}
练习:将字符串截取数字年龄部分,得到字符串;将上一步的字符串转换成为int类型的数字,将上一步的int数字累加100,得到结果int数字。
public class DemoTest {
public static int change(String s, Function<String,String> fun1,
Function<String,Integer> fun2,Function<Integer,Integer> fun3){
return fun1.andThen(fun2).andThen(fun3).apply(s);
}
public static void main(String[] args) {
String str="赵丽颖,20";
int num =change(str,(String s)->{
return s.split(",")[1];
},(String s)->{
return Integer.parseInt(s);
},(Integer i)->{
return i+100;
});
System.out.println(num);
}
}

浙公网安备 33010602011771号