学习记录2

文章内容简要:
1、java8中接口方法的变化
2、Lambda表达式
3、函数式接口
4、方法引用


1、java8中接口方法的变化

-接口中方法默认使用public abstract修饰,字段默认使用public static final修饰;
-java8中可以定义default修饰的方法,也可以定义static修饰的方法;
-default修饰的方法,实现类可以重写,也可以不重写;
-static修饰的方法,实现类获取不到也无法重写(属于接口,直接通过接口.方法调用);
-default修饰的方法应用场景:例如,某个接口已经上线而且实现类很多,因为某个需求需要增加个通用功能,可以在接口里定义一个default方法,而不去一一修改实现类。接口中的新方法使用default修饰,是对接口的一个增强,而且可以不用去修改其实现类;
-static修饰的方法应用场景:该方法可以直接调用,实现类不能去修改,同样是对接口的一个升级增强。


2、Lambda表达式

可以当成是一个匿名方法,可以使代码更简洁

语法:
	(参数列表) -> {语句;}

Lambda表达式由参数列表和一个Lambda体组成,通过“->”连接。
说明:
1)当只有一个参数时,参数列表的“()”是可以省略的;
x -> {System.out.println(x);}
2)参数列表中参数的数据类型可以省略;
(x,y) -> {x.compareTo(y);}
3)Lambda体只有一条语句时,如果是return语句,“{}”和return只能同时省略,不可省略其中一个;如果是非return语句,“{}”可以省略
x -> “111”; 等价于 x -> {return “111”;};
x -> System.out.println(“111”); 等价于 x -> {System.out.println(“111”);};
4)没有参数也可以是一个Lambda表达式。
() -> “hello world”; (返回一个字符串)
以下是符合要求的Lambda表达式

public class Demo1 {
    public static void main(String[] args) {
	    Runnable runnable = () -> {};
	    Callable<String> callable = () -> "hello world";
	    IntBinaryOperator intBinaryOperator = (a, b) -> a + b;
	    IntBinaryOperator intBinaryOperator2 = (int a, int b) -> {return (a + b);};
	    IntFunction<Integer> integerIntFunction = a -> { return a+2; };
	    Function function = a -> {return "111";};
	    Function function2 = a -> "111";
	    Consumer<String> consumer = a -> { System.out.println("111"); };
		Consumer<List<String>> listConsumer = (List<String> list) -> {list.isEmpty();};
	    Callable<Object> callable1 = () -> {return new Object();};
	    Function<Object, Integer> function1 = (Object obj) -> obj.hashCode();
	    Consumer<Object> consumer1 = obj -> System.out.println(111);
    }
}

3、函数式接口

函数式接口:只定义一个抽象方法的接口。例如:Comparator Runnable
函数式接口使用注解@FunctionalInterface声明。
函数式接口是为Lambda表达式准备的,或者说Lambda表达式必须实现一个函数式接口。

/**
 * @FunctionalInterface 声明接口为函数式接口
 */
@FunctionalInterface
public interface AddFunctionInterface {
    Integer add(Integer a,Integer b);
}
/**
 * 只继承了一个抽象方法,是函数式接口
 */
public interface ByteAddInterface extends AddFunctionInterface {
}
/**
 * 加上继承的方法,共有两个抽象方法,不是函数式接口
 */
public interface DoubleAddInterface extends AddFunctionInterface {
    Double add(Double a, Double b);
}

3.1 Predicate<T>接口
它的抽象方法表示判断是否符合条件,符合返回true,不符合返回false;

 `boolean test(T t);`

定义一个方法,将原集合进行数据过滤,使用predicate返回需要的集合。此思路可在项目中作为工具来使用,当一个方法需要对数据做不确定的变化时,可以接收一个predicate参数,在调用时自行定义不同的规则。

public class Demo1 {
    public static void main(String[] args) {
    	/* Predicate */
        List<Integer> list = Arrays.asList(11,22,33,44,55);
        System.out.println("原list:" + list);
        Predicate<Integer> predicate = t -> t >25 ;
        List newList = getNewList(list,predicate);
        System.out.println("新list:" + newList);
        
		Predicate predicate = t -> t instanceof String;
		boolean flag = predicate.test(2);
		System.out.println(flag);	//false
		flag = predicate.test("abc");
		System.out.println(flag);	//true
    }

    /**
     * 将一个list中符合条件的数据放到新的list返回
     * @param predicate 指定一个条件(规则)
     */
    public static <T> List<T> getNewList(List<T> list, Predicate<T> predicate){
        List<T> newList = new ArrayList<>();
        list.forEach(t -> {
            if (predicate.test(t)){ //符合条件返回true
                newList.add(t);
            }
        });
        return newList;
    }
}

