miracle just wanna be better

jdk1.8新特性

2019-07-29
miracle

  • lambda表达式
  • 方法引用
  • 默认方法
  • java跟JavaScript交互
  • stream api 管道概念
  • Date Time api,对java7以前的日期的加强
  • Option类 专门用来解决空指针异常的问题
  • Base64类 专门用来对数据编码和解码

lambda表达式

lambda表达式可以称之为闭包,它是java8中的一个非常重要的特性,很多个用法都用到此表达式
lambda表达式允许把函数作为一个方法的参数,函数作为参数进行传递到方法中,从而使得代码更加简洁
语法:
(parameters)->expression代码
(parameters)->{statement代码块}
说明:
可选参数声明:

  • 不需要声明参数类型,编译器统一识别参数值
  • 可选参数圆括号:一个参数无须定义圆括号,多个参数需要定义圆括号
  • 可选大括号:如果主体包含了一个语句,就不需要使用大括号
  • 可选返回关键字:如果主体只有一个表达式返回值,编译器会自动返回值,如果有大括号需要明确指定返回一个数据值 比如:
    1. 不需要参数,返回值为5
      ()->5;
    2. 接收一个参数(推断出是数字类型),返回参数值的2倍
      x->2*x
    3. 接收两个参数(推断出是数字类型),返回参数的差值
      (x,y)->x-y
    4. 接收两个参数,返回参数的差值
      (int x,int y)->x*y
    5. 接收一个参数,类型为String的参数,并输出参数的值,推断出没有返回值,相当于方法的返回值为void
      (String str)->Sysout.out.println(str)
      其实lambda表示的本质就是接口的子实现
      lambda表达式简化了匿名内部类的写法
      lambda的另一个说法叫做函数式编程(因为在代码中看不到类,只看到方法/函数)

使用lambda表达式需要注意变量的作用域

  • lambda表达式的局部变量可以不用声明为final,但是不可以被后面的代码修改(即隐式的final特性)
  • lambda表达式中不允许声明一个与局部变量同名的参数或局部变量

    举例

/**
 * 其实lambda表示的本质就是接口的子实现
 * 此类专门来演示lambda表达式
 * lambda表达式简化了匿名内部类的写法
 * lambda的另一个说法叫做函数式编程(因为在代码中看不到类,只看到方法/函数)
 */
public class Demo1 {
    //内部接口
    interface MathOperation{
        int operation(int a, int b);
    }
    interface GreetingService{
        void sayMessage(String Message);
    }
    //以接口作为函数的参数
    private int operate(int a ,int b,MathOperation mathOperation){
         return mathOperation.operation(a,b);
    }
    public static void main(String[] args) {
        Demo1 demo1 = new Demo1();
        //java7做法
       int result =  demo1.operate(1, 2, new MathOperation() {
            @Override
            public int operation(int a, int b) {
                 return  a+b;
            }
        });
        System.out.println("result="+result);
        //java8的lambda写法
        //参数带有类型声明的,用add对象代表一个方法
        MathOperation add = (int a,int b)->a+b;
        //参数没有类型声明
        MathOperation sub = (a,b)->a-b;
        //有大括号中有返回语句
        MathOperation mul = (a,b)->{return a*b;};
        //没有大括号和返回语句
        MathOperation div = (a,b)->a/b;
        //输出结果
        System.out.println(demo1.operate(1,2,add));
        System.out.println(demo1.operate(1,2,sub));
        System.out.println(demo1.operate(1,2,mul));
        System.out.println(demo1.operate(1,2,div));

        //不用括号的方式
        GreetingService service1 = message-> System.out.println("hello "+message);
        //用括号的方式
        GreetingService service2 = (message)-> System.out.println("hello "+message);
        //调用方法(多态,调用的方式是接口重写的方法)
        service1.sayMessage("miracle");
        service2.sayMessage("lil-miracle");
    }
}

public class Demo2 {
    //在类中添加一个final成员变量
    final String hello = "hello";
    interface GreetingService{
        void sayMessage(String message);
    }

    public static void main(String[] args) {

        GreetingService service1 = (message)->{
                System.out.println("hello"+message);};


    }
}

方法引用

方法的引用方式是用 类名::方法名,其本质还是lambda表达式 具体的写法有4种

  1. 构造器的引用 Class::new
  2. 静态方法引用 Class::静态方法名称
  3. 特定的类的对象引用 Class::非静态方法名称
  4. 特定的对象方法引用 语法:instance对象::非静态方法名称

例子

Car.java

public class Car {
    /**
     * 方法是静态的
     * 方法的参数是一个接口类型,可以使用lambda表达式
     * @param supplier
     * @return
     */
    public static Car create(final Supplier<Car> supplier){
        return supplier.get();
    }

    /**
     * 碰撞的方法
     * 静态方法
     * @param car
     */
    public static void collide(final Car car){
        System.out.println("碰撞-->"+car.toString());
    }

    /**
     * 跟随方法
     * 方法是非静态
     * @param car
     */
    public void follow(final Car car){
        System.out.println("跟随-->"+car.toString());
    }

