网络编程,泛型,和Stream流

目录

泛型:

泛型定义:

泛型类

泛型方法

泛型通配符

泛型擦除

总结

网络编程

网络编程三要素

UDP协议

TCP协议

基于UDP的方式进行网络传输

基于TCP协议进行网络传输

总结

Lamdba表达式

何时使用

函数式接口:

函数式接口分类

变量作用域

Lambda的优点

方法引用

1.概述

2.类静态方法引用

实例方法引用

Stream流

Stream操作分类

Stream 构成与创建

流的构成

操作符

中间操作符

终端操作符


泛型:

泛型定义:

Java 泛型是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

1、提高效率: 限定数据类型,只存某一种特定的类型,减少类型转化的时间

2、防止类型转换出现问题

泛型类

泛型类:把泛型定义在类上

public class 类名 <泛型类型1,...> {
    
}

定义泛型类,在类名后添加一对尖括号,并在尖括号中填写类型参数,参数可以有多个,多个参数使用逗号分隔

泛型方法

泛型方法概述:把泛型定义在方法上

public <泛型类型> 返回类型 方法名(泛型类型 变量名) {
    
}

泛型通配符

无边界的通配符:<?>, 比如List<?>

固定上边界的通配符,采用<? extends E>的形式

固定下边界的通配符,采用<? super E>的形式

泛型擦除

泛型信息只存在于代码编译阶段,但是在java的运行期(已经生成字节码文件后)与泛型相关的信息会被擦除掉,专业术语叫做类型擦除

所有泛型类的类型参数在编译时都会被擦除,虚拟机运行时中没有泛型,只有普通类和普通方法,从这一点上来说,Java中的泛型从某种程度上是一种语法糖

总结

1、泛型是什么?

本质:参数化的数据类型

将数据类型当作参数使用,定义的时候使用 类型占位符(T,E,K,V) ,实际使用时(创建对象时,调用方法时)传入具体的数据类型。

作用:编译期对数据类型进行检查约束。

2、如果想限定泛型的数据类型的范围怎么做?

上边界通配符: <? extends T>

下边界通配符:<? super T>

3、什么是泛型擦除?

泛型只在编译期进行类型检查(约束),生成的字节码中并不保留泛型的类型信息, 程序运行时会将泛型检查给抹去。

4、什么时候使用泛型?

定义是无法确定数据类型,使用时才能确定的

网络编程

网络编程三要素

1、IP地址

        要想让网络中的计算机能够互相通信,必须为计算机指定一个标识号,通过这个标识号来指定要接受数据的计算机和识别发送的计算机,而IP地址就是这个标识号,也就是设备的标识

2、端口:端口号就可以唯一标识设备中的应用程序,也就是应用程序的标识。

3、协议:常见的协议有TCP协议和UDP协议

UDP协议

UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据

由于使用UDP协议消耗资源少,通信效率高,所以通常都会用于音频、视频和普通数据的传输

TCP协议

传输控制协议(Transmission Control Protocol)

TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据出啊u念书。在TCP连接中必须明确客户端与服务器端,由于客户端向服务器端发出连接请求,每次连接的创建都需要经过“三次握手”

三次握手

TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠

第一次握手:客户端向服务器端发出连接请求,等待服务器确认

第二次握手:服务器端向客户端回送一个响应,通知客户端收到了连接请求

第三次握手:客户端再次向服务器端发送确认信息,确认连接

基于UDP的方式进行网络传输

  • UDP协议是一种不可靠的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接收数据的对象

  • 基于UDP协议的通信双方而言,没有客户端和服务器概念

  • DatagramSocket:用于发送或接收数据包的套接字

  • DatagramPacket:数据包

用到类:

DatagramSocket类:发送和接受数据报

方法类型描述
public DatagramSocket()构造方法构造DatagramSocket对象,不指定监听的端口
public DatagramSocket(int port)构造方法构造DatagramSocket对象,同时指定监听的端口
public void send (DatagramPacket p)方法发送数据报
public void receive(DatagramPacket p)方法接收数据报

DatagramPacket类:用来封装接受的发送的消息的。

方 法类 型描 述
public DatagramPacket(byte[] buf,int length)构造方法用来接收长度为 length 的数据包**,length 参数必须小于等于 buf.length**
public DatagramPacket(byte[] buf,int length,InetAddress address,int port)构造方法构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号
public byte[] getData()方法返回接收数据
public int getLength()方法返回要发送或接收数据 的长度
public InetAddress getAddress()方法返回机器的地址

