Java8 一些新特性

铺垫

注意,这些内容都是看起来复杂,但用几遍之后就会了。所以要多练几遍!

在了解下面这一堆东西的时候,先要了解一个概念:函数式接口

函数式接口:只包含一个抽象方法的接口。

函数式接口可以使用匿名实现类得到实例,如下:

		//这里,Comparator 是函数式接口
		Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        };

Lambda表达式是对匿名内部类的简化,因此所有匿名内部类都能转换成Lambda表达式

方法引用是当Lambda表达式符合一定的条件时,进一步进行简化。

简化到最后就有点抽象了,导致没了解过的朋友经常会出现,每个地方都认识,但为什么组合在一起就看不懂了的尴尬局面 (⊙x⊙;)

Lambda表达式

Lambda表达式的简化,简单来说,就是将确定的东西删去

一共六种格式,看起来很复杂,但其实全部用一遍后就基本上会了。
不用担心,真的挺简单的。

(以下代码出自尚硅谷的Java教程视频)

语法格式一:无参,无返回值

        //r1 和 r2 是一样的(输出不一样)
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("我爱北京天安门");
            }
        };
        //注意,因为是函数式接口,所以这里必定是重写run()方法
        //因此,可以把前面一大堆去掉
        Runnable r2 = () -> {
            System.out.println("我爱北京故宫");
        };

语法格式二:Lambda 需要一个参数,但是没有返回值

        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("谎言和誓言的区别是什么?");

		//当要传参数时,需要参数
        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("一个是听得人当真了,一个是说的人当真了");

    }

语法格式三:数据类型可以省略,因为可由编译器推断得出,称为“类型推断”

		Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("一个是听得人当真了,一个是说的人当真了");
        
        //这就是上面那个例子,但这次连参数类型也删掉了
        Consumer<String> con2 = (s) -> {
            System.out.println(s);
        };
        con2.accept("一个是听得人当真了,一个是说的人当真了");

语法格式四:Lambda 若只需要一个参数时,参数的小括号可以省略

		Consumer<String> con1 = (s) -> {
            System.out.println(s);
        };
        con1.accept("一个是听得人当真了,一个是说的人当真了");
        //接上一个例子,小括号没了
        Consumer<String> con2 = s -> {
            System.out.println(s);
        };
        con2.accept("一个是听得人当真了,一个是说的人当真了");

语法格式五:Lambda 可以有两个或以上的参数,多条执行语句,并且可以有返回值

		Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };

        System.out.println(com1.compare(12,21));

        //这里,有两个参数,相较于上一个例子小括号不能删
        Comparator<Integer> com2 = (o1,o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };

        System.out.println(com2.compare(12,6));

语法格式六:当 Lambda 体只有一条语句时,return 与大括号若有,都可以省略

        Comparator<Integer> com1 = (o1,o2) -> {
            return o1.compareTo(o2);
        };

        System.out.println(com1.compare(12,6));
		
		//看到了吗?只有一条语句时,大括号可以删除,此时有return也是可以删除的
        Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);

        System.out.println(com2.compare(12,21));

其实核心还是那句话:将确定的东西删去
因为这些东西删去后,不会产生歧义。

方法引用

方法引用是当Lambda表达式符合一定的条件时,进一步进行简化。
而这里的关键,就是这个“一定条件”。
(以下代码出自尚硅谷的Java教程视频)

情况一:对象 :: 实例方法

	//Consumer中的void accept(T t)
	//PrintStream中的void println(T t)
	@Test
	public void test1() {
		Consumer<String> con0 = new Consumer<String>() {
			//注意这里!!!
			//accept方法,里面就找了一个System.out对象,让这个对象调用它的println()方法!!!
			//!!!参数列表和返回值,相同或一致(多态)!!!
			//有没有人想过,我叫accept做事,它反手就叫别人帮它把事做了,那我为什么不直接叫别人做事?
			//(注意,这只是简化代码的一个联想,便于理解!实际上,并没有真正越过accept!)
			
			@Override
			public void accept(String s) {
				System.out.println(s);
			}
		};
	
		Consumer<String> con1 = str -> System.out.println(str);
		con1.accept("北京");

		System.out.println("*******************");
		PrintStream ps = System.out;
		
		//接上面联想,直接叫System.out对象过来,让他调用println方法。砍掉了中间商,笑
		Consumer<String> con2 = ps::println;
		con2.accept("beijing");
	}

