JAVA-第五部分-网络、函数式接口、流及方法引用

205 阅读6分钟

网络

  • C/S B/S
  • 使用IP地址和端口号,保证数据准确无误地发送到对方计算机的指定软件上
  • IP地址->小区,端口号->门牌号
  • TCP image.png
  • 服务器是没有IO流的,获取客户端的Socket对象,使用其中提供的IO流与客户端进行交互;服务器要明确与哪个客户端交互
  • 套接字,包含IP地址和端口号的网络单位

Client

Socket socket = new Socket(InetAddress.getLocalHost(), 3213);
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();

Server

ServerSocket serverSocket = new ServerSocket(3213);
//客户端的socket
Socket socket = serverSocket.accept();
//输出流
OutputStream outputStream = socket.getOutputStream();
//获取输入流,读取客户端发过来的内容
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = inputStream.read(bytes);
System.out.println(new String(bytes, 0 ,len));
//回写
outputStream.write("收到".getBytes());

socket.close();
serverSocket.close();

注意事项

  • 在读取文件时候,客户端永远不会读到结束标志,所以导致发给服务器的数据也不会有结束标志,所以要发送结束标志
//结束标记
socket.shutdownOutput();

模拟BS架构

  • 读取服务器上的内容,并返回
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println(InetAddress.getLocalHost());
//浏览器解析服务器回写的html页面,如果有图片,会单独开启一个线程,读取服务图片
while (true) {
    Socket socket = serverSocket.accept();
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                InputStream inputStream = socket.getInputStream();
                //读请求头第一行
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                //切割
                String line = bufferedReader.readLine();
                System.out.println(line);
                //GET /day4-code/src/web/index.html HTTP/1.1 空格分隔;截取字符串,从第一个开始
                String htmlpath = line.split(" ")[1].substring(1);

                //读取html文件
                FileInputStream fileInputStream = new FileInputStream(htmlpath);
                OutputStream outputStream = socket.getOutputStream();
                
                //设置响应头
                outputStream.write("HTTP/1.1 200 OK\r\n".getBytes());
                outputStream.write("Content-Type: text/html\r\n".getBytes());
                // 必须要写入空行,否则浏览器不解析
                outputStream.write("\r\n".getBytes());

                //获取响应体,返回响应体
                int len = 0;
                byte[] bytes = new byte[1024];
                //不会读取到结束标记,导致服务器永远收不到结束标记
                while ((len = fileInputStream.read(bytes)) != -1) {
                    outputStream.write(bytes, 0 ,len);
                }

                fileInputStream.close();
                socket.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();

    //serverSocket.close();
}

函数式接口

  • 有且只有一个抽象方法的接口
  • @FunctionalInterface修饰接口,保证接口只有一个方法,否则报错
  • 使用Lambda作为接口实现类的语法糖传递,仅仅是把接口形式的参数传递进去
  • 作为参数返回
public static void main(String[] args) {
    String[] strings = {"31212", "dazxczxc", "dwa2", "312sdazxczxc"};
    Arrays.sort(strings, getComparable());
    System.out.println(Arrays.toString(strings));
    Arrays.sort(strings, ((o1, o2) -> o1.length() - o2.length()));
    System.out.println(Arrays.toString(strings));
}
private static Comparator<String> getComparable() {
    return (o1, o2) -> o2.length() - o1.length();
}

Supplier

  • 生产型接口,指定的接口泛型是什么类型,接口中的get方法就会生产什么类型的数据
public static void main(String[] args) {
    String s = getString(() -> "java");
    System.out.println(s);
}
public static String getString(Supplier<String> supplier) {
    return supplier.get();
}
  • 重写Supplierget方法,找出最大值
public static void main(String[] args) {
    Integer[] integers = {21231,3,5,7,123,3123,-30};
    //重写get方法
    Integer maxInteger = getMaxInteger(() -> {
        Arrays.sort(integers, (o1,o2) -> o2 - o1);
        return integers[0];
    });
    System.out.println(maxInteger);
}
public static Integer getMaxInteger(Supplier<Integer> supplier) {
    return supplier.get();
}

Consumer

  • 用于消费数据
