java8新特性
来源:互联网 发布:sql范围查询语句 编辑:程序博客网 时间:2024/06/07 10:56
Lambda表达式
一 基础语法: java8 引入一个新的操作符 “->” 该操作符称为操作符或lambda 操作符
操作符将Lambda 表达式拆分成两个部分
左侧:Lambda 表达式的参数列表
右侧:Lambda 表达式所执行的功能,即Lambda体
语法格式一、无参,无返回值
() -> System.out.println("hello java8");
语法格式二、有一个参数,并且无返回值 (若参数只有一个 小括号可以不写)
(x)-> System.out.println(x);
例 有个Student 接口 里面只有一个方法 void student(T t);
Student<String> s = (x)-> System.out.println(x);
s.student(“hello”);
即打印出hello
语法格式三:有两个以上的参数,有返回值,并且Lambda体中有多条语句
注意:该接口必须是函数式接口 即接口内部只有一个方法
语法格式四:有两个以上的参数,有返回值,并且Lambda体中有一条语句 return 和大括号可以不写
语法格式五:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM可以根据上下文推断出数据类型,即“类型推断”
二、四大内置核心函数式接口
1、Consumer<T> : 消费型接口 (无返回值)
void accept(T t);
2、Supplier<T> : 供给型接口 (有返回值)
T get();
3、Function(T,R) : 函数型接口 (有参,有返回值)
R apply(T t);
4、Predicate<T> : 断言型接口 (做判断操作)
boolean test(T t);
注意:函数式接口 是一个接口 里面有且仅有一个方法,如在接口上部添加 @FunctionalInterface 注解,若如此 此接口在写一个未实现的方法是不会通过编译
1、Consumer<T> : 消费型接口 (无返回值)
void accept(T t);
2、Supplier<T> : 供给型接口 (有返回值)
T get();
3、Function<T,R> : 函数型接口
R apply(t)
4、Boolean Predicate<T> : 断言型函数接口
boolea test(t);
三、方法引用:若Lambda 体中的内容有方法已经实现了,我们可以使用“方法引用”
(可以理解为方法引用是Lambda 表达式的另外一种表现形式)
主要有三种语法格式:
对象::实例方法
类::静态方法
类::实例方法
注意:1、Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中的抽象方法的函数列表和返回值类型保持一致;
2、若Lambda 参数列表中的第一个参数是实例方法的调用者,第二个参数是实例方法的参数时,可以使用 ClassName :: method )
注: 这方面知识点想要熟练使用要十分熟悉java类库或项目中的方法,方法引用需要返回值和参数全部对应上。本人水平,阅历经验需要加强,无法信手拈来java内部的方法,现实项目中可以用自己编写的方法。
// 对象::实例方法
@Test
public void test5() {
Person person = new Person(10, "张三");
Consumer<String> consumer = person::setName;
consumer.accept("abcedf");
System.out.println(person.getName());
}
此处程序结果为 abcdedf 。 (留个映像,每次编程往这上面靠,时间长了也就掌握了)
// 类::静态方法
@Test
public void test6() {
Comparator<Integer> comparable = Integer::compare;
int num = comparable.compare(100, 20);
System.out.println(num);
} 此处程序结果为1
// 类::实例方法
@Test
public void test7() {
Function<String, Integer> function = Integer::parseInt;
String str = "120";
int num = function.apply(str);
System.out.println(num);
}
此处程序结果为120
// 构造器引用
@Test
public void test8() {
Supplier<Person> supplier = Person::new;
Person person = supplier.get();
System.out.println(person.toString());
}
// 数组引用
@Test
public void test9() {
Function<Integer, String[]> function = x -> new String[x];
int num = function.apply(5).length;
Consumer<Integer> consumer = System.out::println;
consumer.accept(num);
function = String[]::new;
num = function.apply(6).length;
consumer.accept(num);
}
程序运行结果为 5 6;
四、 Stream 流
官方解释看了那么多,说白了 流 就是另外一种对数组或集合中的数据的操作方式。原理是 :将数据源即数组或集合转化成流,之后像过滤纯净水一样对此流进行一系列特定的操作,得到目标数组或集合,同时原来的数组或集合不被破坏。举个例子:假如 以前要拿出一个list集合中的特定数据,要用for循环(无论增强还是普通的for循环),然后在for循环里拿到一个数据进行操作。现在用流不在用for循环,操作是先将list转化成流,在此基础上进行filer过滤操作等等,这个时候每个数据都会执行filer等操作,然后在返回成目标listlist。看似流比for复杂,但其实用流只需要一行代码搞定,而用for循环则至少三行。
一、操作步骤
1、创建Stream
2、中间操作
3、终止操作
1、创建Stream
@Test
public void test1() {
// 1、通过#Collection 系列集合提供的stream()或parellerStream()
List<String> strs = new ArrayList<>(); // 集合
Stream<String> stream = strs.stream();// 转化成流
// 2、通过#Arrays()中的静态方法stream()获取数组流
String[] args = new String[5];// 数组
stream = Arrays.stream(args);
// 3、通过#Stream()类中的静态方法of()
stream = Stream.of("a", "b", "c");
// 4、创建无限流 (暂无发现使用场合)
// 迭代
Stream<Integer> stream2 = Stream.iterate(0, x -> x + 2);
// 生成
Stream<Integer> stream3 = Stream.generate(() -> (int) (Math.random() * 10));
} 2、中间操作
1) 筛选与切片
filer - 接Lambda表达式,从流中过滤某些元素;
limit - 截断流,使其元素不超过给定的数量
skip - 跳过元素,返回一个扔掉N元素之后的流,若元素不足N个,则返回一个空流,与limit互补
distinct - 筛选,通过流所生成元素的hashCode() 和equals()去除重复元素。
注意:在没执行终止操作时,中间操作不会被执行,这种机制称之为"惰性求值"
@Test
public void test2() {
List<Person> request = Arrays.asList(new Person(20, "张三"), new Person(10, "李四"), new Person(15, "王五"));
request.stream().filter(t -> {
System.out.println("filter....");
return t.getAge() > 15;
}).forEach(System.out::println);
}运行结果
filter....Person [name=张三, age=20]filter....filter....
limit
@Test
public void test2() {
List<Person> request = Arrays.asList(new Person(20, "张三"), new Person(16, "end"), new Person(10, "李四"),
new Person(15, "王五"));
request.stream().filter(t -> {
System.out.println("filter正在被执行");
return t.getAge() > 15;
}).limit(2).forEach(System.out::println);
} 这里需要注意的是 limit 只会输出满足条件的数据,但程序执行次数却不一定,程序会一直执行直到满足条件的数据到2个;
如 上面程序运行的结果为
filter正在被执行Person [name=张三, age=20]filter正在被执行Person [name=end, age=16]
切换list的元素的位置;
@Test
public void test2() {
List<Person> request = Arrays.asList(new Person(20, "张三"), new Person(10, "李四"), new Person(15, "王五"),
new Person(16, "end"));
request.stream().filter(t -> {
System.out.println("filter正在被执行");
return t.getAge() > 15;
}).limit(2).forEach(System.out::println);
} 上面的程序运行结果为:
filter正在被执行Person [name=张三, age=20]filter正在被执行filter正在被执行filter正在被执行Person [name=end, age=16]这种现象在某种意义上提高了代码运行效率
skip 跳过
@Test
public void test2() {
List<Person> request = Arrays.asList(new Person(20, "张三"), new Person(10, "李四"), new Person(15, "王五"),
new Person(16, "end"));
request.stream().filter(t -> {
System.out.println("filter正在被执行");
return t.getAge() > 15;
}).skip(1).forEach(System.out::println);
}注意:因为这里的skip写在filter的后面,所以这里跳过的是满足filter的数据,因此打印结果为
filter正在被执行filter正在被执行filter正在被执行filter正在被执行Person [name=end, age=16]
同理:skip也可以写在filter的前面,那么就是先跳过后过滤。
distinct - 筛选,通过流所生成元素的hashCode() 和equals()去除重复元素。
注意:要实现此方法,需要在person类或者特定pojo类中重写hashCode()和equals()方法
@Test
public void test2() {
List<Person> request = Arrays.asList(new Person(20, "张三"), new Person(10, "李四"), new Person(15, "王五"),
new Person(16, "end"), new Person(16, "end"));
request.stream().filter(t -> {
System.out.println("filter正在被执行");
return t.getAge() > 15;
}).distinct().forEach(System.out::println);
}运行结果为:
filter正在被执行Person [name=张三, age=20]filter正在被执行filter正在被执行filter正在被执行Person [name=end, age=16]filter正在被执行
2)映射
map - 接收Lambda表达式,将元素转成其他形式或提取信息,接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap - 接收一个函数作为参数,将流中的每个值换成另一个流,然后把所有流链接成一个新的流
public void test3() {
List<String> request = Arrays.asList("a", "b", "c", "d", "e");
List<String> respose = request.stream().map(t -> t.toUpperCase()).collect(Collectors.toList());
respose.forEach(System.out::print);
}运行结果为:ABCDE
3、终止操作
1) 归约
reduce(T identity , BinaryOperator) / reduce(BinaryOperator) --可以将流中的元素反复结合起来,得到一个新的值。
@Test
public void test4() {
String str = "1abc1dec104"; // 一个字符串
char[] c = str.toCharArray();// 转化成数组
List<String> strings = new ArrayList<String>();
for (char d : c) {
strings.add(String.valueOf(d));// 将char类型的数组转成String类型的list
}
String newStr = strings.stream() // 转化成流
.filter(t -> t.matches("[a-zA-Z]+")) // 过滤出字母
.reduce("", (x, y) -> x + y); // 将结果集归约成一个字符串
System.out.println(newStr);
} 运行结果为:abcdec
2)收集
collect -- 将流转化成其他形式,接收一个Collector 接口的实现,用于给Stream中元素做汇总的方法
@Test
public void test5() {
List<String> strList = Arrays.asList("aa", "bb", "cc", "dd", "ee", "ee");
strList.forEach(System.out::print);
System.out.println("---------------------------");
Set<String> strSet = strList.stream().map(t -> t.toUpperCase()).collect(Collectors.toSet());
strSet.forEach(System.out::print);
} 0 0
- java8 新特性
- java8新特性 ---译
- Java8新特性教程
- Java8新特性学习
- JAVA8新特性
- Java8新特性详解
- JAVA8的新特性
- java8 新特性
- java8新特性
- java8 新特性
- JAVA8新特性一览
- Java8 新特性学习
- Java8新特性 Stream
- java8新特性
- java8新特性
- java8新特性
- java8新特性学习
- JAVA8新特性
- js获取滚动条位置
- 解决GAT项目Bug:轨迹分析查询不到数据
- Transparent Handwritten Signatures
- maven通过system引入jar问题
- [图形学] 四元数
- java8新特性
- LeetCode-501. Find Mode in Binary Search Tree (JAVA)出现次数最多的元素
- 正则表达式全部符号解释
- supervisor(二)event
- 冒泡排序(java)
- delphi经典大写数字转换函数
- SSL certificate problem: unable to get local issuer certificate
- kafka数据可靠性深度解读
- JVM 原理概要