情况二:类 :: 静态方法

	//Comparator中的int compare(T t1,T t2)
	//Integer中的int compare(T t1,T t2)
	@Test
	public void test3() {
		//上面那个匿名内部类是我怕大家不熟练添加的,这里我们就直接看Lambda表达式吧
		//仔细看,这里和上面非常类似!
		//!!!参数列表和返回值,相同或一致(多态)!!!
		//区别在于,上面是找了一个对象来调用它的实例方法
		//而这里是找了一个类来调用它的静态方法
		Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2);
		System.out.println(com1.compare(12,21));

		System.out.println("*******************");

		//很类似的处理,相信大家都看懂了
		Comparator<Integer> com2 = Integer::compare;
		System.out.println(com2.compare(12,3));

	}

情况三:类 :: 实例方法 (有一点点难度)

	// Comparator中的int comapre(T t1,T t2)
	// String中的int t1.compareTo(t2)
	@Test
	public void test5() {
		//注意这里的参数列表
		//第一个参数调用自己的实例方法,去处理第二个参数
		//这种情况就是,一共有n个参数,第一个参数调用自己的一个实例方法把剩下的n-1个参数都处理了。
		//注意!!!第一个参数,调用自己的一个成员方法把后面的参数全处理了
		//!!!参数列表和返回值,相同或一致(多态)!!!
		//联想起来就像,校长让老师讲课,老师让班长给剩下的所有人讲课,自己摸鱼去了
		Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2);
		System.out.println(com1.compare("abc","abd"));

		System.out.println("*******************");

		//有的朋友可能会疑惑,怎么回事类怎么能调用实例方法呢?
		//别急,其实这只是一种写法,实际上还是对象去调用的
		//此时,用 第一个参数的类 :: 对应实例方法
		Comparator<String> com2 = String :: compareTo;
		System.out.println(com2.compare("abd","abm"));
	}

构造器引用和数组引用

构造器引用:简单来讲就是,构造方法方法引用
与上面方法引用非常类似
格式: 类名 :: new

数组引用:与构造器引用非常类似
格式: 数组名[] :: new

/**
 * 一、构造器引用
 *      和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。
 *      抽象方法的返回值类型即为构造器所属的类的类型
 *
 * 二、数组引用
 *     大家可以把数组看做是一个特殊的类,则写法与构造器引用一致。
 *
 * Created by shkstart
 */
public class ConstructorRefTest {
	
    @Test
    public void test1(){

        Supplier<Employee> sup = new Supplier<Employee>() {
            @Override
            public Employee get() {
                return new Employee();
            }
        };
        System.out.println("*******************");
        
		//构造器引用
    	//Supplier中的T get() 
    	//Employee的空参构造器:Employee()
    	//因为Supplier中的T get()  是无参的,所以调用的就是Employee的空参构造器:Employee()
        Supplier<Employee>  sup2 = Employee :: new;
        System.out.println(sup2.get());
        
        System.out.println("*******************");

		//构造器引用
    	//Function中的R apply(T t)
    	//Employee需要一个参数的构造器:Employee(int id)
    	//因为Function中的R apply(T t)  需要一个参数,所以调用的就是Employee需要一个参数的构造器:Employee(int id)
        Function<Integer,Employee> func2 = Employee :: new;
        Employee employee1 = func2.apply(1002);
        System.out.println(employee1);

		
        System.out.println("*******************");
        
		//构造器引用
    	//BiFunction中的R apply(T t,U u)
    	//Employee需要两个个参数的构造器:Employee(int id, String name)
    	//因为BiFunction中的R apply(T t,U u)  需要两个参数,所以调用的就是Employee需要两个参数的构造器:Employee(int id, String name)
    	//更多参数的情况同理
        BiFunction<Integer,String,Employee> func3 = Employee :: new;
        System.out.println(func3.apply(1002,"Tom"));

    }


	//数组引用
    //Function<T, R>中的R apply(T t)
    @Test
    public void test4(){
        Function<Integer,String[]> func1 = length -> new String[length];
        String[] arr1 = func1.apply(5);
        System.out.println(Arrays.toString(arr1));

        System.out.println("*******************");

        Function<Integer,String[]> func2 = String[] :: new;
        String[] arr2 = func2.apply(10);
        System.out.println(Arrays.toString(arr2));

    }
}

Stream流

先发布,等会写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值