最通俗易懂的 Java 8 新特性讲解

1. 基础语法

Java8中引用一个新的操作符 “->”,该操作符成为箭头操作符或者lambda操作符,箭头操作符将Lambda拆分成两个部分

左侧:Lambda 表达式的参数列表

右侧:Lambda 表达式中所需要的执行的功能,即 Lambda 体

语法格式:

  1. 无参,无返回值

    需要实现接口的抽象方法。无参,无返回值。

()->System.out.println("Hello Lambda");
//测试
@Test
public void test1(){
     //注意:jdk1.8之前局部内部类应用局部变量时局部变量必须是final,jdk1.8之后可以不加final但是默认是final的
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("Hello World");
        }
    };
    //优化后
    Runnable r1 = ()->System.out.println("Hello Lambda");
    r.run();
    r1.run();
}
  1. 有一个参数,无返回值
(x) -> System.out.println(x);
@Test
    public void test2(){
        //一个参数
        Consumer<String> con = (x) -> System.out.println(x);
        con.accept("JAVA威武霸气");
    }
  1. 若只有一个参数小括号可以省略不写
x -> System.out.println(x);
  1. 有两个以上的参数,有返回值,并且lambda体中有多条语句
@Test
public void test3(){
    Comparator<Integer> com = (x,y) ->{
    System.out.println("函数式接口");
    return Integer.compare(x,y);
    };
}
  1. 若lambda体中只有一条语句,return和大括号都可以省略不写
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
  1. 语法格式,Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型

函数式接口:lanbda中只有一个抽象方法的接口为函数式接口,可以使用@FunctionalInterface进行修饰

测试

//创建一个函数式接口
public interface MyPredicate<T> {
    boolean compare(T t);
}
//方法
public Integer operation(Integer num, MyFun myFun){
   return myFun.getValue(num);
}

@Test
public void test5(){
    //对一个数进行操作
    Integer operation = operation(200, x -> x + 200);
    System.out.println(operation);
    Integer operation1 = operation(300, x -> x * x);
    System.out.println(operation1);
}

2. 内置函数式接口

2.1 消费型接口

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

举例:

public class TestLambda3 {
    @Test
    public void test1(){
        happy(20000D,x-> System.out.println(x));
    }
    public void happy(Double money, Consumer<Double> consumer){
        consumer.accept(money);
    }
}

2.2 供给型接口

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

举例:

@Test
public void test2(){
    Double suppy = suppy(() -> 222D);
    System.out.println(suppy);
}
public Double suppy(Supplier<Double> supplier){
    return supplier.get();
}

2.3 函数型接口

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

举例:

 @Test
 public void test3(){
 String abvcdfd = function("abvcdfd", (x) -> x + "12323232");
 	System.out.println(abvcdfd);
}
public String function(String str, Function<String,String> function){
	return function.apply(str);
}

2.4 断言型接口

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

举例:将满足条件的字符串,放入集合中

@Test
public void test4(){
    List<String> list = Arrays.asList("1111","22322","545423232","23232323");
    List<String> filter = filter(list, x -> x.length() > 4);
    System.out.println(filter);
}

public List<String> filter(List<String> strs, Predicate<String> predicate){
    List<String> list = new ArrayList<>();
    for (String str : strs) {
        if(predicate.test(str)){
            list.add(str);
        }
    }
    return list;
}

3. 方法引用和构造器引用

若lambda体中的内容方法已经使用了,我们可以使用“方法引用”

主要有三种语法形式

对象::实例方法名

类::静态方法名

类::实例方法名

①左边函数式接口的参数和返回值要和等号右边的一致。

②若lambda 参数列表中的第一参数是实例方法的调用者,而第二个是实例方法的参数时候,可以使用ClassName:method

3.1 实例方法名

 @Test
    public void test5(){
        Consumer<String> consumer1 = x-> System.out.println(x);
        consumer1.accept("11111");

        Consumer<String> consumer2 = System.out::println;
        consumer2.accept("11111");
    }
@Test
    public void test6(){
        Employee employee = new Employee("张三",12,232323D);
        Supplier<String> sup = () -> employee.getName();
        System.out.println(sup.get());

        Supplier<Integer> age = employee::getAge;
        System.out.println(age.get());
    }

3.2 静态方法名

@Test
public void test7(){
    Comparator<Integer> comparator1 = (x,y)->Integer.compare(x,y);
    Comparator<Integer> comparator2 = Integer::compareTo;
}

3.3 实例方法名

@Test
public void test8(){
    BiPredicate<String,String> bp1 = (x,y) -> x.equals(y);
    BiPredicate<String,String> bp2 = String::equals;
}

3.4 构造器引用

ClassName:new
@Test
    public void test9(){
        Supplier<Employee> sup = ()->new Employee();
        //选用的构造器根据前面需要的决定
        Supplier<Employee> supplier = Employee::new;
    }

3.5 数组引用

public void test10(){
        Function<Integer,String[]> function = (x) -> new String[x];
        Function<Integer,String[]> function1 = String[]::new;
        String[] apply = function1.apply(20);
        System.out.println(apply.length);
    }