发送数据的步骤

1、创建发送端的Socket对象(DatagramSocket)。如果没有指定端口,发送到本地主机所有可用端口(不常用),这里可以采用指定端口构造方法 DatagramSocket(),DatagramSocket(int port)|

2、创建数据,并把数据封装成DatagramPacket包裹,数据一定要转成字节数组,同时需要指定IP地址和端口 DatagramPacket(byte[] buf, int length, InetAddress address, int port)

3、调用DatagraSocket对象的方法发送数据包裹 void send(DatagramPacket p)

4、关闭发送端,释放资源

UDP接收数据 接收数据的步骤

1、创建接收端的Socket对象(DatagramSocket),指定端口 DatagramSocket(int port)

2、准备容器,封装成DatagramPacket包裹,用于接收数据 DatagramPacket(byte[] buf, int length)

3、调用DatagramSocket对象的方法,阻塞式接收包裹 void receive(DatagramPacket p)

4、解析数据包,并把数据在控制台显示 byte[] getData() 和 int getLength()

5、关闭接收端,释放资源

基于TCP协议进行网络传输

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,从而在通信的两端形成网络虚拟链路,一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信。

使用基于TCP协议的Socket网络编程实现,使用Socket对象来代表两端的通信端口

TCP协议基于请求-响应模式,第一次主动发起的程序被称为客户端(Client)程序

第一次通讯中等待连接的程序被称为服务器端(Sercer)程序

步骤

1、在服务端指定一个端口号来创建ServerSocket,并使用accept方法进行侦听,这将阻塞服务器线程,等待用户请求。

2、在客户端指定服务的主机IP和端口号来创建socket,并连接服务端ServerSocket,此时服务端accept方法被唤醒,同时返回一个和客户端通信的socket。

3、在客户端和服务端分别使用socket来获取网络通信输入/输出流,并按照一定的通信协议对socket进行读/写操作。

4、通信完成后,在客户端和服务端中分别关闭socket。

1、服务器端

  1. 创建ServerSocket(int port)对象

  2. 在Socket上使用accept方法监听客户端的连接请求

  3. 阻塞、等待连接的建立

  4. 接收并处理请求信息

  5. 将处理结果返回给客户端

  6. 关闭流和Socket对象

2、客户端

  1. 创建Socket(String host, int port)对象

  2. 向服务器发送连接请求

  3. 向服务器发送服务请求

  4. 接受服务结果(服务响应)

  5. 关闭流和Socket对象

    总结

    TCP与UDP的区别

    TCPUDP
    面向连接,可靠的数据传输无连接的,不可靠的数据库传输
    数据安全,有校验,数据不安全,缺乏校验
    速度慢效率高

Lamdba表达式

Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

使用 Lambda 表达式可以使代码变的更加简洁紧凑。

Lambda表达式的使用场景:用以简化接口实现

何时使用

通过上面的两个需求,发现Lamdba表达式很简单,那何时使用呢

需要显示创建函数式接口对象的地方,都可以使用

函数式接口:

如果说,⼀个接口中,要求实现类必须实现的抽象方法,有且只有⼀个这样的接口,就是函数式接口。使用@FunctionalInterface注解标注。

函数式接口分类

a.系统定义函数接口(Comparator, Runnable)

b.用户自定义函数接口

最为核心的有四个接口:

a.功能性接口:Function<T, R>

有输入参数,有返回值

是对接收一个T类型参数,返回R类型的结果的方法的抽象

通过调用apply方法执行内容

需求:给定一个字符串,返回字符串长度

 Function<String,Integer> function=(str)->str.length();
 Integer apply = function.apply("zhangsan");
 System.out.println(apply);

b.消费型接口:Consumer<T>

有输入参数,没返回值

对应的方法类型为接收一个参数,没有返回值

一般来说使用Consumer接口往往伴随着一些期望状态的改变

或者事件的发生,典型的forEach就是使用的Consumer接口

虽然没有任何的返回值,但是向控制台输出结果

Consumer 使用accept对参数执行行为

需求:输出字符串

 Consumer<String> f1 = str -> System.out.println(str);
 f1.accept("hello");

c.供给型接口:Supplier<T>

无传入参数,有返回值

该接口对应的方法类型不接受参数,但是提供一个返回值

