TCP通信:
通信步骤:服务器端先启动,服务器端不会主动请求客户端,必须使用客户端请求服务器端,两者之间就会建立一个逻辑连接,而这个连接包含一个IO对象,客户端和服务器端通过这个IO对象来进行通信,通信的数据不仅仅是字符,所以IO对象是一个字节流
package TCPDemo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 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)
*
* 注意事项:
* 1.客户端和服务器进行交互,必须使用Socket中提供的网络流,不能使用自己创建的对象
* 2.当我们创建客户端对象Socket的时候,就会去请求服务器和服务器建立连接
*/
public class TCPClientDemo {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);
OutputStream outputStream = socket.getOutputStream();
outputStream.write("你好服务器".getBytes());
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println(new String(bytes,0,len));
socket.close();
}
}
package TCPDemo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* ServerSocket套接字:
* 构造方法:
* ServerSocket(int port):创建绑定到特定端口的服务器套接字
* 服务器端必须知道是哪个客户端请求的服务器,所以可以使用accept方法请求获取到请求的客户端对象Socket
*
* 服务器实现步骤:
* 1.创建服务器ServerSocket对象和系统要指定的端口号
* 2.使用ServerSocket对象中的方法accept,获取到请求的客户端对象Socket
* 3.使用Socket对象中的方法getInputStream()获取网络字节输入流InputStream对象
* 4.使用网络字节输入流InputStream中的方法read读取服务器回写的数据
* 5.使用Socket对象中的方法getOutputStream()获取网络字节输出流OutputStream对象
* 6.使用网络字节输出流OutputStream对象中的方法write,给客户端发送数据
* 7.释放资源
*/
public class TCPServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(8888);
Socket socket = server.accept();
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println(new String(bytes,0,len));
OutputStream outputStream = socket.getOutputStream();
outputStream.write("收到谢谢".getBytes());
socket.close();
server.close();
}
}
上传文件案例:
函数式编程:
函数式接口:有且只有一个抽象方法的接口(但是可以包含其它的方法:默认、静态、私有)
package LambdaDemo;
@FunctionalInterface //检测是否是一个函数式接口
public interface MyFunctionalInterface {
//定义一个抽象方法
public abstract void method();
//void method1();
}
package LambdaDemo;
public class MyFunctionalInterfaceImpl implements MyFunctionalInterface {
@Override
public void method() {
}
}
package LambdaDemo;
/**
* 函数式接口的使用:一般作为方法的参数和返回值类型
*/
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表达式可以延时调用案例:
package LambdaDemo;
@FunctionalInterface
public interface MessageBuilder {
//定义一个拼接消息的抽象方法,返回被拼接的字符串
public abstract String builderMessage();
}
package LambdaDemo;
/**
* 使用Lambda优化日志案例
* Lambda的特点:延迟加载
* Lambda的使用前提,必须存在函数式接口
*/
public class LambdaDemo2 {
public static void main(String[] args) {
String msg1 = "hello";
String msg2 = "world";
String msg3 = "Java";
//参数MessageBuilder是一个函数式接口,所以可以传递Lambda表达式
showLog(1,()->{
//返回一个拼接好的字符串
return msg1+msg2+msg3;
});
/**
* 使用Lambda表达式作为参数传递,仅仅是把参数传递到showLog方法中
* 只有满足条件,日志等级是1,才会调用接口MessageBuilder中的方法builderMessage
* 才会进行字符串的拼接
* 如果条件不满足,日志等级不是1级,那么MessageBuilder接口中的方法builderMessage也不会执行
* 所以拼接字符串的代码也不会执行,不会存在性能的浪费
*/
}
//定义一个现实日志的方法,方法的参数传递日志的等级和MessageBuilder接口
public static void showLog(int level,MessageBuilder mb){
//对日志的等级进行判断,如果是1级,则调用MessageBuilder接口中的BuilderMessage方法
if(level==1){
System.out.println(mb.builderMessage());
}
}
}
函数式接口作为方法的返回值:
package LambdaDemo;
import java.util.Arrays;
import java.util.Comparator;
/**
* 如果一个方法的返回值类型是一个函数式接口,那么就可以返回一个Lambda表达式
* 当需要通过一个方法来获取java.util.Comparator接口类型的对象作为排序时,就可以调用该方法获取
*/
public class ComparatorDemo {
//定义一个方法,方法的返回值类型使用函数式接口
/*public static Comparator<String> getComparator(){
//方法的返回值类型是一个接口,那么我们可以返回这个接口的匿名内部类
return new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//按照字符串的降序排序
return o2.length()-o1.length();
}
};
}*/
//方法的返回值类型是一个接口,那么我们可以返回一个Lambda表达式
public static Comparator<String> getComparator() {
return (String o1, String o2)->{
//按照字符串的降序排序
return o2.length() - o1.length();
};
}
public static void main(String[] args) {
String[] arr = {"aaa","bb","ccccccccc","ddddddddddddddddd"};
Arrays.sort(arr,getComparator());
System.out.println(Arrays.toString(arr));
}
}
常用的函数式接口:
Supplier接口:
package LambdaDemo;
import java.util.function.Supplier;
/**
* 常用的函数式接口:Supplier
* Supplier<T> 接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据
*/
public class SupplierDemo {
//定义一个方法,方法的参数传递Supplier<T>接口,泛型执行String,get方法就会返回一个字符串
public static String getString(Supplier<String> supplier){
return supplier.get();
}
public static void main(String[] args) {
String str = getString(()->{
return "胡歌";
});
System.out.println(str);
}
}
Consumer接口:
package LambdaDemo;
import java.util.function.Consumer;
/**
* Consumer<T>接口与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定
* Consumer接口中包含抽象方法void accept(T,t),意为消费一个数据
*
* Consumer接口的的默认方法:andThen
* 作用:需要两个Consumer接口,可以把两个Consumer接口组合到一起,再对数据进行消费
*
* 比如:
* Consumer<String> con1
* Consumer<String> con2
* String str="hello";
* con1.accept(str);
* con2.accept(str);
* 等价于:con1.andThen(con2).accept(str);谁写前面,谁先消费
*/
public class ConsumerDemo {
public static void method(String name, Consumer<String> con){
con.accept(name);
}
public static void method2(String s,Consumer<String> con1,Consumer<String> con2){
/*con1.accept(s);
con2.accept(s);*/
con1.andThen(con2).accept(s);
}
public static void main(String[] args) {
method("赵丽颖",(String name)->{
//对传递的字符串进行消费
System.out.println(name);
});
method2("AAAbbb",
(String name)->{
System.out.println(name.toUpperCase());
},
(String name)->{
System.out.println(name.toLowerCase());
});
}
}
Predicate接口:
package LambdaDemo;
import java.util.function.Predicate;
/**
* java.util.function.Predicate<T>接口
* 作用:对某种数据类型的数据进行判断,返回布尔值
* Predicate接口中包含一个抽象方法:boolean test(T t):用来对指定的数据类型进行判断的方法
* 结果:符合条件,返回true
* 不符合条件,返回false
*
*
*/
public class PredicateDemo {
/**
* 定义一个方法
* 参数传递一个String类型的字符串
* 传递一个Predicate接口,泛型使用String
* 使用Predicate中的方法test对字符串进行判断,并把判断结果进行返回
*/
public static boolean checkString(String s, Predicate<String> pre){
return pre.test(s);
}
/**
*
* @param s 传入的字符串
* @param pre1 判断字符串长度是否大于5
* @param pre2 判断字符串是否包含a
* @return
*/
public static boolean checkString2(String s,Predicate<String> pre1,Predicate<String> pre2){
return pre1.and(pre2).test(s);
}
public static void main(String[] args) {
boolean flag = checkString("abcd",(String str)->{
//对参数传递的字符串进行判断,判断字符串的长度是否是大于5,并把判断结果返回
return str.length()>5;
});
System.out.println(flag);
System.out.println("==========================");
boolean flag1 = checkString2("abcdef",
(String str)->{
return str.length()>5;
},
(String str)->{
//boolean flag = false;
return str.contains("a");
});
System.out.println(flag1);
}
}
Function接口:
package LambdaDemo;
import java.util.function.Function;
/**
* java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据
* 前者称为前置条件,后者称为后置条件
* Function接口中最主要的抽象方法为:R apply(T t):根据类型T的参数获取类型R的结果
* 使用的场景例如:将String类型转换为Integer类型
*/
public class FunctionDemo {
/**
*
* @param s
* @param fun 使用Function接口中的方法apply,把字符串类型的整数,转换为Integer类型的整数
*/
public static void change(String s, Function<String,Integer> fun){
Integer apply = fun.apply(s);
System.out.println(apply);
}
public static void main(String[] args) {
String s= "1234";
change(s,(String str)->{
return Integer.parseInt(str);
});
}
}
流式思想:
Stream流:
filter->map->skip->count
获取流:
两种方式:
package LambdaDemo;
import java.util.*;
import java.util.stream.Stream;
/**
* 流的转换方式(2种):
* stream():
* of:
*/
public class StreamDemo2 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
Map<String,String> map = new HashMap<>();
Collection<String> values = map.values();
values.stream();
Set<Map.Entry<String, String>> entries = map.entrySet();
entries.stream();
int[] arr = {1,2,3,4};
Stream<int[]> arr1 = Stream.of(arr);
}
}
Stream流中的长用方法:
package LambdaDemo;
import java.util.stream.Stream;
/**
* void forEach(Consumer<? super T> action)
* 该方法接收一个Consumer接口函数,会将每一个流元素交给该函数进行处理
* Consumer接口是一个消费型的函数接口,可以传递Lambda表达式
*
* 简单记:
* forEach(参数是Consumer接口)方法,用来遍历流中的数据,是一个终结方法,遍历之后不能继续调用Stream流中的其它方法
*重写
*
* filter(参数是Predicate接口):
* 重写boolean test(T t)抽象方法
*
*/
public class StreamDemo3 {
public static void main(String[] args) {
Stream<String> stream = Stream.of("张三", "李四", "王五", "赵六", "田七");
/*stream.forEach((String name)->{
System.out.println(name);
});*/
stream.forEach(name->System.out.println(name));
System.out.println("====================================");
Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
Stream<String> stream2 = stream1.filter((String name) -> {
return name.startsWith("张");
});
stream2.forEach(name-> System.out.println(name));
System.out.println("==================================");
Stream<String> stringStream = Stream.of("1", "2", "3", "4");
Stream<Integer> integerStream = stringStream.map((String s) -> {
return Integer.parseInt(s);
});
integerStream.forEach(name-> System.out.println(name));
}
}
方法引用:
package LambdaDemo;
@FunctionalInterface
public interface printable {
public abstract void print(String s);
}
package LambdaDemo;
@FunctionalInterface
public interface Calcable {
int calsAbs(int number);
}
package LambdaDemo;
public interface Greeable {
void greet();
}
package LambdaDemo;
public class MethodRerObject {
public void printUpperCaseString(String str){
System.out.println(str.toUpperCase());
}
}
package LambdaDemo;
public class Human {
public void sayHello(){
System.out.println("Hello");
}
}
package LambdaDemo;
public class Man extends Human {
@Override
public void sayHello() {
System.out.println("hello,I'am man");
}
public void method(Greeable g){
g.greet();
}
public void show(){
/*method(()->{
Human h = new Human();
h.sayHello();
});*/
method(super::sayHello);
}
public static void main(String[] args) {
new Man().show();
}
}
package LambdaDemo;
public class PrintDemo {
public static void printString(printable pri){
pri.print("Hello World");
}
public static void main(String[] args) {
printString((s)->{
System.out.println(s);
});
/**
* 分析:Lambda表达式的目的,打印传递参数的字符串
* 把参数s传递给了System.out对象,调用out对象中的方法prinln对字符串进行了输出
* 注意:
* 1.System.out对象已经存在
* 2.println方法也是已经存在的
* 所以可以使用方法引用来优化Lambda表达式
*/
printString(System.out::println);
System.out.println("==============================");
/**
* 通过对象名引用成员方法
* 前提:对象名已经存在,成员方法也已经存在,就可以使用对象名来引用成员方法
*/
printString1((String s)->{
MethodRerObject obj = new MethodRerObject();
obj.printUpperCaseString(s);
});
MethodRerObject obj = new MethodRerObject();
printString1(obj::printUpperCaseString);
System.out.println("================================");
/**
* 通过类名引用静态方法
*
*/
int num = method(-10,(n)->{
return Math.abs(n);
});
System.out.println(num);
int num2 = method(-10, Math::abs);
System.out.println(num2);
}
public static void printString1(printable p){
p.print("hello");
}
public static int method(int number,Calcable c){
return c.calsAbs(number);
}
}