public static void main(String[] args) {
    setString("xiaoming", str -> {
        System.out.println(str);
        //反转输出
        System.out.println(new StringBuffer(str).reverse());
    });
}

public static void setString(String str, Consumer<String> consumer) {
    consumer.accept(str);
}
  • andThen默认方法,如果参数是两个Consumer类型,就可以实现先做一个处理,再做下一个处理,谁写前面谁先消费
  • 消费的都是输入的初始字符串,第二步处理的并不是第一步的结果
public static void main(String[] args) {
    andThenConsumer("xiaoming,xiaozhang,xiaochen", s -> {
        String[] split = s.split(",");
        s += split[0];
        System.out.println(s);
    }, s -> {
        System.out.println(s.toUpperCase());
    });
}
public static void andThenConsumer(String str, Consumer<String> consumer1 , Consumer<String> consumer2) {
    consumer1.andThen(consumer2).accept(str);
}

Predicate

  • 对某个数据类型进行判断,返回boolean
  • test方法决定判断的方式
public static void main(String[] args) {
    boolean res = test("java", s -> "java".equals(s));
    System.out.println(res);
}
public static boolean test(String str, Predicate<String> predicate) {
    return predicate.test(str);
}
  • and默认方法,类似&&,表示并且关系,连接两个判断条件
public static void main(String[] args) {
    boolean andTestRes = andTest("jwewq", s -> s.length() > 2, s -> s.contains("a"));
    System.out.println(andTestRes);
}
public static boolean andTest(String str, Predicate<String> predicate, Predicate<String> predicate2) {
    return predicate.and(predicate2).test(str);
}
  • or默认方法,类似!!,表示或者关系
public static void main(String[] args) {
    boolean orTestRes = orTest("jwewq", s -> s.length() > 2, s -> s.contains("a"));
    System.out.println(orTestRes);
}

public static boolean orTest(String str, Predicate<String> predicate, Predicate<String> predicate2) {
    return predicate.or(predicate2).test(str);
}
  • negate默认方法,类似!,取反
public static void main(String[] args) {
    boolean negateTestRes = negateTest("java", s -> "java".equals(s));
    System.out.println(negateTestRes);
}

public static boolean negateTest(String str, Predicate<String> predicate) {
    return predicate.negate().test(str);
}

Function

  • 数据类型转换
public static void main(String[] args) {
    functionMethod("123",s -> Integer.valueOf(s));
}
private static void functionMethod(String str, Function<String, Integer> function) {
    System.out.println(function.apply(str));
}
  • andThen默认方法,组合操作,参数会传递,前面传递后会给后面处理
public static void main(String[] args) {
    functionAndThen("123", s -> Integer.valueOf(s) + 10, integer -> String.valueOf(integer));
}
private static void functionAndThen(String str, Function<String, Integer> function1, Function<Integer, String> function2) {
    System.out.println(function1.andThen(function2).apply(str));;
}
  • 三个Function接口,处理年龄
public static void main(String[] args) {
    handleAge("xiaoming-30", s -> s.split("-")[1], s -> Integer.parseInt(s), integer -> integer + 10);
}
private static void handleAge(String str, Function<String, String> function1, Function<String, Integer> function2, Function<Integer, Integer> function3) {
    System.out.println(function1.andThen(function2).andThen(function3).apply(str));;
}

  • 通过流进行过滤和输出,配合函数式接口
ArrayList<String> strings = new ArrayList<>();
strings.add("zhangsan");
strings.add("zhangsi");
strings.add("zhangwu");
strings.add("wangwu");
strings.add("zhaoliu");

strings.stream().filter(s -> s.startsWith("zhang")).filter(s -> s.length() == 7).forEach(s -> System.out.println(s));
  • 流的数据来源,可以是集合也可以是数组,可以进行内部迭代

获取流

  • Stream流属于管道流,只能被消费一次,第一个流使用完毕后,就转到下一个了,上一个已经被关闭,不能被调用
//集合
Set<String> set = map.keySet();
Stream<String> setStream = set.stream();
//转换数组
Stream<Integer> integerStream = Stream.of(312, 3213, 4214, 54);