3.2 Consumer<T>接口
抽象方法,需要访问一个对象并进行操作,不需要返回值时可以使用这个接口。

void accept(T t);

集合的forEach方法就是使用的Consumer接口

public class Demo1 {
    public static void main(String[] args) {
    	/* Consumer */
        List<String> list = Arrays.asList("a","b","d","x","c");
        list.forEach(t -> System.out.println(t));
        Map<String,String> map = new HashMap<>();
        map.put("a","12");
        map.put("b","22");
        map.put("c","32");
        map.forEach((k,v) -> System.out.println("key:"+k+",value:"+v));
        map.forEach((k,v) -> {
            System.out.print("key:"+k);
            System.out.println(",value:"+v);
        });//两个输出结果一样
    }
}

3.3 Function<T,R>接口
抽象方法,需要输入一个对象,经过处理后返回新的值,可以使用这个接口

R apply(T t);

定义一个对原数据处理后返回新结果的函数,同样可以在项目中使用:接收数据,返回其它数据,具体实现方法不同,可以通过函数式接口作为参数来传入不同的逻辑

public class Demo1 {
    public static void main(String[] args) {

        /* Function */
        List<Integer> list = Arrays.asList(11,22,33,44);
        Function<Integer,String> function = t -> t * new Random().nextInt(10)+"-";
        List<String> newList = getNewList(list, function);
        System.out.println(newList);
        list.forEach(t -> newList.add(function.apply(t)));
        System.out.println(newList);

        List<String> stringList = Arrays.asList("123","a","32","aaaaa");
        Function<String,Integer> fun = t -> t.length(); //返回每个数据的长度
        stringList.forEach(t -> System.out.println(t + "的长度:"+fun.apply(t)));
    }

    /**
     * 将一个集合的数据经过处理后写入到另一个集合
     * @param function 处理数据的方法
     */
    public static <T,R> List<R> getNewList(List<T> list,Function<T,R> function){
        List<R> res = new ArrayList<>();
        list.forEach(obj -> res.add(function.apply(obj)));  //把通过apply方法处理后的数据保存到集合中
        return res;
    }
}

3.4 Supplier<T>接口
抽象方法,不需要接收参数,直接返回一个对象

T get();

直接返回一个固定值,无须输入参数

public class Demo1 {
    public static void main(String[] args) {
	    /* Supplier */
	    Supplier supplier = () -> 1;
	    System.out.println(supplier.get());
    }
}

3.5 对基本数据类型的处理
函数式接口的泛型只能接收引用类型,不能直接使用基本类型。
JDK8中为基本类型提供了对应的函数式接口,避免在进行基本类型的输入输出时频繁进行装箱-拆箱操作(耗内存,耗时)。
针对基本类型数据的函数式接口名称前面加了基本类型名的前缀,例如:IntPredicate,IntConsumer,IntFunction等

public class Demo1 {
    public static void main(String[] args) {

        /* 基本数据类型 */
        IntPredicate intPredicate = (i -> i*2 == 2);
        System.out.println(intPredicate.test(1));
        System.out.println(intPredicate.test(2));

        IntConsumer intConsumer = (i -> System.out.println(i));
        intConsumer.accept(1);
        intConsumer.accept(2);

        IntFunction intFunction = (i -> i*2);
        System.out.println(intFunction.apply(1));
        System.out.println(intFunction.apply(2));
    }
}

总结:
1、Predicate接口,接收参数,返回boolean,进行判断,方法是test(),数据进行逻辑判断使用
2、Consumer接口,接收参数,没有返回值,只执行语句,方法是accept(),消费数据,无返回
3、Function接口,接收参数,可以返回其它数据类型,可当做是一个正常的方法,方法是apply(),可根据一个类型数据转成另一类型数据
4、Supplier接口,不接收参数,可以返回其它数据类型,返回固定值,方法是get(),提供数据,无须入参;
5、对于基本数据类型,有对应名称作为前缀的函数式接口可直接使用。
6、函数式接口可以使用变量,但是这个变量必须是final修饰的或者不再改变的才可以(即使是执行后才对变量进行了赋值也是不可以的)


4、方法引用

可以重复使用现有的方法定义,像Lambda一样传递,如:

list.forEach(x -> System.out.println(x));

使用方法引用的话可以改成如下:

list.forEach(System.out::println);

