JDK8新特性学习笔记

JDK8新特性

Lambda表达式

之前存在的问题

使用匿名内部类
	1.定义了一个没有名字的类
	2.这个类实现了runnable接口
	3.创建了这个类的对象
存在的问题
	语法冗余
	Lambda表达式体现的是函数式编程思想,只需要将要执行的代码放到函数中(即方法中)
	使用时直接使用lambda表达式
new Thread(new Runnable(){
    @Override
    public void run(){
        System.out.println("线程执行")
    }
}).start();
new Thread(() -> {
    System.out.println("线程执行")
}).start();

标准格式

(参数列表) -> {}

省略格式

1.参数类型可以省略
2.小括号内只有一个参数,小括号省略
3.大括号内只有一条语句,省略大括号、return和分号

匿名内部类和Lambda表达式区别

1.所需类型不同
	匿名内部类:需要的类型可以是类,接口,抽象类
	Lambda表达式:只能是接口
2.抽象方法的数量不一样
	匿名内部类所需的接口中抽象方法的数量随意
	Lambda表达式所需的接口只能有一个抽象方法
3.实现原理不同
	匿名内部类是在编译后形成class文件
	Lambda表达式是在程序运行的时候动态生成class

常用内置函数式接口

JDK8接口新增的两个方法

jdk8之前的接口

interface 接口名{
    静态常量;
    抽象方法
}

jdk8接口

interface 接口名{
    静态常量;
    抽象方法;
    默认方法; //接口名不能调用,只能继承类对象 调用
    静态方法; //实现类不能继承
}
常用内置函数式接口

Supplier接口

==java.util.function.Supplier==接口,它意味着供给,对应的Lambda表达式需要"对外提供"一个符合泛型类型的对象

@FunctionalInterFace
public interface Supplier<T> {
    public abstract T get();
}

供给型接口,通过Supplier接口中的get方法可以得到一个值,无参有返回的接口

使用Lambda表达式返回数组元素最大值

使用Supplier接口作为方法参数类型,通过Lambda表达式求出int数组中的最大值,提示:接口的泛型请使用Integer类

public class DemoSupplier{
    public static void main(String[] args) {
        printMax(() -> {
         	int[] arr = {10, 20, 100, 30, 40, 50};
            //先排序,最后就是最大值
            Arrays.sort(arr);
            return arr[arr.length - 1]; //最大值
        });
    }
    
    private static void printMax(Supplier<Integer> supplier){
        int maxNum = supplier.get();
        System.out.prinln(maxNum)
    }
    
}

Consumer接口

==java.util.function.Consumer==接口,不是生产一个数据,而是消费一个数据,其数据类型由泛型参数决定

@FunctionalInterface
public interface Consumer<T> {
    public abstract void accept(T t);
}

使用Lambda表达式将一个字符串转成大写和小写的字符串

public class DemoConsumer{
    public static void main(String[] args) {
        test(s -> System.out.println(s.toLowerCase()));
            s -> System.out.println(s.toUpperCase()));
    }
    
    public static void test(Consumer<String> consumer1, Consumer<String> consumer2) {
        String str = "HelloWorld";
        //consumer1.accept(str);
        //consumer2.accept(str)
        //先执行1在执行2
        consumer1.andThen(consumer2).accept(str)l;
    }
}

Function接口

==java.util.function.Function<T,R>==接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件,有参数有返回值

@FunctionalInterface
public interface Function<T,R> {
    public abstract R apply(T t);
}

使用Lambda表达式将字符串转成数字

public class DemoFunction {
    public static void main(String[] args) {
        test(s -> Interger.parseInt(s));
    }
    
    public static void test(Function<String,Integer> function) {
        Integer in = function.apply("10");
        System.out.println(in);
    }
}
andThen方法两次操作,同上

Predicate接口

==java.util.function.Predicate==接口返回boolean类型结果,可以对某种类型的数据进行判断

@FunctionalInterface
public interface Predicate<T> {
    public abstract boolean test(T t);
}

使用Lambda判断一个人名如果超过3个字就认为是很长的名字

public class DemoPredicate {
    public static void main(String[] args) {
        test(s -> s.length() > 3, "迪丽热巴");
    }
    
    private static void test(Predicate<String> predicate, String str) {
        boolean veryLong = predicate.test(str);
        System.out.println(veryLong);
    }
}
and(Predicate<T> predicate)函数 与函数
    t1.and(t2).test(str)
    
or() 或函数
    
negate() 非函数  结果取反

方法引用

Lambda的冗余场景

使用Lambda表达式求一个数组的和

public class DemoMethodRefIntro{
    //求和
    public static void getMax(int[] arr) {
        int sum = 0;
        for(int n : arr){
            sum += n;
        }
        System.out.println(sum);
    }
    
