• day32_Stream&函数式接口


    • 函数式接口
    • 自定义函数式接口
    • 函数式编程
    • 常用的函数接口
    • Stream流
    • 方法引用

    文件上传优化

    文件的名称需要优化

    服务端,保存文件的名称如果固定,那么最终会导致服务器硬盘只保留一个文件,对上传的文件名称需要进行优化

    //文件名称定义规则
    "beautiful" + System.currentTimeMillis() + new Random().nextInt(1000000) + ".jpg"
    

    如何保证服务器端一直处于接收文件状态

    服务器端接收一个文件之后仍不关闭,使用循环进行实现

    //使用循环
    while(true){
    	Socket socket = serverSocket.accept();
       	...
    }
    

    服务器端接收客户端文件的效率问题

    服务器端在接收文件时,假如某个客户端传入一个大文件,此时就不能再接收其它客户端的文件,可以使用多线程技术优化提升效率

    while(true){
    	Socket socket = serverSocket.accept();
        //使用多线程技术,提高效率
        //一个客户端上传文件、开启一个线程完成此任务
        new Thread(new Runnable(){
            //重写run方法
            @Override
            public void run(){
                InputStream is = socket.getInputStream();//使用网络字节输入流对象
                //指定一个目录
                File file = new File("D:\upLoad");
                if(!file.exist){
                    file.mkdirs();
                }
                //防止同名文件被覆盖
                String fileName = "beautiful" + System.currentTimeMillis() + new Random().nextInt(1000000) + ".jpg";
                //构建一个本地的文件字节输出流对象
                FileOutputStram fos = new FileOutputStram(file+"\" + fileName);
                //完成读写
                int len = 0;
                char []chars =new char[1024]; 
                while((len = is.read(chars))!=-1){
                    fos.write(chars,0,len);
                }
            }
        }).start;
    }
    
    //serverSocket.close()   服务器不需要关闭
    

    函数式接口

    ​ 在Java当中指的是:有且仅有一个抽象方法的接口称为函数式接口。(其他方法不做要求)

    ​ 函数式接口,适用于函数式编程,在Java当中的函数式编程体现在Lambda表达式。只有确保接口当中有且仅有一个抽象方法,那么在Java中的Lambda才能进行顺利的推导(上下文环境)

    备注:"语法糖" 是指使用更加便利、快捷的语法方式(原理不变)例如,Lambda是匿名内部类的语法糖
    函数式编程四大核心接口:
    Predicate
    Function
    Supplier
    Consumer

    格式:只有确保接口当中有且仅有一个抽象方法即可
    修饰符  interface  接口名{
    	//只能定义一个抽象方法
        返回值  方法名(参数列表);
    }
    public interface FuntionInterface{
        int sum(int a,int b);
    }
    

    @FunctionalInterface注解

    ​ 作用:检测接口是不是函数式接口,只有有且仅有一个抽象方法与该注解相容,Java8中专门为函数式接口引入的新注解。

    自定义函数式接口的用途

    ​ 对于自定义函数式接口,一般充当方法的返回值和参数。

    函数式编程

    ​ 能够在兼顾Java的面向对象特性基础上,通过Lambda表达式与后面的方法引用,为开发者打开函数式编程的大门

    Lambda的延迟加载

    ​ 有些场景的代码运行执行后,结果不一定会被使用到,从而造成性能的浪费,而Lambda表达式是延迟执行的,正好可以解决此问题,提升性能。

    showLog(4,()->{  //前面条件不满足,后面表达式就不加载了。 
    	//重写run方法
    });
    //使用lambda表达式作为参数传递,只有满足条件,后面的接口方法实现才会被加载
    

    备注:实际上使用匿名内部类也可以达到同样的效果,只是将代码操作延迟到另外一个对象当中通过调用来完成、方法来完成后面的代码执行取决于前面的条件的判断结果

    ​ 在Java中,Lambda表达式是作为匿名内部类的替代品,如果一个方法的参数是一个函数式接口类型,那么可以使用Lambda表达式替代

    java.lang.Runnable接口就是一个函数式接口

    java.util.Comparator接口也是一个函数式接口

    public class LambdaDemo{
        //定义一个方法,返回值类型是Comparator接口
        public static Comparator<String> creatComparator(){
         		//常规
           	 	return new Comparator(){
                   @Override
                   public int compare(String o1,String o2){
                       return o1.length()-o2.length();
                   }
               	}
            	//Lambda
            	return (o1,o2) -> o1.length()-o2.length();
        }
        public static void main(String []args){
            String []strs = {"aaa","bbb","ccccc"};
            Arrays.sort(strs,creatComparator);// 调用获得的比较器
        }
    }
    

    常用的函数式接口

    ​ JDK提供了大量的常用函数式接口,丰富Lambda表达式的使用场景。他们主要在java.util.function包中被提供。

    ​ Supplier接口,该接口中有且仅有一个无参的方法 T get(),它是用来获取一个泛型参数指定类型的对象数据。由于该接口是一个函数式接口,可以使用Lambda表达式对其操纵。

    ​ Supplier接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get()方法就会生产什么类型的数据

    public static void main(String[] args) {
            //调用getString方法,参数传递一个Supplier<T>是一个函数式接口,可以使用Lambda
            System.out.println(getString(() ->{
                //生产返回一个字符串
                return  "Nike good boy!";
            }));
    }
    //定义一个方法,方法的参数传递一个Supplier<T>接口类型、泛型指定String,get方法就会返回一个String
        public static String getString(Supplier<String> sup){
            return sup.get();
        }
    

    ​ Consumer接口,被称为消费型接口,该接口刚好和Supplier接口相反,它不是用来生产一个数据,而是消费一个数据。至于数据的类型由泛型来指定。accept方法:消费一个指定泛型的数据

    //定义一个方法、方法的参数传递一个Consumer<String>接口,传递一个字符串值
        public static void consumer(String s,Consumer<String> con){
            con.accept(s); //使用accept消费数据
        }
    
        public static void main(String[] args) {
            //调用消费方法
            consumer("abcdefg",name->{
                //把里面的字符串改为大写
                System.out.println(new StringBuilder(name.toUpperCase()).reverse());//GFEDCBA
            });
        }
    

    默认方法:andThen

    如果一个方法的参数和返回值全是Consumer类型的,那么就可以实现这样的效果:消费数据的时候

    ,首先做一个消费的操作,再做一个消费的操作,实现组合。可以通过Consumer接口当中的默认方法andThen来实现

    //定义一个方法,方法的参数传递一个字符串和两个Consumer接口
        public static void consumer(String str, Consumer<String> con1,Consumer<String> con2){
            //con1.accept(str);
            //con2.accept(str);
            //andThen连续消费操作
            con1.andThen(con2).accept(str);
            //规则:con1连接con2,先执行con1消费数据,再执行con2消费数据
        }
        public static void main(String[] args) {
            //由于consumer方法的参数Consumer是一个函数式接口,可使用lambda
            consumer("Java31-中国最棒-都是业界大佬",(name1)->{
                //截取传入的字符串
                String sub = name1.substring(0, 6);
                System.out.println(sub);
            },(name2)->{
                String[] strs = name2.split("-");
                System.out.println(Arrays.toString(strs));
            });
        }
    

    andThen方法不允许传入null对象,否则抛出空指针异常。

    要想把两次消费的动作连接起来,需要传入两个Consumer接口,通过andThen方法实现消费动作

    练习:定义一个字符串数组,存储每一个人的信息,如 "张三,20,北京",存储多人上述信息,使用Consumer接口,按照指定格式进行打印输出:姓名:Xxx ;年龄:xx;地址:xx。要求

    1. ​ 将打印姓名的动作作为第一个Consumer接口的规则

    2. ​ 将打印年龄的动作作为第二个Consumer接口的规则

    3. ​ 将打印地址的动作作为第三个Consumer接口的规则

      public static void print(String[] arr, Consumer<String> consumer1, Consumer<String> consumer2, Consumer<String> consumer3) {
              for (String s1 : arr) {
                  consumer1.andThen(consumer2).andThen(consumer3).accept(s1);
                  //consumer1.accept(s1);
                  //consumer2.accept(s1);
                  //consumer3.accept(s1);//多个accept与使用andThen效果相同
              }
          }
          public static void main(String args[]) {   //精简Lambda
              String[] arr = {"张三,20,北京", "Lily,21,郑州", "Bob,23,纳尼", "二毛,30,上海", "狗剩,19,东京"};
              print(arr, (name) -> System.out.print("姓名:" + name.split(",")[0] + ";	")
              , (age) -> System.out.print("年龄:" + age.split(",")[1] + ";	")
              , (address) -> System.out.println("地址:" + address.split(",")[2] + ";"));
          }
      

    Stream流

    ​ 在Java1.8中,由于Lambda表达式这种函数式编程,JDK引入了一个全新的概念Stream流。用于解决已有集合类库的一些弊端。

    给定一些集合的数据
    public class StreamDemo{
        public static void main(String agrs[]){
            //构建一个集合
            List<String> list = new ArrayList();
            list.add("abc123");
            list.add("aaa22");
            list.add("bcd125");
            list.add("abcd120");
            list.add("bbb230");
            // 将字符串中包含1的元素取出
            List<String> list2 = new ArrayList();
            for(String str : list){
                if(str.contains("1")){
                    list2.add(str);
                }
            }
            // 并将元素字符串不超过6个的元素取出来
            List<String> list3 = new ArrayList();
            for(String str : list2){
                if(str.length()<=6){
                    list3.add(str);
                }
            }
            //遍历查看集合元素
            for(String str : list){
                System.out.println(str);
            }
        } 
    }
    

    ​ 当我们需要对集合中的元素进行操作的时候,总是需要对集合不停的遍历,遍历再遍历。烦不烦呐?很烦 !then:

    Java1.8可以使用Lambda表达式的衍生优化遍历集合的方式。---Stream流

    public class StreamDemo{
        public static void main(String agrs[]){
            //构建一个集合
            List<String> list = new ArrayList();
            list.add("abc123");
            list.add("aaa22");
            list.add("bcd125");
            list.add("abcd120");
            list.add("bbb230");
            // 将字符串中包含1的元素取出
            // 将元素字符串不超过6个的元素取出来
            //遍历查看集合元素
            list.stream()  //stream来自Collection接口中
                .filter(str -> str.contains("1"))
                .filter(str -> str.length()<=6)
                .forEach(str->System.out.println(str));
        } 
    }
    

    一般我们把流式思想称之为 "生产流水线"

  • 相关阅读:
    敏捷之旅--携程境外租车团队敏捷实践
    (一)LoadRunner安装
    性能测试,相关术语解析
    Newtonsoft.Json
    主流浏览器基于哪些内核?
    火狐浏览器与谷歌浏览器区别在哪里?
    带宽计算-大B与小b的区别
    loadrunner11录制不成功解决方法
    代码中的事务约束
    IOC框架Ninject实践总结
  • 原文地址:https://www.cnblogs.com/mitoris/p/14160687.html
Copyright © 2020-2023  润新知