终结方法

  • 使用终结方法后,流就结束了
  • forEach里面放着Consumer接口,使用数据
  • count输出数量
  • collect,将流转换为集合
ArrayList<String> strings = new ArrayList<>();
strings.add("123123");
strings.add("213123");
strings.add("1323123");
//直接转换成集合
List<Integer> collect = strings.stream().map(s -> Integer.parseInt(s)).collect(Collectors.toList());

//新建,针对一个元素新建集合;累加,将一个元素添加到这个集合;合并每个元素的结合
ArrayList<Object> collect1 = strings.stream().map(s -> Integer.parseInt(s)).collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
  • 最大值、最小值
//没有值则为1或者0
Integer integer = collect.stream().max(Integer::compare).orElse(1);
Integer integer1 = collect.stream().min(Integer::compare).orElse(0);

过滤方法

  • filter里面放着Predicate接口
Map<String, String> map = new HashMap<>();

map.put("zhangsan", "12");
map.put("zhang", "12");
map.put("zhasan", "32");

Stream<Map.Entry<String, String>> stream = map.entrySet().stream();
Stream<Map.Entry<String, String>> entryStream = stream.filter(stringStringEntry -> Integer.parseInt(stringStringEntry.getValue()) < 14);
entryStream.forEach(stringStringEntry -> System.out.println(stringStringEntry.getKey() + " - " + stringStringEntry.getValue()));

映射

  • map
  • 将流中的数据映射到另一个流中,且可以改变数据类型
List<String> list = new ArrayList<>();
list.add("131");
list.add("3123");
list.add("12311");
list.stream().map(s -> Integer.parseInt(s)).forEach(integer -> System.out.println(integer + 1000));

取用前几个

  • limit
list.stream().limit(7).forEach(s -> System.out.println(s));

跳过前几个

  • skip
list.stream().skip(3).forEach(s -> System.out.println(s));

去重和合并

  • 将一个集合的多个流,合并成一个流
  • flatMap 合并,扁平化处理
  • distinct 去重
//pointsList 类型为List<List<Integer>>
pointsList.stream().flatMap(Collection::stream).distinct().sorted().collect(toList());

组合

  • 静态方法concat
  • 数据类型可以不一样,但是要看具体怎么处理
Stream.concat(integer, list.stream()).forEach(s -> System.out.println(s));

方法引用

  • Lambda的简化
  • 前提,Lambda的方法体中使用的对象和方法是存在的
public static void main(String[] args) {
    printString(s -> System.out.println(s));
    printString(System.out::println);
}
private static void printString(Printable printable) {
    printable.print("hello");
}
  • ::引用运算符,Lambda传递的参数,一定要是引用方法中能接受的参数

自定义对象方法实现方法引用

  • 对象
public class MethodRefObject {
    public void printUpperCaseString(String str) {
        System.out.println(str.toUpperCase());
    }
}
  • 调用,对象名和成员方法都已经存在,针对Lambda方法体的优化
public static void main(String[] args) {
    printString(new MethodRefObject()::printUpperCaseString);
}
private static void printString(Printable printable) {
    printable.print("hello");
}

通过类名实现方法引用

  • 直接类名加::
  • 类名Math和方法abs都存在
public static void main(String[] args) {
    int abs = abs(-10, Math::abs);
    int abs1 = abs(-20, number -> Math.abs(number));
    System.out.println(abs);
    System.out.println(abs1);
}
private static int abs(int number, Calcable calcable) {
    return calcable.calsAbs(number);
}

子父类引用

public void method(Greetable greetable) {
    greetable.greet();
}

public void show() {
    method(super::hello);
    method(this::hello);
}

类的构造引用

public static void main(String[] args) {
    creatMan("zhangsan", name -> new Man(name));
    creatMan("lisi", Man::new);
}
public static void creatMan(String name, ManBuilder manBuilder) {
    System.out.println(manBuilder.builderMan(name).getName());
}

数据的构造引用

public static void main(String[] args) {
    int[] ints = creatArrary(10, int[]::new);
    System.out.println(ints.length);
}
public static int[] creatArrary(int length, ArraryBuilder arraryBuilder) {
    return arraryBuilder.builderArrary(length);
}