    public static void main(String[] args) {
        /*printMax((int[] arr) -> {
            int sum = 0;
            for(int n : arr){
                sum += n;
            }
            System.out.println(sum);
        });*/
        //方法引用
        //让指定方法重写接口的抽象方法
        printMax(DemoMethodRefIntro::getMax);
    }
    
    private static void printMax(Consumer<T> consumer) {
        int[] arr = {10, 20, 30, 40, 50};
        consumer.accept(arr);
    }
}

方法引用的格式

符号表示 ::

应用场景:替代Lambda方法

常见引用方式:

​ 1.instanceName::methodName 对象::方法名

​ 2.ClassName::staticMethodName 类名::静态方法名

​ 3.ClassName::methodName 类名::方法名

​ 4.ClassName::new 类名::new调用构造器

​ 5.TypeName[]::new String[]:new调用数组的构造器

对象名::方法名

@Test
public void test(){
    Date now = new Date();
    Supplier<Long> su1 = () -> {
        return now.getTime();
    };
    
    Long aLong = su1.get();
    System.out.println(aLong);
    
}

//方法引用
/*
1.被引用的方法,参数要和接口中抽象方法的参数一样
2.当接口的抽象方法有返回值时,被引用的方法也必须有返回值
*/
@Test
public void test(){
    Date now = new Date();
    Supplier<Long> su1 = now::getTime;
    
    Long aLong = su1.get();
    System.out.println(aLong);
    
}

类名::静态方法

@Test
public void test(){
    Supplier<Long> Su = System::currentTimeMillis;
}

类名::实例方法

@Test
public void test(){
    
    //类名::实例方法  实际上会将第一个参数作为方法的调用者
    Function<String,Integer> f1 = String::length;
    
    int length = f1.apply("hello");
    System.out.println("length = " + length);
    
    
    /*
    BiFunction<T,U,R>
    R apply(T, U);
    */
    BiFunction<String, Integer, String> f2 = String::substring;
    String str2 = f2.apply("helloworld", 3);
    System.out.println(str2);
    
}

类名::new (自动调用构造器)

@Test
public void test(){
    Supplier<Person> su1 = Person::new;
	Person person = su1.get();
	System.out.println("Person =" + person);
}


//有参
@Test
public void test(){
	BiFunction<String, Integer, Person> bif = Person::new;
    Person person = bif.apply("zhangsan", 18);
    System.out.println(person);
}


数组::new (自动调用数组构造器)

@Test
public void test(){
    Function<Integer, int[]> f1 = int[]::new;
    int arr[] = f1.apply(10);
    System.out.println(Arrays.toString(arr));
}

集合之Stream流式操作

集合处理数据的弊端

@Test
public void test(){
    
    //ArrayList集合中存储数据
    //需求
    //1.拿到所有姓张的
    //2.再拿到张姓里面名字长度3个字的
    //3.打印
    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
    
    //1.拿到所有姓张的
    ArrayList<String> zhangList = new ArrayList();
    for(String name : list){
        if(name.startsWith("张")){
            zhangList.add(name);
        }
    }
        
    //2.拿到名字长度为3个字的
    ArrayList<String> threeList = new ArrayList();
    for(String name : zhangList){
        if(name.length == 3){
            threeList.add(name);
        }
    }
    
    //3.打印
    for(String name : threeList){
        System.out.println(name);
    }
    
}

Stream流式思想概述

注意:Stream和IO流没有任何关系

Stream流式思想类似于工厂车间的生产流水线,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序,在流水线上,通过多个工序让一个原材料加工成一个商品

@Test
public void test(){
    
    //ArrayList集合中存储数据
    //需求
    //1.拿到所有姓张的
    //2.再拿到张姓里面名字长度3个字的
    //3.打印
    ArrayList<String> list = new ArrayList<>();
    Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
    
    //1.拿到所有姓张的;2.拿到姓张的名字三个字的;3.打印
    list.stream()
        .filter((s) -> {
            return s.startsWith("张");
        })
        .filter((s) -> {
            return s.length() == 3;
        })
        .forEach((s) -> {
            System.out.println(s);
        })
    
}

获取Stream流的两种方式

根据Collection获取流

//根据Collection获取流
//Collection接口中有一个默认的方法,default Stream<E> stream()
List<String> list = new ArrayList();
Stream<String> stream1 = list.stream();

Set<String> set - new HashSet();
Stream<String> stream2 = set.stream();

Map<String, String> map = new HashMap();
Stream<String> stream3 = map.keySet().stream();
Stream<String> stream4 = map.values().stream();
Stream<Map.Entry<String, String>> stream5 = map.entrySet().stream();

