java lambda表达式相关
lambda表达式的作用就是将函数作为参数传入方法.
常见的写法一:
代替匿名内部类:
public class LambdaDemo {
public interface Operation {
/**
* 加法
*
* @param x
* @param y
* @return
*/
public int add(int x, int y);
}
public static void main(String[] args) {
new LambdaDemo().testAdd(1, 2, new Operation() {
@Override
public int add(int x, int y) {
return 0;
}
});
/* lambda简化匿名内部类的写法*/
/* 写法一*/
new LambdaDemo().testAdd(1,2,(x,y)->{
return x+y;
});
/* 写法二*/
Operation o = (x, y) -> {
return x + y;
};
new LambdaDemo().test(1,2,o);
}
private int testAdd(int x, int y, Operation o) {
return o.add(x, y);
}
}
方法引用
方法引用通过方法的名字来指向一个方法。
方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用使用一对冒号 ::
主要用于list.forEach()方法中
如:
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
Person p1 = new Person("白色");
Person p2 = new Person("黑色");
Person p3 = new Person("黄色");
list.add(p1);
list.add(p2);
list.add(p3);
list.forEach(Person::printColor);
}
}
class Person {
private String color;
public Person(String color) {
this.color = color;
}
public void setColor(String color) {
this.color = color;
}
public String getColor() {
System.out.println(color);
return color;
}
public void printColor(){
System.out.println(color);
}
//@TODO 此处待深入了解
函数式接口
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
它可由@FunctionalInterface 注解,这个注解仅仅用来限制接口中只有一个抽象方法.
函数式接口可以被隐式转换为 lambda 表达式。
lambda表达式可以用来实现这仅有的抽象方法.
例子
interface Bark{
public void barkAAA(String message);
}
/*lambda实现这个barkAAA方法 */
Bark b=(message)->System.out.println(message);
/* 调用b的barkAAA方法就是 */
b.barkAAA("汪汪汪");
/* 这样就可以通过把b这个对象传递给其他方法,从而实现了函数式编程*/
例如可以写一个方法
public void barkBBB(String message,Bark bark){
bark.barkAAA(message);
}
/* 又因为lambda和函数式接口可以隐式转换*/
/*实际调用barkBBB*/
brakBBB("喵喵喵",(message)->System.err.println(message));
实际项目中,自己定义这些函数式接口太几把烦了,于是jdk8就已经预定义了很多接口,直接拿过来就很方便了.
1 BiConsumer<T,U>
代表了一个接受两个输入参数的操作,并且不返回任何结果
2 BiFunction<T,U,R>
代表了一个接受两个输入参数的方法,并且返回一个结果
3 BinaryOperator
代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
4 BiPredicate<T,U>
代表了一个两个参数的boolean值方法
5 BooleanSupplier
代表了boolean值结果的提供方
6 Consumer
代表了接受一个输入参数并且无返回的操作
7 DoubleBinaryOperator
代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。
8 DoubleConsumer
代表一个接受double值参数的操作,并且不返回结果。
9 DoubleFunction
代表接受一个double值参数的方法,并且返回结果
10 DoublePredicate
代表一个拥有double值参数的boolean值方法
11 DoubleSupplier
代表一个double值结构的提供方
12 DoubleToIntFunction
接受一个double类型输入,返回一个int类型结果。
13 DoubleToLongFunction
接受一个double类型输入,返回一个long类型结果
14 DoubleUnaryOperator
接受一个参数同为类型double,返回值类型也为double 。
15 Function<T,R>
接受一个输入参数,返回一个结果。
16 IntBinaryOperator
接受两个参数同为类型int,返回值类型也为int 。
17 IntConsumer
接受一个int类型的输入参数,无返回值 。
18 IntFunction
接受一个int类型输入参数,返回一个结果 。
19 IntPredicate
:接受一个int输入参数,返回一个布尔值的结果。
20 IntSupplier
无参数,返回一个int类型结果。
21 IntToDoubleFunction
接受一个int类型输入,返回一个double类型结果 。
22 IntToLongFunction
接受一个int类型输入,返回一个long类型结果。
23 IntUnaryOperator
接受一个参数同为类型int,返回值类型也为int 。
24 LongBinaryOperator
接受两个参数同为类型long,返回值类型也为long。
25 LongConsumer
接受一个long类型的输入参数,无返回值。
26 LongFunction
接受一个long类型输入参数,返回一个结果。
27 LongPredicate
R接受一个long输入参数,返回一个布尔值类型结果。
28 LongSupplier
无参数,返回一个结果long类型的值。
29 LongToDoubleFunction
接受一个long类型输入,返回一个double类型结果。
30 LongToIntFunction
接受一个long类型输入,返回一个int类型结果。
31 LongUnaryOperator
接受一个参数同为类型long,返回值类型也为long。
32 ObjDoubleConsumer
接受一个object类型和一个double类型的输入参数,无返回值。
33 ObjIntConsumer
接受一个object类型和一个int类型的输入参数,无返回值。
34 ObjLongConsumer
接受一个object类型和一个long类型的输入参数,无返回值。
35 Predicate
接受一个输入参数,返回一个布尔值结果。
36 Supplier
无参数,返回一个结果。
37 ToDoubleBiFunction<T,U>
接受两个输入参数,返回一个double类型结果
38 ToDoubleFunction
接受一个输入参数,返回一个double类型结果
39 ToIntBiFunction<T,U>
接受两个输入参数,返回一个int类型结果。
40 ToIntFunction
接受一个输入参数,返回一个int类型结果。
41 ToLongBiFunction<T,U>
接受两个输入参数,返回一个long类型结果。
42 ToLongFunction
接受一个输入参数,返回一个long类型结果。
43 UnaryOperator
接受一个参数为类型T,返回值类型也为T。
这些接口很多,但有规律,Predicate系列返回布尔类型的值,表示判断,Operator通常与操作符有关,含有Bi的一般是两个参数,(Both input),大概是这样.
那么就可以写成
public static void bark(String message, Function <String,String> f){
System.out.print(f.apply(message));
}
/* 调用bark方法*/
bark("abc",(message)->return message.toUpperCase();)
接口中的默认方法
jdk8接口中允许有默认方法和静态方法,都是在接口中实现了.
实例
@FunctionalInterface
public interface A{
public void a();
default void b(){
System.out.println("我是A");
}
}
/** 调用默认方法*/
在实现它的类中
A.super.b();
/** 静态方法类似于类中的静态方法调用*/
也可以在实现类中重写默认方法
Stream
ava 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
串行流使用实例
Function<Entity, Entity> function = (entity) -> {
entity.setHeight(500L);
entity.setName("myName");
return entity;
};
List<Entity> myList=list.stream().
// map用于将流中的元素映射
map(function).
// filter设置流中的过滤
filter((entity)->entity.getHeight()>120L).
// 将根据sex从小到大排序
sorted(Comparator.comparing(Entity::getSex)).collect(Collectors.toList());
// 遍历List并打印性别
myList.forEach(entity -> System.out.println(entity.getSex()));
Optional类
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
Entity e = new Entity();
e.setMoney(BigDecimal.ONE);
/* 创建Optional容器,e可以为null*/
Optional<Entity> optional = Optional.ofNullable(e);
BigDecimal bigDecimal = BigDecimal.ZERO;
/* 如果e不为null*/
if (optional.isPresent()) {
// 如果e的money不为null则返回,否则返回0
bigDecimal = Optional.ofNullable(optional.get().getMoney()).orElse(BigDecimal.ZERO);
}
// orThrow(()->new Exception()) //如果不存在则抛出异常
//Objects.nonNull(obj); // 判断对象不为空
//Objects.
System.err.println(bigDecimal);
}