使用get()方法获得这个返回值

需求:生成一个随机数字

  Supplier<Integer> f1 = () -> {
             Random random = new Random();
             return random.nextInt(100);
         };
         System.out.println(f1.get());

d.断言型接口:Predicate<T>

有传入参数,有返回值Boolean

该接口对应的方法为接收一个参数,返回一个Boolean类型值

多用于判断与过滤,使用test()方法执行这段行为

需求:输入字符串,判断长度是否大于0

 ​

变量作用域

lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

栗子1:对字符串数组按字符串长度排序

Lambda的优点

a.极大的减少代码冗余,同时可读性也好过冗长的匿名内部类

b.与集合类批处理操作结合,实现内部迭代,并充分利用现代多核CPU进行并行计算。之前集合类的迭代都是外部的,即客户代码。而内部迭代意味着由Java类库来进行迭代,而不是客户代码。

方法引用

1.概述

某些lambda表达式里面仅仅是调用了一个已存在的方法,在这种情况下

直接通过方法名称引用方法的形式可读性更高一些,这种形式就是方法引用

方法引用是一种更简洁易懂的lambda 表达式替换

其唯一用途就是支持Lambda的简写

函数接口中抽象方法的参数列表,必须与方法引用方法的参数列表保持一致

函数引用:引用⼀个已经存在的方法,使其替代lambda表达式完成接口的实现

2.类静态方法引用

语法:类::静态方法

范例:Integer::parseInt

Integer类的方法:public static int parseInt(String s) 将此String转换为int类型数据。

实例方法引用

引用对象的实例方法,其实就引用类中的成员方法

格式:对象::成员方法

范例: "HelloWorld"::toUpperCase

Stream流

Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。

Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势.

Stream操作分类

Stream的操作可以分为两大类:中间操作、终结操作

中间操作可分为:

  • 无状态(Stateless)操作:指元素的处理不受之前元素的影响

  • 有状态(Stateful)操作:指该操作只有拿到所有元素之后才能继续下去

终结操作可分为:

  • 短路(Short-circuiting)操作:指遇到某些符合条件的元素就可以得到最终结果

  • 非短路(Unshort-circuiting)操作:指必须处理完所有元素才能得到最终结果。

  • Stream 构成与创建

    流的构成

    当我们使用一个流的时候,通常包括三个基本步骤:

    获取一个数据源(source)→ 数据转换 → 执行操作获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道。

  • 操作符

    中间操作符

    通常对于Stream的中间操作,可以视为是源的查询,并且是懒惰式的设计,对于源数据进行的计算只有在需要时才会被执行,这类操作都是惰性化的,仅仅调用到这类方法,并没有真正开始流的遍历,真正的遍历需等到终端操作时。

  • 流方法含义
    filter用于通过设置的条件过滤出元素
    map接受一个函数作为参数。这个函数会被应用到每个元素上,并将其映射成一个新的元素(使用映射一词,是因为它和转换类似,但其中的细微差别在于它是“创建一个新版本”而不是去“修改”)
    distinct返回一个元素各异(根据流所生成元素的hashCode和equals方法实现)的流
    sorted返回排序后的流
    limit会返回一个不超过给定长度的流
    skip返回一个扔掉了前n个元素的流
    flatMap使用flatMap方法的效果是,各个数组并不是分别映射成一个流,而是映射成流的内容。所有使用map(Arrays::stream)时生成的单个流都被合并起来,即扁平化为一个流
    peek对元素进行遍历处理

    终端操作符

    Stream流执行完终端操作之后,无法再执行其他动作,否则会报状态异常,提示该流已经被执行操作或者被关闭,想要再次执行操作必须重新创建Stream流

    一个流有且只能有一个终端操作,当这个操作执行后,流就被关闭了,无法再被操作,因此一个流只能被遍历一次,若想在遍历需要通过源数据在生成流

    终端操作的执行,才会真正开始流的遍历

    流方法含义
    collect收集器,将流转换为其他形式
    forEach遍历流
    findFirst返回第一个元素
    findAny将返回当前流中的任意元素
    count返回流中元素总数
    max最大值
    min最小值
    anyMatch检查是否至少匹配一个元素,返回boolean
    allMatch检查是否匹配所有元素,返回boolean
    noneMatch检查是否没有匹配所有元素,返回boolean
    reduce可以将流中元素反复结合起来,得到一个值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值