JAVASE17
一、四大内置函数型接口
Lambda的实现依赖于函数式接口,接口可以我们自己定义,当然也可以使用JDK已经提供好的一些函数式接口,这些接口基本已经能够满足我们的常用操作,并且在集合等框架中已经广泛地使用了,所以我们可以直接使用这些接口
四大内置函数型接口
消费型接口 Consumer
void accept(T t)
供给型接口 Supplier
T get()
函数型接口 Function<T,R>
R apply(T t)
断定型接口 Predicate
boolean test(T t)
我们可以这样理解:
消费性:只进不出
供给型:白手起家,空手套白狼
函数型:礼尚往来
断定行:鉴定评审
public static void main(String[] args) {
//消费型
testCom(15,m-> System.out.println("今天中午吃饭消费"+m));
testCom(5000,m-> System.out.println("给主播托马斯刷一个藏宝图花了"+m));
List<Integer> list = List.of(1,2,3,4,5,6);
list.forEach(i->System.out.println(i));
//供给型
//10个1~5之间的随机数
System.out.println(testSupplier(10,()-> (int)(Math.random()*(5-1+1)+1)));;
System.out.println(testSupplier(20,()-> (int)(Math.random()*(100-1+1)+1)));;
//函数型
System.out.println(strHandler(" 哈哈哈哈 ",str->str.trim()));;
System.out.println(strHandler(" 哈哈哈哈 ",str->str.substring(1,3)));;
//段言型
List<String> ls = List.of("abc"," ab","aaaaaaa","bbbb");
System.out.println(tesPredicate(ls,s-> s.length()>3));;
}
// 断定型接口 Predicate<T>
// 可以对一个List集合中的数据,进行某种规则的判断,返回满足要求的数据
/* public static List<String> tesPredicate(List<String> ls, Predicate<String> pre){
//存储满足条件要求的字符串
List<String> list = new ArrayList<>();
ls.forEach(s -> {
if(pre.test(s)){
list.add(s);
}
});
return list;
}*/
// 断定型接口 Predicate<T>
// 可以对一个List集合中的数据,进行某种规则的判断,返回满足要求的数据
public static List<String> tesPredicate(List<String> ls, Function<String,Boolean> pre){
//存储满足条件要求的字符串
List<String> list = new ArrayList<>();
ls.forEach(s -> {
if(pre.apply(s)){
list.add(s);
}
});
return list;
}
// 函数型接口 Function<T,R>
// 接收一个字符串,进行某种规则操作得到结果
public static String strHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
//供给型接口 Supplier<T>
//指定提供n个随机数,返回一个集合
public static List<Integer> testSupplier(int n, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
//循环产生n个随机数
for(int i=1;i<=n;i++){
list.add(sup.get());
}
return list;
}
//消费型: 有来无回
public static void testCom(double money, Consumer<Double> comsumer){
comsumer.accept(money);
}
二、方法引用
若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用是Lambda表达式的另一种表现形式),主要有三种语法格式:
使用要求:
当lambda体的实现就是通过调用其他方法实现的时候,lambda的结构就可以使用方法引用简化,直接引用那个方法就可以
方法引用:
对象::成员方法 :
1)lambda体是否通过引用另外一个方法实现的
2)并且抽象方法的参数列表作为方法内部所引用的方法的参数列表的时候,并且所引用方法的返回值与抽象方法的返回值保持一致保持一致
类名::静态方法
1)lambda体是否通过引用另外一个方法实现的
2)lambda的参数列表与返回值是否匹配引用方法的参数列表与返回值
3)是静态方法->类名::静态方法
类名::成员方法 :
1)lambda体是否是通过引用另外一个方法实现的
2)抽象的参数列表的第一个参数是否作为调用内部所引用方法的对象存在
3) 抽象方法参数列表的第二参数及以后是否与所引用方法的参数列表保持一致,返回值保持一致
4) 引用的方法时成员方法
public static void main(String[] args) {
test3();
}
//类名::成员方法
public static void test3(){
//比较两个字符串是否相等
//BiPredicate pre = (x,y) -> x.equals(y);
//判断是否可以使用类名::成员方法简化: 1)lambda体是否是通过引用另外一个方法实现的 2)抽象的参数列表的第一个参数是否作为调用内部所引用方法的对象存在 3) 抽象方法参数列表的第二参数及以后是否与所引用方法的参数列表保持一致,返回值保持一致 4) 引用的方法时成员方法
//方法引用简化
BiPredicate<String,String> pre = String::equals;
System.out.println(pre.test("zhangsan","zhangsan"));
//Comparator<Integer> com = (a,b)->Integer.compare(a,b);
Comparator<Integer> com =Integer::compare;
}
//类名::静态方法
public static void test2(){
//比较两个double类型的数据,返回最大的
//考虑是否能够使用方法引用简化: 1)lambda体是否通过引用另外一个方法实现的->是 2)lambda的参数列表与返回值是否匹配引用方法的参数列表与返回值->是 3)是静态方法->类名::静态方法
//BiFunction<Double,Double,Double> fun = (a,b)->Math.max(a,b);
//方法引用简化
BiFunction<Double,Double,Double> fun = Math::max;
System.out.println(fun.apply(1.1,2.2));
//字符串转为Integer
//Function<String,Integer> f = (s)->Integer.valueOf(s);
Function<String,Integer> f = Integer::valueOf;
Integer i = f.apply("234");
System.out.println(i);
}
//测试 对象::成员方法
public static void test1(){
//lmabda {} 中的行为是不是通过调用另外一个方法实现的 : 是通过调用println()方法实现的打印
PrintStream ps = System.out;
//Consumer<String> com = s -> System.out.println(s);
//Consumer<String> com = s -> ps.println(s);
//方法引用简化
//Consumer<String> com = ps::println;
Consumer<String> com = System.out::println;
com.accept("zhangsan");
//把集合中的每一个数据拿出来当做Consumer中accept的参数传递,写的方法 体就是把每一个参数打印输出
List.of(1,3,2,5,6,4).forEach(System.out::println);
List.of(1,3,2,5,6,4).forEach( s -> System.out.println(s));
}
构造器引用以及数组引用
public static void main(String[] args) {
Comparator<Integer> com = (x,y)->x-y; //不能使用方法引用简化
com = (x,y)->Demo03.test(x,y); //可以使用方法引用简化
com = Demo03::test;
System.out.println(com.compare(1,2));
//构造器引用 : lambda体是通过new关键字实现的,并且创建的对象就作为抽象方法的返回值存在
//Supplier<String> sup = ()->new String();
Supplier<String> sup = String::new; //因为接口中的抽象方法没有参数列表,匹配的构造器就没有参数列表
System.out.println(sup.get().length());
//Function<String,String> fun = (s)-> new String(s);
Function<String,String> fun = String::new; //因为抽象方法存在一个参数,匹配的构造器就是一个带参构造
//数组引用
//Function<Integer,String[]> sup2 = (i)->new String[i];
Function<Integer,String[]> sup2 = String[]::new;
System.out.println(sup2.apply(10).length);
System.out.println(Arrays.toString(sup2.apply(10)));
}
static int test(int x,int y){
return x-y;
}
三、网络编程
我们先对网页编程与网络编程进行区别:
网页编程: 是html以及js等工具,上层应用
网络编程: 底层数据,是数据的传输
IP: 定位节点
端口: 区分软件
URL: 统一资源定位符
传输层协议:
UDP: 相当于写信, 不安全,只管写,不管是否能够正确接收到 ,大小限制,效率高
TCP: 相当于打电话,基于连接,安全,大小没有限制,但是效率低
IP:
定位互联网中的每一个节点(电脑,路由器,服务器,手机…)
192.168.0.0~192.168.255.255 ->非注册IP,供组织内部使用的
IPV4 4个字节 32位 | IPV6
127.0.0.1 -> 本地IP
localhost: 本机 ->域名
IP 与 域名:
IP定位节点
人类对 字符更敏感,域名就是一种IP的字符变现形式
通过DNS服务器
InetAddress : 此类表示Internet协议(IP)地址。
public static void main(String[] args) throws UnknownHostException {
//static InetAddress getLocalHost() 返回本地主机的地址。
//static InetAddress getByName(String host) 根据主机名称确定主机的IP地址。
InetAddress id1 = InetAddress.getLocalHost();
InetAddress id2 = InetAddress.getByName("www.baidu.com");
System.out.println(id2);
//String getHostAddress() 返回文本表示中的IP地址字符串。
//String getHostName() 获取此IP地址的主机名。
System.out.println(id2.getHostName()); //主机名 域名
System.out.println(id2.getHostAddress()); //IP
}
①端口
区分不同软件
2个字节 0~65535之间的整数表示
但是8000以内的不建议使用,预留端口号
80: http协议
8080: tomcat
3306: mysql
1521: oracle
同一协议下端口号不能冲突
InetSocketAddress : 此类实现IP套接字地址(IP地址+端口号)它也可以是一对(主机名+端口号)
InetSocketAddress(String hostname, int port) 根据主机名和端口号创建套接字地址。
InetSocketAddress(InetAddress addr, int port) 根据IP地址和端口号创建套接字地址。
public static void main(String[] args) {
InetSocketAddress i1 = new InetSocketAddress("localhost",9999);
InetSocketAddress i2 = new InetSocketAddress("127.0.0.1",9999);
System.out.println(i2);
//int getPort() 获取端口号。
//InetAddress getAddress() 获取 InetAddress 。
//String getHostName() 获取 hostname 。
System.out.println(i1.getPort());
System.out.println(i1.getHostName());
System.out.println(i1.getAddress());
}
②URL:统一资源定位符
互联网的三大基石: http html url
组成:
协议 : http
域名 :
端口 : 80
资源 :
列如百度: http://www.baidu.com:80/index.html?username=zhangsan&password=123#a
public static void main(String[] args) throws IOException {
//url
URL url = new URL("http://www.baidu.com:80/index.html?username=zhangsan&password=123#a");
//String getFile() 获取此 URL的文件名。
//String getHost() 获取此 URL的主机名(如果适用)。
//String getPath() 获取此 URL的路径部分。
//int getPort() 获取此 URL的端口号。
//String getProtocol() 获取此 URL的协议名称。
//String getQuery() 获取此 URL的查询部分。
//String getRef() 获取此 URL的锚点(也称为“引用”)。
System.out.println(url.getProtocol());
System.out.println(url.getHost());
System.out.println(url.getPort());
System.out.println(url.getPath());
System.out.println(url.getQuery());
System.out.println(url.getRef());
System.out.println(url.getFile());
}
③协议
TCP:TCP(transfer control protocol) 打电话 面向连接、安全、可靠,效率低,没有大小限制,基于三次握手
UDP:UDP(UserDatagramProtocol ) 发送短信 非面向连接、不安全、数据可能丢失 、协议简单效率高 ,大小由限制 一般不超过60k
Socket套接字:
传输层为应用层开辟的一个小口子
TCP,UDP,面向socket编程
不同 的协议socket的实现方式不同
UDP协议
DatagramSocket : 此类表示用于发送和接收数据报包的套接字。
DatagramPacket : 该类表示数据报包。
发送端:
1.定义我是发送端 DatagramSocket(int port) 构造一个数据报套接字并将其绑定到本地主机上的指定端口。
2.准备数据
3.打包
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
4.发送 send(DatagramPacket p) 从此套接字发送数据报包。
5.关闭资源
注意: UDP 基于字节数组传输数据
Address already in use: Cannot bind 端口号冲突
//发送端
public static void main(String[] args) throws IOException {
System.out.println("----------------发送端----------------");
// 1.定义我是发送端 DatagramSocket(int port)
DatagramSocket client = new DatagramSocket(8888);
// 2.准备数据
String msg = "你好";
byte[] arr = msg.getBytes();
// 3.打包
DatagramPacket packet = new DatagramPacket(arr, 0, arr.length, new InetSocketAddress("localhost",9999));
// 4.发送 send(DatagramPacket p) 从此套接字发送数据报包。
client.send(packet);
// 5.关闭资源
client.close();
}
接收端:
1.定义我是接收端 DatagramSocket(int port) 构造一个数据报套接字并将其绑定到本地主机上的指定端口。
2.准备包裹,用来接收数据 DatagramPacket(byte[] buf, int offset, int length)
3.阻塞式接收数据 receive(DatagramPacket p) 从此套接字接收数据报包。
4.处理数据
5.关闭资源
public static void main(String[] args) throws IOException {
System.out.println("----------------接收端----------------");
// 1.定义我是接收端 DatagramSocket(int port) 构造一个数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket server = new DatagramSocket(9999);
// 2.准备包裹,用来接收数据
byte[] arr = new byte[1024];
DatagramPacket packet = new DatagramPacket(arr,0, arr.length);
// 3.阻塞式接收数据 receive(DatagramPacket p) 从此套接字接收数据报包。
server.receive(packet);
// 4.处理数据
// 5.关闭资源
//byte[] getData() 返回数据缓冲区。
//int getLength() 返回要发送的数据的长度或接收的数据的长度。
byte[] newArr = packet.getData();
System.out.println(new String(newArr,0,packet.getLength()));
// 5.关闭资源
server.close();
}
TCP协议
客户端
服务端
注意: tcp协议是基于字节流的
客户端:
实现基本流程
1.定义客户端 Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
2.准备数据
3.获取输出流
4.写出
5.刷出
6.关闭
public static void main(String[] args) throws IOException {
System.out.println("-----------------我是客户端-----------------");
// 1.定义客户端 Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
Socket client = new Socket("127.0.0.1",9898);
// 2.准备数据
String str = "中国";
// 3.获取输出流
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
// 4.写出
out.writeUTF(str);
// 5.刷出
out.flush();
// 6.关闭
out.close();
client.close();
}
服务器
1.定义服务器 ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
2.阻塞式监听 Socket accept() 侦听对此套接字的连接并接受它。
3.获取输入流
4.读取客户端传递的数据
5.处理数据
6.关闭
public static void main(String[] args) throws IOException {
System.out.println("-----------------服务端--------------------");
//1.定义服务器 ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
ServerSocket server = new ServerSocket(9898);
//2.阻塞式监听 Socket accept() 侦听对此套接字的连接并接受它。
Socket client = server.accept();
System.out.println("一个客户端连接成功.....");
//3.获取输入流
DataInputStream is = new DataInputStream(new BufferedInputStream(client.getInputStream()));
//4.读取客户端传递的数据
String msg = is.readUTF();
//5.处理数据
System.out.println(msg);
//6.关闭
is.close();
client.close();
server.close();
}
客户端的双向登录
接收用户名与密码
发送数据到服务端
public static void main(String[] args) throws IOException {
System.out.println("-----------------我是客户端-----------------");
//1.定义客户端 Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
Socket client = new Socket("127.0.0.1",9898);
//2.准备数据
String str = "username=laopei&password=123";
//3.获取输出流
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
//4.写出
out.writeUTF(str);
//5.刷出
out.flush();
//6.接收服务器端响应的数据
DataInputStream is = new DataInputStream(new BufferedInputStream(client.getInputStream()));
//7.读入数据
String result = is.readUTF();
//8.处理响应结果
System.out.println(result);
//9.关闭
is.close();
out.close();
client.close();
}
服务器双向登录
public static void main(String[] args) throws IOException {
System.out.println("-----------------服务端--------------------");
//1.定义服务器
ServerSocket server = new ServerSocket(9898);
//2.阻塞式监听
Socket client = server.accept();
System.out.println("一个客户端连接成功.....");
//3.获取输入流
DataInputStream is = new DataInputStream(new BufferedInputStream(client.getInputStream()));
//4.读取客户端传递的数据
String msg = is.readUTF();
//5.处理数据
//用户名:laopei 密码:123
String str = "username="+"laopei"+"&password="+"123";
System.out.println("客户端登录"+msg);
System.out.println("服务端拼接"+str);
//6.输出流
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
if(str.equals(msg)){
out.writeUTF("登录成功");
}else{
out.writeUTF("登录失败");
}
//7.刷出
out.flush();
//8.关闭
out.close();
is.close();
client.close();
server.close();
}