- lambda表达式
- 方法引用
- 默认方法
- java跟JavaScript交互
- stream api 管道概念
- Date Time api,对java7以前的日期的加强
- Option类 专门用来解决空指针异常的问题
- Base64类 专门用来对数据编码和解码
…
lambda表达式
lambda表达式可以称之为闭包,它是java8中的一个非常重要的特性,很多个用法都用到此表达式
lambda表达式允许把函数作为一个方法的参数,函数作为参数进行传递到方法中,从而使得代码更加简洁
语法:
(parameters)->expression代码
(parameters)->{statement代码块}
说明:
可选参数声明:
- 不需要声明参数类型,编译器统一识别参数值
- 可选参数圆括号:一个参数无须定义圆括号,多个参数需要定义圆括号
- 可选大括号:如果主体包含了一个语句,就不需要使用大括号
- 可选返回关键字:如果主体只有一个表达式返回值,编译器会自动返回值,如果有大括号需要明确指定返回一个数据值
比如:
- 不需要参数,返回值为5
()->5; - 接收一个参数(推断出是数字类型),返回参数值的2倍
x->2*x - 接收两个参数(推断出是数字类型),返回参数的差值
(x,y)->x-y - 接收两个参数,返回参数的差值
(int x,int y)->x*y - 接收一个参数,类型为String的参数,并输出参数的值,推断出没有返回值,相当于方法的返回值为void
(String str)->Sysout.out.println(str)
其实lambda表示的本质就是接口的子实现
lambda表达式简化了匿名内部类的写法
lambda的另一个说法叫做函数式编程(因为在代码中看不到类,只看到方法/函数)
- 不需要参数,返回值为5
使用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种
- 构造器的引用 Class::new
- 静态方法引用 Class::静态方法名称
- 特定的类的对象引用 Class::非静态方法名称
- 特定的对象方法引用 语法: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
例子
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
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);
}
}