欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JDK1.8 新特性(部分讲解)

程序员文章站 2022-06-04 22:58:53
...

JDK1.8 新特性

1、Lambda表达式的初体验

Lambda表达式就是匿名内部类的简化方案,替代品,Lambda表达式是从JDK1.8开始才有的特性。

Lambda表达式直观上给人一种非常简洁的感觉。

/*
    Lambda表达式就是为了替换匿名子类

 */
public class Demo01 {
    public static void main(String[] args) {
        //匿名子类的方式
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("匿名子类的方式");
                    }
                }
        ).start();


        //Lambda表达式
        new Thread(() -> {
            System.out.println("Lambda表达式方式");
        }).start();
        
    }
}

2. Lambda表达式的格式,及含有参数和返回值的Lambda写法

Lambda表达式的格式:参数列表,箭头,方法体

(参数列表) -> { 方法体 }

【代码实践】

含有参数和返回值的接口

public interface Calculate {
    int cal(int a, int b);
}

其lambda表达式如下

Calculate c2 = (int a, int b)->{
    return a+b;
};

System.out.println(c2.cal(10, 20));

【练习】

/*
定义Person类型,创建多个Person对象,放到集合中,让集合排序按照年龄的升序排序
排序后打印结果。
 */
public class Demo01 {
    public static void main(String[] args) {
        ArrayList<Person> list = new ArrayList<>();
        list.add(new Person(18, "迪丽热巴"));
        list.add(new Person(17, "古力娜扎"));
        list.add(new Person(20, "马儿扎哈"));
				//传统的匿名子类方式
        //Collections.sort(list, new Comparator<Person>() {
        //    @Override
        //    public int compare(Person o1, Person o2) {
        //        return o1.getAge() - o2.getAge();
        //    }
        //});
			
      	//Lambda 表达式
        Collections.sort(list, (Person o1, Person o2) -> {
            return o1.getAge() - o2.getAge();
        });

        System.out.println("list = " + list);

    }
}
public class Person {
    private int age;
    private String name;

    public Person() {
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

//此处省略:getter/setter方法
    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Person{");
        sb.append("age=").append(age);
        sb.append(", name='").append(name).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

3. Lambda表达式的省略格式

【参数列表】

  1. 参数列表的参数类型可以省略==【一省全省】==
  2. 只有一个参数,可以把小括号省略==【类型也要省略】==
  3. 如果参数列表中没有参数,括号不能省
public class Demo01 {
    public static void main(String[] args) {
        ArrayList<Person> list = new ArrayList<>();
        list.add(new Person(18, "迪丽热巴"));
        list.add(new Person(17, "古力娜扎"));
        list.add(new Person(20, "马儿扎哈"));
        //省略参数中的类型
        Collections.sort(list, (o1, o2) -> {
            return o1.getAge() - o2.getAge();
        });
        System.out.println("list = " + list);

        //参数列表中只有一个参数:类型+括号 都可以省略
        Printable p = str -> {
            System.out.println(str);
        };
        p.print("Hello");
        //如果参数列表中没有参数,括号不能省
        Runnable r = () -> {
            System.out.println("");
        };
        
    }
}

【方法体】

  1. 如果方法体中只有一个语句,那么大括号,return,分号==【一省全省】==
public class Demo01 {
    public static void main(String[] args) {
        ArrayList<Person> list = new ArrayList<>();
        list.add(new Person(18, "迪丽热巴"));
        list.add(new Person(17, "古力娜扎"));
        list.add(new Person(20, "马儿扎哈"));
        //省略参数中的类型
        Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());

        System.out.println("list = " + list);

        //参数列表中只有一个参数:类型+括号 都可以省略
        Printable p = str -> System.out.println(str);


        p.print("Hello");
        //如果参数列表中没有参数,括号不能省
        Runnable r = () -> System.out.println("");


    }
}

4. 函数式接口

  1. 什么接口称为函数式接口?

    只有一个抽象方法的接口,就是一个函数式接口,只有函数式接口才可以写Lambda表达式。

    注意:可以含有Object中equals抽象方法

    boolean equals(Object obj)
    

    可以有其他的默认方法,是私有方法,静态方法

  2. 如何自己定义函数式接口?

    定义一个接口,只要保证只有一个抽象方法,就是函数式接口

  3. 注解@FunctionalInterface的作用?

    这个注解可写可不写【建议写上,有保障】

    用来强制保证定义的接口就是函数式接口,如果一个接口被这个@FunctionalInterface注解了,那么意味着只能有一个抽象方法,否则报错。

/*
函数式接口就是能够写Lambda表达式的接口,【要求只能有一个抽象方法】
 */
public class Demo01 {
    public static void main(String[] args) {
        //Lambda表达式创建的Eatable的子类
        Eatable e1 = food -> System.out.println("享用:" + food);
        System.out.println("e1 = " + e1);

        e1.eat("山珍海味");
        e1.sleep();

    }
}
@FunctionalInterface  //为了告诉其他的程序员,我这个接口是函数式接口,别动
public  interface Eatable {
    void eat(String food);

   default void sleep(){
       System.out.println("边吃边睡!!");
   };
   //void fly();
}

5. 常用函数式接口:Consumer

Consumer:是一个函数式接口,含有一个抽象方法

抽象方法:

  void accept(T t);   这个方法接收一个参数,并把这个参数进行处理

特别常见的使用场景:集合遍历时

 				ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "AA", "BB", "CC", "DD");