4. Stream

对数据源、集合、数组等进行一系列流水线式的中间操作,产生一个全新的流,数据源不会改变。

Stream 自己不会存储元素

Stream不会改变源对象。相反,他们会返回一个持有结果的新的Stream

Stream操作是延迟执行的。这意味着他们会等到需要的结果的时候才进行执行

4.1 创建流

1.可以通过Collection系列集合提供stream()或parallelStream

ArrayList<String> strings = new ArrayList<>();
strings.stream();

2.通过Arrays中的静态方法stream()获取数组流

Employee[] employees = new Employee[10];
Stream<Employee> stream = Arrays.stream(employees);

3.通过stream类中的静态方法of()

Stream<String> aaa = Stream.of("aaa", "bbb", "vccc");

4.创建无限流

  • 迭代
Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);
iterate.limit(10).forEach(System.out::println);
  • 生成
Stream<Double> generate = Stream.generate(() -> Math.random());
generate.limit(20).forEach(System.out::println);

4.2 筛选和切片

fileter–接收Lambda,从流中排除某些元素

Stream<Employee> employeeStream = employees.stream().filter(e -> e.getAge() > 27);
employeeStream.forEach(System.out::println);

注意:生成Stream的中间操作,不会执行任何操作,直到终止操作时才会执行全部内容,即惰性求值

limit–截断流,使其元素不超过给定的数量

employees.stream().filter(e -> {
            System.out.println("短路");
            return  e.getAge() > 27;
        }).limit(2).forEach(System.out::println);

skip(n) --跳过元素,返回一个扔掉了前n个元素的流。若流中的元素不足n个,则返回一个空流。与limit互补

employees.stream().filter((e) -> {
            return  e.getAge() > 27;
        }).skip(2).forEach(System.out::println);

distinct–筛选,通过流生成的元素的 hashCode() 和 equals() 去除重复元素

employees.stream().filter((e) -> e.getAge() > 27).distinct().forEach(System.out::println);

4.3 映射

map–接收 Lambda ,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素

List<String> list = Arrays.asList("aaa","bbb","ccc");
list.stream().map(String::toUpperCase).forEach(System.out::println);

employees.stream().map(Employee::getName).forEach(System.out::println);

flatMap–接收一个函数作为参数,将流中每个值都转换成另一个流,然后把所有的流连接成一个流

@Test
    void test1() {
        List<String> list = Arrays.asList("asdfsdfas","fasdf","fasdf");
        Stream<Stream<Character>> streamStream = list.stream().map(TestStreamApi2::filterCharacter);
        //这种流里套流的方式,可以直接使用flatMap
        streamStream.forEach(st-> st.forEach(System.out::println));
        //连接成一个流
 list.stream().flatMap(TestStreamApi2::filterCharacter).forEach(System.out::println);
}
    
public static Stream<Character> filterCharacter(String str){
    List<Character> list = new ArrayList<>();
    for (char c : str.toCharArray()) {
        list.add(c);
    }
    return list.stream();
}

4.4 排序

sorted()–自然排序(Comparable)

List<String> list = Arrays.asList("aaa","ccc","bbb","eee","fff");
list.stream().sorted().forEach(System.out::println);

sorted(Comparator)–定制排序

 employees.stream().sorted((e1,e2)->{
            if(e1.getAge()==e2.getAge()){
                return Double.compare(e1.getSalary(),e2.getSalary());
            }
            return Integer.compare(e1.getAge(),e2.getAge());
        }).forEach(System.out::println);

4.5 查找与匹配

allMatch–检查是否匹配所有元素

anyMatch–检查是否至少匹配一个元素

noneMatch–检查是否没有匹配所有元素

findFirst–返回第一个元素

findAny–返回当前流中的任意元素

count–返回流中的元素的总个数

max–返回流中的最大值

min–返回流中的的最小值

 //allMatch
        boolean b = employees.stream().allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b);
        //anyMatch
        boolean b1 = employees.stream().anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b1);
        //noneMatch
        boolean b2 = employees.stream().noneMatch(e -> e.getStatus().equals(Employee.Status.AAA));
        System.out.println(b2);
        //findFirst
        Optional<Employee> op = employees.stream().sorted(Comparator.comparingDouble(Employee::getSalary).reversed()).findFirst();
        System.out.println(op.get());
        //findAny
        Optional<Employee> any = employees.stream().filter(e -> e.getStatus().equals(Employee.Status.FREE)).findAny();
        System.out.println(any.get());
        //count
        long count = employees.stream().count();
        System.out.println(count);
        //max
        Optional<Employee> employee = employees.stream().max(Comparator.comparingDouble(Employee::getSalary));
        System.out.println(employee.get());
        //min
        Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compare);
        System.out.println(min.get());

4.6 归约

List<Integer> list = Arrays.asList(1,2,5,7,8,32);
        Integer sum = list.stream().reduce(0, (x, y) -> x + y);
        System.out.println(sum);
        System.out.println("------------------------");
        Optional<Double> reduce = employees.stream().map(Employee::getSalary).reduce(Double::sum);
        System.out.println(reduce.get());

