赞
踩
- 只包含一个抽象方法的接口,称为函数式接口
- 并且可以使用lambda表达式来创建该接口的对象,
- 可以在任意函数式接口上使用@FunctionalInterface注解,来检测它是否是符合函数式接口。
- 同时javac也会包含一条声明,说明这个接口是否符合函数式接口。
1. 自定义函数式接口
@FunctionalInterface
public interface MyNuber{
public double getValue();
}
2. 泛型函数式接口
@FunctionalInterface
public interface MyFunc<T>{
public T getValue(T t);
}
Consumer c = new Consumer<Student>() {
@Override
public void accept(Student student) {
System.out.println(student);
}
};
c.accept(new Student("张三",18));
//使用Lambda表达式实现
Consumer c1 = student->System.out.println(student);
c1.accept(new Student("李四",19));
Supplier<Student> s = new Supplier<Student>() {
@Override
public Student get() {
Student s = new Student("王五", 20);
return s;
}
};
//lambda表达式
Supplier<Student> s1=()->new Student("a",19);
Student student1 = s1.get();
System.out.println(student1);
Function<Integer, Student> f = new Function<Integer, Student>() {
@Override
public Student apply(Integer id) {
Student s = Student.getByIdStudent(id);
return s;
};
Student a = f.apply(3);
System.out.println(a);
//使用lambda表达式实现
Function<Integer, Student> ss=id->Student.getByIdStudent(id);
Student apply = ss.apply(2);
System.out.println(apply);
Predicate<Student> z = new Predicate<Student>() {
@Override
Student s = new Student(4, "zl", 18);
return student.age == s.age;
};
Student s1 = Student.getByIdStudent(2);
System.out.println(s1);
System.out.println(test);
//使用lambda表达式实现
Student s = new Student(4, "zl", 18);
Predicate<Student> z1=a->a.age==s.age;
Student s11 = new Student(5, "xx", 18);
boolean test1 = z1.test(s11);
System.out.println(test1);
在下面这个接口中,我们除了定义了一个抽象方法 study,还定义了一个带有默认实现的方法 play。 我们在实现这个接口时,可以只需要实现 study方法,默认方法 play可以直接调用即可。
// 定义一个公式接口
interface school{
// 学习
void study();
// 做游戏
default string play(String name) {
return "我和"+ name + "一起做游戏";
}
}
School school = new School() {
@Override
public void study() {
system.out.println("学习中");
}
};
可以用lambda表达式创建函数式接口对象
(参数列表) -> { 方法体 }
- 参数列表的数据类型可以省略
- 参数列表只有一个参数,可以把()去掉
- 如果方法体只有一条语句,可以把 { } 和 return 去掉
public void test1(){
Runnable r1 = new Runnable(){
@Override
public void run(){
System.out.println("我爱北京天安门");
}
};
Runnable r2 = ()->{
System.out.println("我爱北京天安门");
};
}
@Test public void test2(){ Consumer<String> con1 = new Consumer<String>() { @Override public void accept(String s) { System.out.println(s + 1); } }; Consumer<String> con2 = (String s)->{ System.out.println(s + 2); } //数据类型可以省略,因为可由编译器推断得出,称为“类型推断” Consumer<String> con3 = (s)->{ System.out.println(s + 3); } }
@Test
public void test3(){
Consumer<String> con1 = (s) -> {
System.out.println(s);
};
Consumer<String> con2 = s -> {
System.out.println(s);
};
}
@Test
public void test4(){
Comparator<Integer> com1 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1 + o2);
System.out.println(o1);
}
};
Comparator<Integer> com2 = (o1,o2) -> {
System.out.println(o1 + o2);
return o1.compareTo(o2);
};
}
@Test
public void test5(){
Comparator<Integer> com1 = (o1,o2) -> {
return o1.compareTo(o2);
};
Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);
}
应用场景:如果Lambda表达式所要实现的方案,已经有其他方法存在相同的方案,那么则可以使用方法引用,有下列四种情况:
- 类 :: 静态方法
- 类 :: 实例方法
- 类 :: 构造器
- 对象 :: 实例方法
- 数组:构造器
public static void main(String[] args) {
// 使用Lambda
Function<Integer, Integer> func = (i) -> Math.abs(i);
Integer i = func.apply(-10);
System.out.println(i);
// 使用方法引用
Function<Integer, Integer> func1 = Math::abs;
Integer i1 = func1.apply(-10);
System.out.println(i1);
}
public class MethodReferenece {
public static void main(String[] args) {
// Lambda方式
PersonBuilder pb = (name) -> new Person(name);
System.out.println(pb.buildPerson("zhangsan").getName());
// 方法引用
PersonBuilder pb1 = Person::new;
System.out.println(pb1.buildPerson("lisi").getName());
}
}
// Lambda方式
ArrayBuilder ab = (len) -> new int[len];
int[] array = ab.buildArray(5);
// 方法引用
ArrayBuilder ab1 = int[]::new;
int[] array1 = ab1.buildArray(5);
Stream操作的三个步骤
//第一种:通过集合:对于Collection接口(List 、Set、Queue等)直接调用Stream()方法可以获取Stream
List<String> list = new ArrayList<>();
Stream<String> stringStream = list.stream(); //返回一个顺序流
Stream<String> parallelStream = list.parallelStream(); //返回一个并行流(可多线程)
//第二种:通过数组
Stream<String> stream1 = Arrays.stream(new String[]{"CBB", "YJJ", "CB", "CJJ"});
//第三种:Stream.of()静态方法直接手动生成一个Stream
Stream<String> stream = Stream.of("A", "B", "C", "D");
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator
Stream API示例
创建List集合
//首先我们创建一个List集合
List<String> stringCollection = new ArrayList<>();
stringCollection.add("ddd2");
stringCollection.add("aaa2");
stringCollection.add("bbb1");
stringCollection.add("aaa1");
stringCollection.add("bbb3");
stringCollection.add("ccc");
stringCollection.add("bbb2");
stringCollection.add("ddd1");
Filter过滤
stringCollection
.stream()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
// "aaa2", "aaa1"
Sorted排序
stringCollection
.stream()
.sorted()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
// "aaa1", "aaa2"
Map转换
stringCollection
.stream()
.map(String::toUpperCase)
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);
// "DDD2", "DDD1", "CCC", "BBB3", "BBB2", "AAA2", "AAA1"
Match匹配
// 验证 list 中 string 是否有以 a 开头的, 匹配到第一个,即返回 true
boolean anyStartsWithA =
stringCollection
.stream()
.anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true
// 验证 list 中 string 是否都是以 a 开头的
boolean allStartsWithA =
stringCollection
.stream()
.allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false
// 验证 list 中 string 是否都不是以 z 开头的,
boolean noneStartsWithZ =
stringCollection
.stream()
.noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // true
Count计数
// 先对 list 中字符串开头为 b 进行过滤,让后统计数量
long startsWithB =
stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();
System.out.println(startsWithB); //
Reduce
Optional<String> reduced =
stringCollection
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);
reduced.ifPresent(System.out::println);
// "aaa1#aaa2#bbb1#bbb2#bbb3#ccc#ddd1#ddd2"
Parallel-Streams并行流
我们创建一个包含 1000000 UUID list 集合,分别通过顺序流和并行流,对这个 list 进行排序,测算耗时:
int max = 1000000;
List<String> values = new ArrayList<>(max);
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
顺序流:
// 纳秒:获取当前时间1
long t0 = System.nanoTime();
//获取串行流输出
long count = values.stream().sorted().count();
System.out.println(count);
//纳秒:获取当前时间2
long t1 = System.nanoTime();
// 纳秒转微秒
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("顺序流排序耗时: %d ms", millis));
// 顺序流排序耗时: 899 ms
并行流
// 纳秒:获取当前时间1
long t0 = System.nanoTime();
//并行流输出
long count = values.parallelStream().sorted().count();
System.out.println(count);
//纳秒:获取当前时间2
long t1 = System.nanoTime();
// 纳秒转微秒
long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);
System.out.println(String.format("并行流排序耗时: %d ms", millis));
// 并行流排序耗时: 472 ms
同样的逻辑处理,通过并行流,我们的性能提升了近 50%。完成这一切,我们需要做的仅仅是将 stream 改成了 parallelStream。
- @Target:用于描述注解的使用范围:接口、类、枚举等等
- @Retention:表示在”source、class、runtime“哪个阶段,注解依然存在
- @Documented:说明该注解将被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
//使用自定义注解 //通过四个元注解自定义注解 @Target(value = {ElementType.METHOD,ElementType.TYPE}) @Retention(value = RetentionPolicy.RUNTIME) @Documented @Inherited @interface MyAnnotation{ } @MyAnnotation public class Test01{ public void test(){ System.out.println("hello"); } }
对于注解(也被称做元数据),Java 8 主要有两点改进:类型注解和重复注解。
类型注解被用来支持在Java的程序中做强类型检查。配合第三方插件工具Checker Framework,可以在编译的时候检测出runtime error,以提高代码质量。
import checkers.nullness.quals.*;
public class TestDemo{
void sample() {
@NonNull Object my = new Object(); //通过,不报错
}
}
允许在同一声明类型(类,属性,或方法)上多次使用同一个注解。
- Java8以前,相同的注解在同一位置只能使用一次
- Java 8 引入了重复注解机制,这样相同的注解可以在同一地方使用多次。
- 重复注解机制本身必须用
@Repeatable注解,通过@Repeatable元注解标记该注解使用哪个注解组进行包含。
@interface MyHints {
Hint[] value();
}
@interface Hint {
String value();
}
@MyHints({@Hint("hint1"), @Hint("hint2")})
class Person {}
@interface MyHints {
Hint[] value();
}
@Repeatable(MyHints.class) //通过@Repeatable 元注解标记该注解使用哪个注解组进行包含。
@interface Hint {
String value();
}
@Hint("hint1")
@Hint("hint2")
class Person {}
public class RepeatingAnnotations { @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Filters { Filter[] value(); } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Repeatable(Filters.class) public @interface Filter { String value(); } @Filter("filter1") @Filter("filter2") public interface Filterable { } public static void main(String[] args) { for (Filter filter : Filterable.class.getAnnotationsByType(Filter.class)) { System.out.println(filter.value()); } } } 输出结果: filter1 filter2
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。