			//匿名子类
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s+":");
            }
        });
			//Lambda方式
        list.forEach(e-> System.out.println(e));
/*
Consumer函数式接口,专门用来消费数据
抽象方法:
   void accept(T t);

接收一个数据,进行消费

 */
public class Demo01 {
    public static void main(String[] args) {

        test("HelloWorld", s -> System.out.println(s));
        test("Hello:World", str -> System.out.println(str.split(":")[0]));


        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "AA", "BB", "CC", "DD");


        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s+":");
            }
        });

        list.forEach(e-> System.out.println(e));
        list.forEach(str-> System.out.println("【"+str+"】"));
    }


    public static void test(String str, Consumer<String> consumer) {
        consumer.accept(str);
    }

}

6. 常用的函数式接口:Predicate

抽象方法:

boolean test(T t)

【练习】

/*
Predicate用来判断某个数据是否符合要求
抽象方法:
    boolean test(T t)


 */
public class Demo01 {
    public static void main(String[] args) {
        //要求密码只能6位
        test("123456", t -> t.length() == 6);
        test("123456789", t -> t.length() == 6);
        test("abcdefg", t -> t.length() >3);

    }


    public static void test(String password, Predicate<String> predicate) {
        boolean result = predicate.test(password);
        System.out.println("result = " + result);
    }

}

7.Stream流的使用

流式思想其实就根现实中的流水线作业相似

1. Stream流的获取

流的获取方式:
1)集合获取流
Collection集合中存在一个方法叫做:stream()可以直接将集合转化成流
Collection接口中存在一个默认方法:default Stream<T> stream()

2)数组获取流
Stream.of(T… values):这个方法是一个静态方法,可以直接传入数组【可变参数的底层就是数组】

/*
获取流的第一种方式:
    Collection中有一个方法stream(),可以直接将所有的Collection集合转换为流。
获取流的第二种方式:
    借助Stream中的静态方法,将单个的数据,散装的数据,数组直接转换为流对象
    Stream s=Stream.of("Hello");
    Stream s=Stream.of("Hello","World");

Map集合没有方法可以直接转换为流,可以先将Map的键或者值或者键值对对象转换为集合,通过集合转换为流对象


 */
public class Demo01 {
    public static void main(String[] args) {
        //获取流的第一种方式:
        Collection<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        //获取流的第二种方式:
        Stream<String> steam2 = Stream.of("AAAA");
        String[] arr = {"AAA", "BBB", "CCC"};
        Stream<String> stream3 = Stream.of(arr);

        //注意:Map没有直接的方法转换为流
        Map<String, String> map = new HashMap<>();
       // map.stream()
        Set<Map.Entry<String, String>> entries = map.entrySet();
        Stream<Map.Entry<String, String>> stream4 = entries.stream();

    }
}

2.Stream流中常用的方法

注意:stream流对象只能使用一次