    /**
     * 维修的方法
     * 方法是非静态
     */
    public void repair(){
        System.out.println("维修-->"+this.toString());
    }
}

Demo1.java

public class Demo1 {

    public static void main(String[] args) {
        //构造方法的引用
        //java7写法
        Car car1 = Car.create(new Supplier<Car>() {
            @Override
            public Car get() {
                return new Car();
            }
        });
        //java8的lambda写法
        Car car2 = Car.create(()->new Car());
        System.out.println(car2);
        //java8的方法的引用    构造方法的引用,替代了接口中重写的get方法
        Car car3 = Car.create(Car::new);

        System.out.println(car3);

        //java8的方法的引用    静态方法的引用Class::staticmethod

        List<Car> cars = Arrays.asList(car1,car2,car3);
        cars.forEach(Car::collide);//等价于
        cars.forEach(car -> Car.collide(car));

        //java8方法的引用  非静态方法引用  Class::method
        cars.forEach(Car::repair);//等价于
        cars.forEach(car -> car.repair());
        //java8方法的引用  非静态方法引用 instance对象::method
        Car car4 = Car.create(Car::new);
        cars.forEach(car4::follow);//等价于
        cars.forEach((car)->car4.follow(car));

    }
}

Supplier.java(接口)

/**
 * 此接口中必须修饰一个注解
 * 此注解标记此接口是一个函数式接口
 * @param <T>
 */
@FunctionalInterface
public interface Supplier<T> {
    public T get();
}

函数式接口

函数式接口(Function interface)就是一个有且只有一个抽象方法,但是可以有多个非抽象方法的接口 函数式接口可以用lambda表达式,也可以用方法的引用 在jdk8之前已经有部分函数式接口 java.lang.Runnable java.util.Comparator java.io.FileFilter等 在jdk8之后新添加的函数式接口 java.util.Function 其中包含很多类 比如: Consumer Predicate Supplier等...

例子

GreetingService.java(接口)

@FunctionalInterface
public interface GreetingService {
    public void sayMessage(String message);

}

Demo1.java

public class Demo1 {
    public static void main(String[] args) {
        //lambda写法
        GreetingService service1 = (message -> System.out.println("hello"+message));
        service1.sayMessage("zhangsan");
        //方法引用写法
        GreetingService service2 = (System.out::println);
        service2.sayMessage("lisi");
    }
}

Demo3.java

public class Demo3 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8);
        System.out.println("输出所有数据");
        execute(list,(i)->true);
        System.out.println("输出所有偶数");
        execute(list,(i)->i%2==0);
        System.out.println("输出所有大于5的数");
        execute(list,(i)->i>5);
    }
    public static void execute(List<Integer> list, Predicate<Integer> predicate){
        for(Integer i:list){
            if(predicate.test(i)){
                System.out.println(i+" ");
            }
        }
    }
}

默认方法

在接口中可以放置有方法体的方法,但方法必须用default来修饰 在接口中添加默认方法,是用来给所有的子类提供同一个功能 在接口中还可以放静态方法,静态方法是有方法体的

例题

public class Demo1 {
    public static void main(String[] args) {
        Vehicle v = new Car();
        v.print();
    }
}
interface Vehicle{
    default void print(){
        System.out.println("这是一辆车");
    }
   static void laba(){
        System.out.println("喇叭响了");
    }
}
interface FourWheel{
    default  void print(){
        System.out.println("是一辆四轮车");
    }
}
class Car implements Vehicle,FourWheel{
    @Override
    public void print() {
        FourWheel.super.print();
        Vehicle.super.print();
        Vehicle.laba();
        System.out.println("我是一辆四轮小轿车");
    }
}

Stream流管道

在java8中添加了一个新的抽象,称之为流,可以让你以一种声明式的方式处理数据 stream流处理方式,可以把要处理的元素看成是一种流,流在管道中传输,并且可以在管道的节点上进行处理,处理包含:筛选,排序,聚合等操作 元素流在管道中经过经过中间的操作处理,最后由最终的操作得到前面的处理结果

Stream流管道的几个名词解释:

  • 数据源:流的源头,可以是集合,数组,IO,其他的数据源
  • 聚合操作:就是一些在流中筛选数据的操作 比如:filter,map,reduce,find,match,sorted等….

如何生成一个Stream流的源头 stream() 生成一个串行流 parallesStream() 生成一个并行流 比如: List strings = Arrays.asList("abc","bc","cba","qaz","qwer","null") List filtered = strings.stream().filter(str->!str.isEmpty()).collect(Collections.toList);

map方法用于映射每个元素对应的结果

filter方法用于通过设置条件过滤出元素

limit方法,用于获取指定数量的流

sorted方法,用于对流进行排序

Collector类实现了很多规约操作

例题

