jdk8的新特性
1、Lambda表达式&函数式接口
1.1 什么是Lambda表达式
Lambda表达式可以理解为一种匿名函数的替代,Lambda表达式允许将函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递,目的是简化代码的编写
1.2 什么是函数式接口
lambda表达式需要函数式接口的支持,
所谓函数式接口,是指只有一个抽象方法
另外JDK8也提供了一个注解,帮助我们编译时检查语法是否符合
注解:@FunctionInterface
1.3 Lambda表达式使用案例
lambda 基本语法
函数式接口(A) 变量名(b) = (参数1,参数2...)->{
//方法体;
}
A类型是函数式接口 或者 是被@FunctionInterface注解修饰的接口
案例1
//普通方式
//匿名内部类
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("run....");
}
};
Thread t1 = new Thread(runnable);
t1.start();
//lambda 方式1
Runnable runnable1 = ()->{
System.out.println("lambda..");
};
Thread t2 = new Thread(runnable1);
t2.start();
//lambda 方式2
//单个语句可省略大括号
Thread t3 = new Thread(()-> System.out.println("hello Lambda!"));
t3.start();
案例2
//如果方法体有返回值并且方法体只有一条语句时,可以省略return 和 ; 和 {}
//如果方法体没有返回值并且方法体只有一条语句时,可省略 ; 和 {}
//普通方式
//匿名内部类
Comparator<String> comparator = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
};
TreeSet set = new TreeSet(comparator);
//lambda 方式1
Comparator<String> com1 = ((o1, o2) -> {
return o1.length() - o2.length();
});
TreeSet treeSet = new TreeSet(com1);
//lambda 方式2
//这种方式有时候需加泛型,有可能后面参数调用的方法在Object类型中找不到
TreeSet<String> strings = new TreeSet<>(((o1, o2) -> o1.length() - o2.length()));
1.4 lambda表达式注意事项
lambda 引入新的操作符:->(箭头操作符),->将表达式分成两部分
左侧:(参数1,参数2...)表示参数列表;
右侧:{} 内部是方法体
-
形参列表的参数类型会自动判断;
-
如果参数列表为空,只需保留();
-
如果形参只有一个,()可以省略,只需要参数的名称即可;
-
如果方法体有返回值并且方法体只有一条语句时,可以省略return 和 ; 和 {}
如果方法体没有返回值并且方法体只有一条语句时,可以省略 ; 和 {}
-
使用lambda表达式不会生成一个单独的内部类文件
-
lambda表达式若访问了局部变量,则局部变量必须是final修饰的;若是局部变量没有加final关键字,系统会自动添加,此后再修改局部变量,会报错
2、流式编程-StreamAPI
2.1 什么是Stream
Stream是jdk8中处理数组、集合的抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。
一个Stream表面上与一个集合很类似,集合中保存的是数据,流设置的是对数据的操作。
Stream的特点:
- Stream自己不会存储元素。
- Stream不会改变源对象。相反,它会返回一个持有结果的新Stream。
- Stream 操作是延迟执行的,这意味着他会等到需要结果的时候才执行。详见下面例子
- Stream 遵循“做什么,而不是怎么去做”的原则。只需要描述做什么,而不用考虑程序是怎么实现的
- Stream 的终止操作执行完后,会关闭;该Stream不能被再次使用。
2.2 体验StreamAPI的特点
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("wang");
list.add("han");
list.add("qing");
int c = 0;
for (String s : list) {
if (s.length() > 3){
c++;
}
}
System.out.println(c);
//Stream的方式
// s -> s.length() > 3 lambda表达式
//1、链式编程
//2、函数式接口
//3、lambda表达式
//刚开始这一步并没有执行
Stream<String> stream = list.stream().filter(s -> s.length() > 3);//中间操作
//count() 结果的时候才执行上面的步骤
long c1 = stream.count();
System.out.println(c1);
long c2 = stream.count();//运行报错 :流已经被操作或关闭
System.out.println(c2);
}
2.3 使用StreamAPI的步骤
- 创建一个Stream 。(创建)
- 在一个或多个步骤中,将初始stream 转化到另一个Stream的中间操作。 (中间操作)
- 使用一个终止操作来产生一个结果。该操作会强制它之前的延时操作立即执行。在这之后,该Stream就不能再被使用了。(终止操作)
2.4 创建Stream的方式
-
集合创建:
详见上面示例
-
数组创建:
int[] arr = {15,6,1,3,8};
IntStream stream1 = Arrays.stream(arr);
long c3 = stream1.filter((i) -> i > 2).count();
System.out.println(c3);
2.5 Stream的中间操作
2.5.1 筛选和切片(filter,limit(n),skip(n),distinct)
class Employee{
private String name;
private int age;
private int salary;
public Employee(String name, int age, int salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
'}';
}
@Override
public boolean equals(Object o) {
System.out.println("------调用了equals方法-----");
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age &&
salary == employee.salary &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
// System.out.println(Objects.hash(name, age, salary));
return Objects.hash(name, age, salary);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
package com.wanghq.learning.JDK8;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
/**
* Stream的中间操作
*/
public class StreamAPI_1 {
public static void main(String[] args) {
Employee e1 = new Employee("zhangsan", 25, 6000);
Employee e2 = new Employee("lisi", 30, 25000);
Employee e3 = new Employee("wangwu", 40, 50000);
Employee e4 = new Employee("wangwu", 40, 50000);
List<Employee> list = new ArrayList<Employee>();
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
//筛选年龄大于 28 的员工信息
Stream<Employee> s1 = list.stream().filter(e -> e.getAge() > 28);
s1.forEach(e-> System.out.println(e));
//筛选年龄大于 28 的员工 并 去重
// 去重方法会自动调用hashCode() 和 equals方法,hashCode方法值相同再判断equals方法
Stream<Employee> s2 = list.stream().filter(e -> e.getAge() > 28).distinct();
System.out.println(s2.count());
System.out.println("=========== skip =============");
//跳过前几个(长度)
Stream<Employee> skip = list.stream().skip(2);
skip.forEach(System.out::println);
System.out.println("=========== limit =============");
//获取前几个(长度)
Stream<Employee> limit = list.stream().limit(2);
limit.forEach(System.out::println);
}
}
-
《Effective Java》是本好书,连Java之父James Gosling都说,这是一本连他都需要的Java教程。在这本书中,作者指出,如果重写了一个类的equals()方法,那么就必须一起重写它的hashCode()方法!必须!没有商量的余地!
必须使得重写后的equals()满足如下条件:
根据equals()进行比较,相等的两个对象,hashCode()的值也必须相同;
根据equals()进行比较,不相等的两个对象,hashCode()的值可以相同,也可以不同;
因为这是Java的规定,违背这些规定将导致Java程序运行不再正常。
2.5.2 映射(map)
- 将元素转成其他形式 或者提取信息。接受一个函数作为参数,该函数会被应用到每个元素上, 并将其映射成一个新的元素
- 将一个集合的数据转换成另一个集合
//map接受 lambda表达式
Stream<Integer> integerStream = list.stream().map(e -> e.getAge());
integerStream.forEach(e-> System.out.println(e));
//小写转大写
List<String> lists = Arrays.asList("a", "b", "c");
Stream<String> stream = lists.stream().map(String::toUpperCase/*e->e.toUpperCase()*/);
// stream.forEach(System.out::println);两种写法都行
stream.forEach(e-> System.out.println(e));
2.5.3 排序 (sorted)
//排序
System.out.println("====按年龄自然排序===");
Stream<Integer> sorted = list.stream().map(e -> e.getAge()).sorted();
sorted.forEach(System.out::println);
System.out.println("====定制排序1===");
Stream<String> sorted1 = list.stream().map(e -> e.getName()).sorted((x, y) -> {
return x.length() - y.length();
});
sorted1.forEach(System.out::println);
System.out.println("====定制排序2===");
Stream<Employee> sorted2 = list.stream().sorted((x, y) -> {
if (x.getAge() == y.getAge()) {
return x.getName().compareTo(y.getName());
} else
return y.getAge() - x.getAge();
});
sorted2.forEach(employee -> System.out.println(employee));
//定制排序2 的匿名内部类写法 复习下匿名内部类
System.out.println("====定制排序2===");
Stream<Employee> sorted2 = list.stream().sorted(
//匿名内部类, Comparator类也是个函数式接口,所以能写成lambda表达式
new Comparator<Employee>() {
@Override
public int compare(Employee x, Employee y) {
if (x.getAge() == y.getAge()) {
return x.getName().compareTo(y.getName());
} else
return y.getAge() - x.getAge();
}
}
);
sorted2.forEach(employee -> System.out.println(employee));
2.6 终止操作
2.6.1 遍历操作
forEach
2.6.2 查找和匹配
- allMatch 检查当前流中是否匹配所有元素
- anyMatch 检查当前流中是否至少匹配一个元素
- noneMatch 检查当前流中是否没有匹配的元素
- findFirst 返回当前流中的第一个元素
- findAny 返回当前流中的任意元素
- count 返回当前流的总个数
- max 返回当前流中自定义比较规则(Comparator函数式接口)的最大值
- min 返回当前流中自定义比较规则(Comparator函数式接口)的最小值
boolean b = list.stream().allMatch(employee -> employee.getAge() >30);
System.out.println(b);
boolean b1 = list.stream().anyMatch(e -> e.getAge() > 30);
System.out.println(b1);
System.out.println(list.stream().noneMatch(e -> e.getAge() > 40));
Optional<Employee> first = list.stream().findFirst();
System.out.println(first.get());
Optional<Employee> any = list.stream().findAny();
System.out.println(any.get());
Optional<Employee> max = list.stream().max((x, y) -> {
return x.getAge() - y.getAge();
});
System.out.println(max.get());
2.7 Stream的串行 和 并行
Stream有串行和并行两种,串行Stream的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。
串行
public static void main(String[] args) {
List list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
list.add(UUID.randomUUID().toString());
}
long start = System.currentTimeMillis();
long count = list.stream().sorted().count();
System.out.println(count);
long end = System.currentTimeMillis();
//计算排序的时间
System.out.println(end-start);// 669
}
并行
public static void main(String[] args) {
List list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
list.add(UUID.randomUUID().toString());
}
long start = System.currentTimeMillis();
//命令式的
long count = list.parallelStream().sorted().count();
System.out.println(count);
long end = System.currentTimeMillis();
//计算排序的时间
System.out.println(end-start);// 390
}
本文来自博客园,作者:wannx,转载请注明原文链接:https://www.cnblogs.com/wannx/articles/15202194.html

浙公网安备 33010602011771号