常用函数接口:
函数式接口:
函数式接口在Java中是指:有且仅有一个抽象方法的接口(可以含其他方法)。
而Java中的函数式编程的体现就是Lambda。
@FunctionalInterface 注解:检测接口是否是函数式接口。
函数式接口的使用:一般可以作为方法的参数和返回值类型。
Lambda表达式有延迟执行的特点,可提高程序运行效率。
性能浪费案例:
@java.lang.FunctionalInterface public interface FunctionalInterface { public abstract void method(); }
public class Demo { //定义一个方法,参数使用函数式接口 public static void show(FunctionalInterface myInter){ myInter.method(); } public static void main(String[] args) { //方法的参数是一个接口,所以可以传递接口的实现类 show(new MyFunctionalInterfaceImpl()); //也可以传递接口的匿名内部类 show(new FunctionalInterface() { @Override public void method() { System.out.println("匿名内部类"); } }); //方法的参数也是一个函数式接口,所以可以用Lambda。 show(()-> System.out.println("Lambda")); } }
以上代码中存在性能浪费的问题,
Lambda作为返回值:在调用show方法时,如果level不等于1,那么第二个参数字符串拼接的操作就相当于白做了。
使用Lambda进行优化:
public class Logger { public static void show(int level,MessageBuilder mb){ if (level==1) System.out.println(mb.messageBuilder()); } public static void main(String[] args) { String s1="Hello"; String s2="World"; show(1,()->{return s1+s2;}); } }
以上代码中,只是将参数传递到show方法中,只有条件满足,才会执行拼接操作。
常用函数式接口:
* Supplier :生产型接口。Supplier<T> T get() 。用来返回泛型参数指定类型的对象。
public class test {
public static String getString(Supplier<String> stringSupplier){
return stringSupplier.get();
}
public static void main(String[] args) {
String s=getString(()->"rt");
System.out.println(s);
}
}
* Consumer:消费型接口。accept() 对接收的泛型参数进行消费(处理)
public class test { public static void consume(String name,Consumer<String> consumer){ consumer.accept(name); } public static void main(String[] args) { consume("rt",(String name)-> System.out.println(name)); } }
Consumer中的默认方法andThen:可以将两个Consumer接口组合到一起,再对数据消费。
* Predicate:对某种类型的数据进行相关判断。boolean test(T t)
public class test { public static boolean checkString(String s,Predicate<String> predicate){ return predicate.test(s); } public static void main(String[] args) { String name="abc"; boolean b=checkString(name,s -> s.length()>3); System.out.println(b); } }
默认方法 and : 返回多个test的与关系值。
public class test { public static boolean checkString(String s,Predicate<String> predicate1,Predicate<String> predicate2){ return predicate1.and(predicate2).test(s); // 相当于:return predicate1.test(s)&&predicate2.test(s); } public static void main(String[] args) { String name="abc"; boolean b=checkString(name,s -> s.length()>2,s -> s.contains("a")); System.out.println(b); } }
默认方法: or : 或 negate :非。
* Function 接口: Function<T,R> 根据一个类型的数据得到另一个类型的数据。
R apply(T t ) 根据类型T 的参数 获取类型R 的结果。
public class test { public static void change(String s, Function<String,Integer> function){ Integer integer=function.apply(s); System.out.println(integer); } public static void main(String[] args) { String string="123"; change(string,s -> Integer.parseInt(s)); } }
默认方法:andThen :组合操作。
public class test { /* 将String转为Integer ,加10,然后转为String。 */ public static void change(String s,Function<String,Integer> function1,Function<Integer,String> function2){ String str=function1.andThen(function2).apply(s); System.out.println(str); } public static void main(String[] args) { String str="123"; change(str,s -> Integer.parseInt(s)+10,i->i.toString()); } }
Stream流式思想:
Stream 流的方式,遍历集合,对集合中的数据进行过滤。
Stream流是JDK1.8 之后出现的。
public class Demo { public static void main(String[] args) { List<String> list=new ArrayList<>(); list.add("张玉昊"); list.add("胡云钰"); list.add("张日天"); list.add("张天"); list.stream().filter(name->name.startsWith("张")) .filter(name->name.length()==3) .forEach(name-> System.out.println(name)); } }
获取Stream流:
java.util.stream.Stream<T> ,是Java8 加入的最常用的流接口。
1、所有的Collection集合都有stream方法来获取流 default Stream<E> stream()
2、Stream接口的静态方法of可以获取数组对应的流。 static <T> Stream<T> of (T...values)
Stream流的常用方法:
forEach:
forEach用来遍历流中的数据
该方法接收一个Consumer接口函数,会将流元素交给该函数处理
Consumer接口是一个消费型的函数式接口,可以传递lambda表达式,消费数据
forEach是一个终结方法,遍历之后就不能再使用Stream其他方法
filter:
filter用来对Stream流中的数据进行过滤,并生成新的流,可以用Lambda。
map:
将流中元素映射到另一个流中,可以将当前T类型的流转换为R类型的流。
public static void main(String[] args) { Stream<String> stream = Stream.of("1", "2", "3"); Stream<Integer> stream1 = stream.map(number -> Integer.parseInt(number)); stream1.forEach(number-> System.out.println(number)); }
count:
count方法用于统计Stream流中的元素个数,返回Long类型的整数。
count方法是一个终结方法。
limit:
limit方法,延迟方法,对流中的元素截取前几个,返回新的流。limit(Long maxsize),
skip:
跳过前几个元素,返回新的流,skip(long n)
concat:
concat:把流组合到一起,concat(流1,流2);
Stream流的特点:
Stream流属于管道流,只能被使用一次。第一个Stream流调用完毕方法,数据就会流转到下一个Steam流,当前Stream流则关闭。
方法引用:
Java8 中引入方法引用新特性,用于简化应用对象方法的调用, 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。 方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些。方法引用是一种更简洁易懂的Lambda表达式。
Lambda表达式的作用,就是实现接口的方法,也就是写 “该怎么做”,而当“该怎么做”只是一个方法调用时,只需要写“该怎么做”的方法即可,来代替Lambda。
1、通过对象引用成员方法。
public class test { public static void print(Printable p){ p.print("Hello"); } public static void main(String[] args) { print(s->{ PrintString pt=new PrintString(); pt.printString(s); }); PrintString pt=new PrintString(); print(pt::printString); } }
2、通过类名引用静态方法,类名::静态方法。