public class Demo1 {
    public static void main(String[] args) {
        System.out.println("java7的用法");
        List<String> strings = Arrays.asList("abc","bc","cba","qaz","qwer","");
                //计算空字符串
        long count7_1  = getCountEmptyStringByJava7(strings);
        System.out.println(count7_1);
        System.out.println("java8的用法");
        //计算空字符串
        long count8_1 = strings.stream().filter((str)->str.isEmpty()).count();
        System.out.println(count8_1);
        //计算字符串长度为3的字符串数目
        System.out.println("java7的用法");
        long count7_2 = getCountLength3ByJava7(strings);
        System.out.println(count7_2);
        System.out.println("java8的用法");
        long count8_2 = strings.stream().filter(str->str.length()==3).count();
        System.out.println(count8_2);
        //删除空字符串
        System.out.println("java7的用法");
        List<String> count7_3 = deleteEmptyStringByJava7(strings);
        System.out.println(count7_3);
        System.out.println("java8的用法");
        List<String> count8_3 = strings.stream().filter(str->!str.isEmpty()).collect(Collectors.toList());
        System.out.println(count8_3);
        //删除空字符串并使用逗号把他们合并起来
        System.out.println("java7的用法");
        String merge7_4=getMergeStringByJava7(strings);
        System.out.println(merge7_4);
        System.out.println("java8的用法");
        String merge8_4= strings.stream().filter(str->!str.isEmpty()).collect(Collectors.joining(","));
        System.out.println(merge8_4);

        List<Integer> numbers = Arrays.asList(3,2,2,3,7,3,5);
        //获取集合中的数据的平方数
        System.out.println("java7的用法");
        List<Integer> square7_5 = getSquare(numbers);
        System.out.println(square7_5);
        System.out.println("java8的用法");
        List<Integer> square8_5 = numbers.stream().map(i->i*i).distinct().collect(Collectors.toList());
        System.out.println(square8_5);

        //输出10个随机数
        Random random = new Random();
        for (int i=0;i<10;i++){
            System.out.println(random.nextInt(100));
        }
        System.out.println();
        random.ints(0,100).limit(10).sorted().forEach(System.out::println);
    }
    private static List<Integer> getSquare(List<Integer> numbers){
        List<Integer> temps = new ArrayList<Integer>();
        for(Integer num:numbers){
            Integer square = new Integer(num.intValue()*num.intValue());
            if (!temps.contains(square)){
                temps.add(square);
            }
        }
        return temps;
    }
    private static String getMergeStringByJava7(List<String> strings){
        StringBuilder sb = new StringBuilder();
        for (String str:strings){
            if(!str.isEmpty()){
                sb.append(str);
                sb.append(",");
            }
        }
        String str = sb.toString();
        return str.substring(0,str.length()-1);
    }
    private static List<String> deleteEmptyStringByJava7(List<String> strings){
        List<String> strs = new ArrayList<String>();
        for (String str:strings){
            if(!strings.isEmpty()){
                strs.add(str);
            }
        }
        return strs;
    }

    private static long getCountEmptyStringByJava7(List<String> strings){
        long count = 0;
        for(String str:strings){
            if(str.isEmpty()){
                count++;
            }
        }
        return count;
    }
    private static long getCountLength3ByJava7(List<String> strings){
        long count = 0;
        for(String str:strings){
            if(str.length()==3){
                count++;
            }
        }
        return count;
    }
}

java8的日期操作

java8通过发布新的Date-Time api(JSR310)来进一步加强对日期与时间的处理 在旧版中日期和时间的api存在有很多问题

  • 非线程安全,java.util.Date是非线程安全的,所有的日期类都是可变的.
  • 设计很差:java.util.date跟java.sql.Date类都是日期类,重复定义很多,所以用Calendar来替代java.util.Date
  • 时区处理很麻烦,在java.util.Date并没有提供时区的处理的api,java.util.Calendar能控制时区. java.util.TimeZone类能够控制时区 在java8中有一个包java.time包,提供了很多新的api
  • Local(本地):简化了日期和时间的处理,没有时区的问题
  • Zoned(时区):通过指定的时区处理日期和时间

例题

/**
 * 演示本地化日期和时间api
 * 本地化 Local
 */
public class Demo1 {
    public static void main(String[] args) {
        Demo1 demo1 = new Demo1();
        demo1.localDateTime();
    }
    private void localDateTime(){
        //获取当前的日期和时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);

        LocalDate date1 = now.toLocalDate();
        System.out.println(date1);

        LocalTime time = now.toLocalTime();
        System.out.println(time);

        System.out.println(now.getYear());

        System.out.println(now.getMonth());

    }
}
/**
 * 此类演示时区的用法
 * Zone
 */
public class Demo2 {
    public static void main(String[] args) {
        Demo2 demo = new Demo2();
        demo.zoneDateTime();
    }
    private void zoneDateTime(){
        //获取当前日期和时间,基于某个时区
        ZonedDateTime date1 = ZonedDateTime.parse("2019-07-29T12:12:12+05:30[Asia/ShangHai]");
        System.out.println(date1);

        ZoneId currentZone = ZoneId.systemDefault();
        System.out.println(currentZone);
    }
}

上一篇 jdk1.5新特性

下一篇 xml相关

Comments

Content