端口号
TCP通信的概述:
TCP通信的客户端:向服务器发送连接请求,给服务器发送数据,读取服务器回写的数据
表示客户端的类:
java.net.Socket:此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
套接字:包含IP地址和端口号的网络单位
构造方法:
Socket(String host, int port)
创建一个流套接字并将其连接到指定主机上的指定端口号。
参数:
String host:服务器主机的名称/服务器的IP地址
int port:服务器的端口号
成员方法:
OutputStream getOutputStream()
返回此套接字的输出流。
InputStream getInputStream()
返回此套接字的输入流。
void close()
关闭此套接字。
实现步骤:
- 创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号
- 使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
- 使用网络字节输出流OutputStream对象中的方法write,给服务器发送数据
- 使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
- 使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据
- 释放资源(Socket)
注意: - 客户端和服务器端进行交互,必须使用Socket中提供的网络流,不能使用自己创建的流对象
- 当我们创建客户端对象Socket的时候,就会去请求服务器,和服务器经过三次握手建立连接通路
这时如果服务器没有启动,那么就会抛出异常
如果服务器已经启动,那么就可以进行交互了
TCP通信的服务器端:接收客户端的请求,读取客户端发送的数据,给客户端回写数据
表示服务器的类:
java.net.ServerSocket:此类实现服务器的套接字
构造方法:
ServerSocket(int port)
创建绑定到特定端口的服务器套接字。
服务器必须明确一件事,必须得知道是哪个客户端请求的服务器
所以可以使用accept方法获取到请求的客户端对象Socket
成员方法:
Socket accept()
侦听并接受到此套接字的连接。
服务器的实现步骤:
- 创建服务器ServerSocket对象和系统要指定的端口号
- 使用ServerSocket对象中的accept方法,获取到请求的客户端对象Socket
- 使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
- 使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据
- 使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
- 使用网络字节输出流OutputStream对象中的方法write,给客户点回写数据
- 释放资源(Socket,ServerSocket)
综合案例:文件上传
代码实现:
1、客户端代码:
2、服务器端代码
函数式接口
函数式接口:有且只有一个抽象方法的接口,称之为函数式接口
当然接口中可以包含其他的方法(默认,静态,私有)
@FunctionInterface
作用:可以检测接口是否为一个函数式接口
是:编译成功
否:编译失败
函数式接口的使用:一般可以作为方法的参数和返回值类型
常见的函数式接口
Supplier接口
java.util.function.c< T>接口仅包含一个无参的方法:T get()。用来获取一个泛型参数指定类型的对象数据
Supplier< T>接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会产生什么类型的数据。
Consumer接口
java.util.function.Consumer< T>接口则正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定。Consumer接口中包含抽象方法void accept(T t),意为消费一个指定泛型的数据
Consumer接口是一个消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据,至于具体怎么消费(使用),需要自定义(输出,计算…)
Consmer接口的默认方法andThen
作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,再对数据进行消费
例如:
Consumer< String > con1
Consumer< String > con2
String s = “hello”;
con1.accept(s)
con2.accept(s)
连接两个Consumer接口,再进行消费
con1.andThen(con2).accept(s);谁写前边谁先消费
Predicate接口
java.util.function.Predicate< T>接口
作用:对某种数据类型的数据进行判断,结果返回一个boolean值
Predicate接口中包含一个抽象方法:
boolean test(T t):用来对指定数据类型数据进行判断的方法
结果:符合条件,返回true
不符合条件,返回false
逻辑表达式:可以连接多个判断的条件
&&:与运算符,有false则false
||:或运算符,有true则true
!:非(取反)运算符,非真则假,非假则真
需要:判断一个字符串,有两个判断的条件
- 判断字符串的长度是否大于5
- 判断字符串中是否包含a
两个条件必须同时满足,我们就可以使用&&运算符连接两个条件
默认方法and
Predicate接口中有一个方法and,表示并且关系,也可以用于连接两个判断条件
default Predicate< T> and (predicate<? super T> other){
Objects.requirNonNull(other);
return(t) -> this.test(t) && other.test(t);
}
方法内部的两个判断条件,也是使用&&运算符连接起来
默认方法or
需要:判断一个字符串,有两个判断的条件
- 判断字符串的长度是否大于5
- 判断字符串中是否包含a
满足一个条件即可,我们就可以使用||运算符连接两个条件
Predicate接口中有一个方法or,表示或者关系,也可以用于连接两个判断条件
default Predicate< T> and (predicate<? super T> other){
Objects.requirNonNull(other);
return(t) -> this.test(t) || other.test(t);
}
方法内部的两个判断条件,也是使用||运算符连接起来的
默认方法negate
需求:判断一个字符串的长度是否大于5
如果字符串的长度大于5,那么返回false
如果字符串的长度不大于5,那么返回true
所以我们可以使用取反符号!对判断的结果进去取反
Prediacate接口中有一个方法negate,也表示取反的意思
default Predicate< T> negate(){
return(t) -> !test(t);
}
Function接口
java.util.function.Function< T,R>接口来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件
Function接口中最主要的抽象方法为:R apply(T,R),根据类型T的参数获取类型R的结果
使用场景:例如将String类型转换为Integer类型
默认方法andThen
Stream流
获取流
java.util.Stream< T>是java 8新加入的最常用的接口。(这不是一个函数式接口)
获取一个流非常简答,有以下几种常用的方式:
- 所有的Collection集合都可以通过stream默认方法获取流
default Stream< E> stream() - Stream接口的静态方法of可以获取数组对应的流
static < T> Stream< T> of (T…values)
参数是一个可变参数,那么我们就可以传递一个数组
Stream流中的常用方法:forEach
void forEach(Consumer<? super T> action);
该方法接收一个Consumer接口函数,会将每一个流元素交给该函数进行处理
Consumer接口是一个消费型的函数式接口,可以传递Lambda表达式,消费数据
简单记:
forEach方法,用来遍历流中的数据
是一个终结方法,遍历之后就不能继续调用Stream流中的其他方法
Stream流中的常用方法:filter
用于对Stream流中的数据进行过滤
Stream< T> filter(Predicate<? super T> prediacate);
filter方法的参数Predicate是一个函数式接口,所以可以传递Lambda表达式,对数据进行过滤
Prediacate中的抽象方法:
boolean teat(T t);
Stream流属于管道流,只能被消费(使用)一次
第一个Stream流调用完毕方法,数据就会流转到下一个Stream上
而这时第一个Stream流已经使用完毕,就会关闭了
所以第一个Stream流就不能再调用方法了
Stream流中的常用方法:map
如果需要将流中的元素映射到另一个流中的时候,可以使用map方法
< R> Stream< R> map(Function<? super T,? extends R> mapper)
该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换成另一种R类型的流
Function中的抽象方法:
R apply(T t);
Stream流中的常用方法:count
count方法用于统计Stream流中元素的个数
Long count();
count方法是一个终结方法,返回值是一个Long类型的整数
所以不能再继续调用Stream流中的其他方法了。
Stream流中的常用方法:limit
limit方法用于截取流中的元素
limit方法可以对流进行截取,只取前n个。方法签名:
Stream< T> limit (long maxSize);
参数是一个long型,如果集合当前长度大于参数则进行截取;否则不进行操作
limit方法是一个延迟方法,只是对流中的元素进行截取,返回的是一个新的流,所以可以继续调用Stream流中的其他方法。
Stream流中的常用方法:skip
skip方法用于跳过元素
如果希望跳过前几个元素,可以使用skip方法获取一个截取之后的新流
Stream< T> skip (long n);
如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0 的空流。
Stream流中的静态方法:concat
concat方法用于把流组合到一起
如果有两个流,希望合并为一个流,那么可以使用Stream接口的静态方法concat
static < T> Stream< T > concat(Stream<? extend T> a,Stream <? extends T> b)
方法引用
通过对象名引用成员方法
使用前提是对象名是已经存在的,成员方法也是已经存在的,就可以使用对象名来引用成员方法
通过类名引用静态方法
类已经存在,静态成员方法也已经存在,就可以通过类名直接引用静态成员方法
通过super引用父类成员方法
通过this引用本类成员方法
类的构造器引用
数组的构造器引用