方法引用可以看作是仅仅调用特定方法的Lambda表达式的一种快捷写法,需要使用方法引用时,目标引用(类名)放在"::“前,方法名放在”::“后面,只需要方法名,不需要”()",例如:
(String s) -> s.length(); 等同于 String::length;

public class Demo1 {
    public static void main(String[] args) {
		List list = Arrays.asList(3,5,6,1);
        list.forEach(t -> System.out.println(t));
        list.forEach(System.out::println);	//二者等效
		
		String str = "123456";
        Function<String, Integer> fun = (s) -> s.length();
        Function<String, Integer> fun1 = String::length;
        Assert.isTrue(fun.apply(str)==fun1.apply(str),()->"不相等");
    }
}

方法引用主要分为四类:
1、指向静态方法

public class Demo1 {
    public static void main(String[] args) {
		Integer i = 123;
        Function function = String::valueOf;
        System.out.println(function.apply(i) instanceof String);
        Integer[] arr = {516,3,81,20,66};
        Arrays.sort(arr,Integer::compareTo); //对数组排序
        System.out.println(Arrays.toString(arr));
    }
}

2、指向实例方法

public class Demo1 {
    public static void main(String[] args) {
        BiFunction<Demo1, Demo1, Boolean> compare = Demo1::compare;
        System.out.println(compare.apply(new Demo1(),new Demo1()));
    }
    public boolean compare(Demo1 b){
        return this.equals(b);
    }
}

3、指向现有对象的实例方法引用

public class Demo1 {
    public static void main(String[] args) {
        String s = "abc";
        System.out.println(s.compareTo("123"));
        Function<String, Integer> function1 = s::compareTo;
        System.out.println(function1.apply("123"));
    }
}

4、指向构造方法的引用
对于一个现有的构造方法,可以使用类名和new来创建对象,需要注意,三个及以上参数的构造方法需要自定义函数式接口去实现

public class Demo1 {
    public static void main(String[] args) {
		Supplier<Demo1> sup = Demo1::new;   //无参构造
        System.out.println(sup.get());
        Function<String, Demo1> fun = Demo1::new;   //一个参数构造
        System.out.println(fun.apply("aaa"));
        BiFunction<String, String, Demo1> bi = Demo1::new;  //两个参数构造
        System.out.println(bi.apply("aaa","bbb"));
        ConstructionFunction<String, String, Integer, Demo1> function = Demo1::new;//三个参数及以上构造需要自己定义接口
        System.out.println(function.apply("aaa","bbb",123));
    }
    //field,setter,getter,construction,toString省略
}
/**
 * 自定义多个构造参数接口
 */
@FunctionalInterface
interface ConstructionFunction<T,U,V,R>{
    R apply(T t,U u,V v);
}

Lambda表达式小练习

public class Test {
    public static void main(String[] args) {
        List<Student> list = Arrays.asList(new Student("zs",22,"北京市")
        ,new Student("ls",33,"上海市")
        ,new Student("ab",32,"重庆市")
        ,new Student("mm",25,"天津市"));
        //原始数据
        System.out.println("old data:"+list);

        //匿名内部类
        list.sort(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge()-o2.getAge();
            }
        });
        System.out.println("age asc:"+list);

        //Lambda表达式
        list.sort((s1,s2) -> s2.getAge().compareTo(s1.getAge()));
        System.out.println("age desc:"+list);
        BiFunction<String, String, Integer> comparator = String::compareTo;
        list.sort((s1,s2) -> comparator.apply(s1.getAdd(),s2.getAdd()));
        System.out.println("add asc:"+list);

        //Comparator接口中comparing静态方法
        list.sort(Comparator.comparing(Student::getName));
        System.out.println("name asc:"+list);
    }
}
class Student{
    private String name;
    private Integer age;
    private String add;

    public String getName() {
        return name;
    }
    public Integer getAge() {
        return age;
    }
    public String getAdd() {
        return add;
    }
    
    public Student() {
    }
    public Student(String name, Integer age, String add) {
        this.name = name;
        this.age = age;
        this.add = add;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", add='" + add + '\'' +
                '}';
    }
}

定义一个函数式接口

public class Demo {
    public static void main(String[] args) {
        MyFunctionInterface myFunctionInterface = new MyFunctionInterface() {
            @Override
            public void m() {
                System.out.println("匿名内部类里实现函数式接口的方法");
            }
        };
        myFunctionInterface.m();

        MyFunctionInterface myFunctionInterface1 = () -> System.out.println("Lambda表达式实现函数式接口的方法");
        myFunctionInterface1.m();
    }
}
@FunctionalInterface
interface MyFunctionInterface {
    void m();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值