4.7 收集

收集:将流转换为其他格式。接收一个Collecotr接口的实现,用于给Stream中元素做汇总方法

Collector接口中方法的实现决定了如何对流执行收集操作(如:收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法,可以方便的创建常见的收集器实例。

//转换为List
        List<String> list = employees.stream().map(Employee::getName).collect(Collectors.toList());
        list.forEach(System.out::println);
        //转换为Set
        Set<String> collect = employees.stream().map(Employee::getName).collect(Collectors.toSet());
        HashSet<String> collect1 = employees.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
        //总条数目
        Long collect2 = employees.stream().collect(Collectors.counting());
        System.out.println(collect2);
        //平均值
        Double average = employees.stream().collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(average);
        //总和
        Double collect3 = employees.stream().collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(collect3);
        //最大值
        Optional<Employee> collect4 = employees.stream()
                .collect(Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary)));
        System.out.println(collect4);
        //获取最小工资
        Optional<Double> min = employees.stream().map(Employee::getSalary).min(Double::compare);
        System.out.println(min);

分组

Collectors.groupingBy

Map<Employee.Status, List<Employee>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(JSON.toJSONString(map));

        //多级分组
        Map<Employee.Status, Map<String, List<Employee>>> collect = employees.stream().
                collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(e -> {
                    if (e.getAge() <= 35) {
                        return "青年";
                    } else if (e.getAge() <= 50) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));
        System.out.println(JSON.toJSONString(collect));

分区

满足条件的分一个区,不满足条件的分一个区

Map<Boolean, List<Employee>> collect = employees.stream().collect(Collectors.partitioningBy(e -> e.getSalary() > 8000));
        System.out.println(JSON.toJSONString(collect));

其他

 DoubleSummaryStatistics collect = employees.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
        double max = collect.getMax();
        double average = collect.getAverage();
        double min = collect.getMin();

连接字符串

String collect = employees.stream().map(Employee::getName).collect(Collectors.joining(",","===","==="));
System.out.println(collect);

5. 并行流和顺序流

Instant start = Instant.now();
        LongStream.rangeClosed(0,100000000000L)
            	//parallel()并行
                .parallel()
                .reduce(0,Long::sum);
        Instant end = Instant.now();
        System.out.println("耗费时间:"+ Duration.between(start,end).toMillis());

6. Optional

Optional 容器类的常用方法

Optional.of(T t):创建一个 Optional 实例

Optional.empty() : 创建一个空的 Optional 实例

Optional.ofNullable(T t):若 t 不为null,创建一个 Optional 实例,否则创建空实例

isPresent() : 判断是否包含值

orElse(T t) : 如果调用对象包含值,返回值,否则返回t

orElseGet(Supplier s) : 如果调用对象包含值,返回该值,否则返回s获取的值

map(Function f):如果有值对其进行处理,并返回处理后的 Optional,否则返回 Optional.empty()

flatMap(Function mapper) :与map类似,要求返回值必须为Optional

7. 接口中的默认方法和静态方法

类优先原则

多实现,有相同实现的方法签名时需要实现

静态方法可以直接使用

8. 时间API

//初始化
LocalDateTime ldt = LocalDateTime.now();
LocalDateTime ldt2 = LocalDateTime.of(2019, 12, 12, 16, 24, 25);

//获取年月日
int dayOfMonth = ldt2.getDayOfMonth();
int dayOfYear = ldt2.getDayOfYear();

//时间加减
LocalDateTime ldt3 = ldt2.plusDays(5);

//计算两个时间差
long between1 = ChronoUnit.YEARS.between(ld1, ld2);
System.out.println(between1);

//TemporalAdjuster : 时间矫正器
//--下个星期日
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
//下个工作日
LocalDateTime localDateTime = ldt.with(l -> {
            LocalDateTime ldt4 = (LocalDateTime) l;
            DayOfWeek dow = ldt4.getDayOfWeek();
            if (dow.equals(DayOfWeek.FRIDAY)) {
                return ldt4.plusDays(3);
            } else if (dow.equals(DayOfWeek.SATURDAY)) {
                return ldt4.plusDays(2);
            } else {
                return ldt4.plusDays(1);
            }
        });
System.out.println("下一个工作日日期:"+localDateTime);

//格式化时间 以前:SimpleDateFormatter 新:DateTimeFormatter
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
LocalDateTime localDateTime = LocalDateTime.now();
String format = localDateTime.format(dtf);
System.out.println(format);
//自定义格式化DateTimeFormatter.format()
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String format1 = dateTimeFormatter.format(localDateTime);
System.out.println(format1);
// 解析
LocalDateTime parse = LocalDateTime.parse(format1, dateTimeFormatter);
System.out.println(parse);

//时区支持
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Aden"));
System.out.println(ldt);
ZonedDateTime zonedDateTime = ldt.atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime);

9.可重复注解和类型注解

在注解上面加 @Repeatable(MyAnnotations.class)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是刘奇奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值