/*
终结方法:
    public abstract void forEach(Consumer<? super String> action): 遍历Stream中的元素
    public abstract long count():获取流中元素的个数
非终结方法:
    public abstract Stream<String> filter(Predicate<? super String> predicate):筛选数据
    public abstract Stream<String> limit(long maxSize):获取前几个数据
    public abstract Stream<String> skip(long n):跳过前几个元素

    public static <T>Stream<String> concat(Stream<? extends String> a, Stream<? extends String> b):拼接两个流


注意:stream流对象只能使用一次
stream has already been operated upon or closed

 */
public class Demo01 {
    public static void main(String[] args) {
        //Stream流对象创建
        Stream<String> stream = Stream.of("AAA", "BB", "CCCC", "DDDDD", "EEE", "FFF");
        //filter:过滤
        stream = stream.filter(str->str.length()>=3);

        //limit:获取前几个元素
        stream =stream.limit(4);

        //skip: 跳过前几个元素
        stream = stream.skip(2);


        //concat:拼接两个流为一个
        Stream<String> stream1 = Stream.of("111", "222");

        stream = Stream.concat(stream, stream1);


        //forEach
        stream.forEach(str-> System.out.println(str));

        //count
        //long count = stream.count();
        //System.out.println("count = " + count);
    }
}

8.Stream得综合案例

现在有两个ArrayList集合存储队伍当中的多个成员姓名,要求使用传统的for循环(或增强for循环)依次进行以下若干操作步骤:

  1. 第一个队伍只要名字为3个字的成员姓名;
  2. 第一个队伍筛选之后只要前3个人;
  3. 第二个队伍只要姓张的成员姓名;
  4. 第二个队伍筛选之后不要前2个人;
  5. 将两个队伍合并为一个队伍;
  6. 打印整个队伍的姓名信息。

两个队伍(集合)的代码如下:

/*
使用流解决
传统得for遍历方式进行完成以下需求
 */
public class Demo02Stream {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");

        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("张三丰");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");

        //1. 第一个队伍只要名字为3个字的成员姓名;
        //2. 第一个队伍筛选之后只要前3个人;
        Stream<String> stream1 = one.stream()
                .filter(name -> name.length() == 3)
                .limit(3);

        //3. 第二个队伍只要姓张的成员姓名;
        //4. 第二个队伍筛选之后不要前2个人;
        Stream<String> stream2 = two.stream()
                .filter(name -> name.startsWith("张"))
                .skip(2);

        //5. 将两个队伍合并为一个队伍;
        //6. 打印整个队伍的姓名信息。
        Stream.concat(stream1, stream2)
                .forEach(name-> System.out.println("name = " + name));


    }
}
/*
传统得for遍历方式进行完成以下需求
 */
public class Demo01 {
    public static void main(String[] args) {
        List<String> one = new ArrayList<>();
        one.add("迪丽热巴");
        one.add("宋远桥");
        one.add("苏星河");
        one.add("老子");
        one.add("庄子");
        one.add("孙子");
        one.add("洪七公");

        List<String> two = new ArrayList<>();
        two.add("古力娜扎");
        two.add("张无忌");
        two.add("张三丰");
        two.add("赵丽颖");
        two.add("张二狗");
        two.add("张天爱");
        two.add("张三");

        //1. 第一个队伍只要名字为3个字的成员姓名;
        List<String> one1 = new ArrayList<>();
        for (String name : one) {
            if (name.length() == 3) {
                one1.add(name);
            }
        }
        //2. 第一个队伍筛选之后只要前3个人;
        List<String> one2 = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            one2.add(one1.get(i));
        }
        //3. 第二个队伍只要姓张的成员姓名;
        List<String> two1 = new ArrayList<>();
        for (String name : two) {
            if (name.startsWith("张")) {
                two1.add(name);
            }
        }

        //4. 第二个队伍筛选之后不要前2个人;
        List<String> two2 = new ArrayList<>();
        for (int i = 2; i < two1.size(); i++) {
            two2.add(two1.get(i));

        }

        //5. 将两个队伍合并为一个队伍;
        for (String name : one2) {
            two2.add(name);
        }
        //6. 打印整个队伍的姓名信息。

        for (String name : two2) {

            System.out.println("name = " + name);
        }
    }
}
相关标签: JDK1.8新特性