Stream中的静态方法of获取流

由于数组对象不可能添加默认方法,所以Stream接口中提供了静态方法of

Stream<String> stream = Stream.of("aa","bb","cc");

String[] strs = {"aa","bb","cc"};
Stream<String> stream2 = Stream.of(strs);

//基本数据类型的数组不能使用Stream流,会将整个数组看作一个元素

Stream常用方法和注意事项

方法名方法作用返回值类型方法种类
count统计个数long终结
forEach逐一处理void终结
filter过滤Stream函数拼接
limit取用前几个Stream函数拼接
skip跳过前几个Stream函数拼接
map映射Stream函数拼接
concat组合Stream函数拼接

**终结方法:**返回值类型不再是Stream类型的方法,不再支持链式调用

**非终结方法:**返回值仍然是Stream类型的方法,支持链式调用

注意事项(重要)

1.Stream流调用终结方法后,就会被关闭

2.Stream非终结方法返回新的流

3.Stream不调用终结方法,中间的操作不会执行

常用方法

forEach

List<String> list = new ArrayList();
Collection.addAll(list,"","");
list.stream().forEach(s -> System.out.println(s));

count

List<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c");

long count = list.stream().count();
System.out.println(count);

filter

//过滤数据
List<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c");

list.stream()
    .filter(s -> s=="a")
    .forEach(System.out::println);

limit

//对流数据进行截取
List<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c");

list.stream()
    .limit(2)
    .forEach(System.out::println);

skip

//跳过指定个数数据
List<String> list = new ArrayList<>();
Collections.addAll(list, "a", "b", "c");

list.stream()
    .skip(1)
    .forEach(System.out::println);

map

//把一种类型的流转换为另一种类型的流
List<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3");

list.stream()
    .map(s -> Integer.parseInt(s))
    .forEach(s -> System.out.println(s.getClass()));

sorted

//将数据排序,可以默认自然排序(无参),也可以指定比较器(有参)
Stream<Integer> stream = Stream.of(55, 22, 66, 33, 11);
stream.sorted()
    .sorted((o1, o2) -> o2 - o1)
    .forEach(System.out::println);

distinct

//去重   自定义对象去重需要重写equals和hashcode方法
Stream<String> stream = Stream.of("a", "a", "b", "b", "c");
stream.distinct().forEach(System.out::println);

match

Stream接口中提供了三个相关方法

boolean allMatch(Predicate<? super T> predicate);//元素是否全部满足条件
boolean anyMatch(Predicate<? super T> predicate);//元素是否有任一个满足条件
boolean noneMatch(Predicate<? super T> predicate);//元素是否全部不满足条件
//allMatch
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
boolean b = stream.allMatch(s -> s < 7);
System.out.println(b);

//anyMatch
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
boolean b = stream.anyMatch(s -> s < 3);
System.out.println(b);

//noneMatch
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
boolean b = stream.noneMatch(s -> s < 3);
System.out.println(b);

find

//从集合中找到第一个数据
//findFirst
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
Optional<Integer> first = stream.findFirst();
System.out.println(first.get());

//findAny
Stream<Integer> stream = Stream.of(5, 4, 3, 2, 1);
Optional<Integer> first = stream.findAny();
System.out.println(first.get());

max和min

//得到最大或最小的值
//max  取最后一个值,自己比较排序好
Optional<Integer> max = Stream.of(5, 4, 3, 2, 1).max((o1, o2) -> o1 - o2);
System.out.println(max.get());

//min  取第一个值,自己排序好
Optional<Integer> max = Stream.of(5, 4, 3, 2, 1).min((o1, o2) -> o2 - o1);
System.out.println(max.get());

reduce ***

//将所有数据归纳得到一个数据
Stream<Integer> integerStream = Stream.of(4, 5, 9, 7);

//T reduce(T identity, BinaryOperator<T> accumulator);
// T identity是默认值
// BinaryOperator对数据处理的方式
Integer sum = integerStream.reduce(0, (a, b) -> {
    System.out.println("a = " + a + ";b = " + b);
    return a+b;
});
System.out.println(sum);
//map和reduce组合使用
//求所有年龄的总和
//1.得到所有年龄
//2.求和
Person p1 = new Person("张三", 20);
Person p2 = new Person("李四", 32);
Person p3 = new Person("王五", 18);
Person p4 = new Person("赵六", 45);

Stream<Person> stream = Stream.of(p1, p2, p3, p4);
int ageCount = stream.map(s -> s.getAge())
    .reduce(0, (a, b) -> a + b);
System.out.println(ageCount);

mapToInt

//Stream流中的Integer数据转换为int数据
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值