在这里主要介绍主要的五个特性
1. lambda表达式
2. 函数式接口。
3. 方法引用。
4. Stream流
5. 日期时间类
(1)Lambda表达式
语法: (参数列表)->{方法体}
前提: 接口必须为函数式接口。
注意: 函数式接口:接口中只有一个抽象方法。
(参数1,参数2): 抽象方法的参数
->: 分隔符
{}:表示抽象方法的实现
public class Text01 {
public static void main(String[] args) {
Thread thread = new Thread(new Me());
thread.start();
Runnable me=new Runnable() {
@Override
public void run() {
System.out.println("匿名内部类");
}
};
me.run();
System.out.println("------------");
new Thread(()->{
System.out.println("Lambda表达式");
}).start();
}
}
class Me implements Runnable{
@Override
public void run() {
}
}
public class Text02 {
public static void main(String[] args) {
Swimming swimming = new Swimming() {
@Override
public void swimming() {
System.out.println("匿名内部类方式");
}
};
fun(swimming);
// lambda表达式
fun(()->{
System.out.println("使用lambda表达式");
});
}
public static void fun(Swimming s){
s.swimming();
}
//函数接口
interface Swimming {
public void swimming();
}
}
2. 函数式接口。
函数式编程:
JDK内置哪些函数式接口:
【1】消费型:有参无返回值。Consumer<T>
【2】供给型:无参有返回值: Supplier<T>
【3】函数型:有参有返回值: Function<T,R>
【4】断言型:有参返回值为boolean ,Predicate<T>
//消费性接口
public class Text05 {
public static void main(String[] args) {
Consumer<Double> c=t-> System.out.println("大保健花费:"+t);
fun01(c,1000.0);
}
// 调用某个方法时,该方法为参数类型接口,这时可以用lambda表达式
public static void fun01(Consumer<Double> consumer,double money){
consumer.accept(money);
}
}
//函数型接口
public class Text06 {
public static void main(String[] args) {
fun((t) -> {
return t.length();
}, "DDZS");
}
public static void fun(Function<String, Integer> function, String length) {
Integer s = function.apply(length);
System.out.println("结果为:" + s);
}
}
/**
* 段言行接口
* boolean text(T t) 返回值进行判断
*/
public class Text07 {
public static void main(String[] args) {
fun(n->{return n.length()>18?true:false;},"王组长");
}
public static void fun(Predicate<String> predicate,String height){
boolean h= predicate.test(height);
System.out.println("该长度是否爽啊"+h);
}
}
/**
* 供给型接口
*/
public class Text08 {
public static void main(String[] args) {
// 随机产生随机数范围为0-10
fun(()->new Random().nextInt(10));
}
public static void fun(Supplier<Integer> supplier){
Integer random = supplier.get();
System.out.println("产生的随机数为:"+random);
}
}
(3)方法引用: 当lambda表达式有且仅有一条语句,而这条语句是调用了其他的方法。这时可以考虑使用方法引用。::
[1]静态方法引用: 类名::静态方法 (参数)->类名.静态方法(参数)
[2]实例方法引用: 对象::实例方法 (参数)->对象.实例方法(参数)
[3]对象方法引用: 类名::实例方法. (参数1,参数2)->参数1.实例方法(参数2)
[4]构造方法引用: 类名::new (参数)->new 类名(参数)
public class Test03 {
public static void main(String[] args) {
//[3]对象方法引用: 类名::实例方法. (参数1,参数2)->参数1.实例方法(参数2)
// Function<String,Integer> function=(str)->{
// return str.length();
// };
// Function<String,Integer> function=String::length;
//
// Integer len = function.apply("hello");
// System.out.println(len);
//比较两个字符串的内容是否一致.T, U, R
// R apply(T t, U u);
// BiFunction<String,String,Boolean> bi=(t,u)->{
// return t.equals(u);
// };
// BiFunction<String,String,Boolean> bi=String::equals;
// Boolean aBoolean = bi.apply("hello", "world");
// System.out.println(aBoolean);
// [4]构造方法引用: 类名::new (参数)->new 类名(参数)
// Supplier<String> supplier=()->{
// return new String("hello");
// };
// Supplier<People> supplier=People::new;
// Function<String,People> function=(n)->new People(n);
Function<String,People> function= People::new;
People s = function.apply("张三");
System.out.println(s);
}
}
class People{
private String name;
public People() {
}
public People(String name) {
this.name = name;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
'}';
}
}
4. Stream流
Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式。Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找、过滤、筛选等操作.
为什么使用Stream流
当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。我们来体验 集合操作数据的弊端,需求如下:
一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,张强,张三丰,何线程 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
代码如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class My {
public static void main(String[] args) {
// 一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,张强,张三丰
// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
// 1.拿到所有姓张的
ArrayList<String> zhangList = new ArrayList<>(); // {"张无忌", "张强", "张三丰"}
for (String name : list) {
if (name.startsWith("张")) {
zhangList.add(name);
}
}
// 2.拿到名字长度为3个字的
ArrayList<String> threeList = new ArrayList<>(); // {"张无忌", "张三丰"}
for (String name : zhangList) {
if (name.length() == 3) {
threeList.add(name);
}
}
// 3.打印这些数据
for (String name : threeList) {
System.out.println(name);
}
}
}
分析:
这段代码中含有三个循环,每一个作用不同:
首先筛选所有姓张的人;
然后筛选名字有三个字的人;
最后进行对结果进行打印输出。
每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。这是理所当然的么?不是。循环 是做事情的方式,而不是目的。每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,只能再使 用另一个循环从头开始。
那Stream能给我们带来怎样更加优雅的写法呢?
Stream的更优写法
package demo08; import java.util.ArrayList; import java.util.Collections; import java.util.function.Predicate; public class Test { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰","何线程"); list.stream() .filter(item->item.startsWith("张")) .filter(item->item.length()==3) .forEach(item-> System.out.println(item)); } }
Stream流的原理
注意:Stream和IO流(InputStream/OutputStream)没有任何关系,请暂时忘记对传统IO流的固有印象!
Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种==数据结构==,==不保存数据==,而是对数据进行==加工 处理==。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
如何获取Stream流对象。
public class Test02 {
public static void main(String[] args) {
//通过集合对象调用stream()获取流
List<String> list=new ArrayList<>();
list.add("闫克起");
list.add("何线程");
list.add("杨坤");
list.add("王地");
Stream<String> stream = list.stream();
//通过Arrays数组工具类获取Stream对象
int[] arr={3,4,5,63,2,34};
IntStream stream1 = Arrays.stream(arr);
//使用Stream类中of方法
Stream<String> stream2 = Stream.of("hello", "world", "spring", "java");
//LongStream
LongStream range = LongStream.range(1, 10);
//上面都是获取的串行流。还可以获取并行流。如果流中的数据量足够大,并行流可以加快处速度。
Stream<String> stringStream = list.parallelStream();
//
// stringStream.forEach(item-> System.out.println(item));
stringStream.forEach(System.out::println);
}
}
public class Text02 {
public static void main(String[] args) {
// stream串行流的四种获取方法
// 通过集合对象调用stream流
ArrayList<String> list = new ArrayList<>();
list.add("DD");
list.add("桥本坏奈");
list.add("工藤静香");
list.add("新恒结衣");
Stream<String> stream = list.stream();
stream.forEach(item-> System.out.println(item));
// 通过Arraylist数组工具类获取stream对象
int[]arr = {1,5,7,9,6};
IntStream stream1 = Arrays.stream(arr);
stream1.forEach(item2-> System.out.println(item2));
// 通过使用Stream类中of方法
Stream<String> of = Stream.of("java","springBoot","shiro","Mybatis");
of.forEach(item3-> System.out.println(item3));
// 通过使用LongStream来获取特殊的stream流
LongStream longStream = LongStream.rangeClosed(1, 5);
longStream.forEach(item4-> System.out.println(item4));
// stream并行流获取方法 在代码比较多的情况下 运行效率快
Stream<String> stringStream = list.parallelStream();
stringStream.forEach(a-> System.out.println(a));
}
}
Stream流中常见的api
public class Text09 {
public static void main(String[] args) {
List<Person> personList = new ArrayList<>();
personList.add(new Person("欧阳雪", 18, "中国", "女"));
personList.add(new Person("Tom", 24, "美国", "男"));
personList.add(new Person("Harley", 22, "英国", "女"));
personList.add(new Person("向天笑", 20, "中国", "男"));
personList.add(new Person("李康", 22, "中国", "男"));
personList.add(new Person("小梅", 20, "中国", "女"));
personList.add(new Person("何雪", 21, "中国", "女"));
personList.add(new Person("李康", 22, "中国", "男"));
// 1.找出集合中年龄小于20岁的人并输出
personList.stream().filter(item -> item.getAge() < 20).forEach(System.out::println);
// 2.找出所有中国人的数量 使用count终止操作
long count = personList.stream().filter(item -> item.getCountry().equals("中国")).count();
System.out.println(count);
// 3.找出所有性别为女的所有人
personList.stream().filter(item -> item.getSex().equals("女")).forEach(System.out::println);
//4.集合中间操作 显示名字和年龄
personList.stream().map(item -> {
Map<String, Object> map = new HashMap<>();
map.put("name", item.getName());
map.put("age", item.getAge());
return map;
}).forEach(System.out::println);
// 对集合中的元素进行排序 需要自定义排序规则
personList.stream().sorted((a1, a2) -> a1.getAge() - a2.getAge()).forEach(System.out::println);
// 找出集合中年龄最大的人
Optional<Person> max = personList.stream().max((a1, a2) -> a1.getAge() - a2.getAge());
System.out.println(max.get());
//找出集合中名字最长的人
String s = personList.stream().map(item -> item.getName()).max((o1, o2) -> o1.length() - o2.length()).get();
System.out.println(s);
//搜集方法collection 的属于终止方法
// 年龄大于20且性别为女
List<Person> collection = personList.stream().filter(item -> item.getAge() > 20).filter(item -> item.getSex() == "女").collect(Collectors.toList());
System.out.println(collection);
// findFirst match
Optional<Person> first = personList.parallelStream().filter(item -> item.getSex() == "女").findAny();
System.out.println(first);
boolean b = personList.parallelStream().filter(item -> item.getSex() == "女").anyMatch(item -> item.getAge() > 20);
System.out.println(b);
}
}
class Person {
private String name;
private Integer age;
private String country;
private String sex;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", country='" + country + '\'' +
", sex=" + sex +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person(String name, Integer age, String country, String sex) {
this.name = name;
this.age = age;
this.country = country;
this.sex = sex;
}
}
Stream流练习题
交易员类
public class Trader {
private final String name;
private final String city;
public Trader(String name, String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public String getCity() {
return city;
}
@Override
public String toString() {
return "Trader{" +
"name='" + name + '\'' +
", city='" + city + '\'' +
'}';
}
}
Transaction(交易记录)
public class Transaction {
private final Trader trader;
private final int year;
private final int value;
public Transaction(Trader trader, int year, int value){
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader(){
return this.trader;
}
public int getYear(){
return this.year;
}
public int getValue(){
return this.value;
}
public String toString(){
return "{" + this.trader + ", " +
"year: "+this.year+", " +
"value:" + this.value +"}";
}
}
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
List<Transaction> transactions = Arrays.asList(
new Transaction(brian, 2011, 300),
new Transaction(raoul, 2012, 1000),
new Transaction(raoul, 2011, 400),
new Transaction(mario, 2012, 710),
new Transaction(mario, 2012, 700),
new Transaction(alan, 2012, 950)
);
(1) 找出2011年发生的所有交易,并按交易额排序(从低到高)。
(2) 交易员都在哪些不同的城市工作过?
(3) 查找所有来自于剑桥的交易员,并按姓名排序。
(4) 返回所有交易员的姓名字符串,按字母顺序排序。
(5) 有没有交易员是在米兰工作的?
(6) 打印生活在剑桥的交易员的所有交易额。
(7) 所有交易中,最高的交易额是多少?
(8) 找到交易额最小的交易。
附答案
package aaa.dd.demo11;
import java.util.*;
import java.util.stream.Collectors;
public class Text {
public static void main(String[] args) {
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
List<Transaction> transactions = Arrays.asList(
new Transaction(brian, 2011, 300),
new Transaction(raoul, 2012, 1000),
new Transaction(raoul, 2011, 400),
new Transaction(mario, 2012, 710),
new Transaction(mario, 2012, 700),
new Transaction(alan, 2012, 950)
);
// 1.找出2011年发生的所有交易,并按照交易顺序从低到高排序
List<Transaction> collect = transactions.stream().filter(a->a.getYear()==2011).
sorted((o1, o2) -> o1.getValue()- o2.getValue()).collect(Collectors.toList());
// System.out.println(collect);
//2. 交易员都在哪些不同的城市工作过?
transactions.stream().map(item->{
Map<String,Object> map=new HashMap<>();
map.put("city",item.getTrader().getCity());
map.put("name",item.getTrader().getName());
return map;
}).distinct().forEach(System.out::println);
System.out.println("---------------");
// (3) 查找所有来自于剑桥的交易员,并按姓名排序。
List<Trader> traderList =transactions.stream()
.map(item->item.getTrader()).filter((item)->item.getCity().equals("Cambridge"))
.sorted(Comparator.comparing((item)->item.getName())).collect(Collectors.toList());
traderList.stream().forEach(System.out::println);
System.out.println("---------------");
// (4) 返回所有交易员的姓名字符串,按字母顺序排序。
String sort=traderList.stream().map(item->item.getName())
.distinct().sorted().collect(Collectors.joining());
System.out.println(sort);
System.out.println("---------------");
// (5) 有没有交易员是在米兰工作的?
boolean milan=transactions.stream().anyMatch(item->item.getTrader().getCity().equals("Milan"));
System.out.println(milan);
System.out.println("---------------");
// (6) 打印生活在剑桥的交易员的所有交易额。
transactions.stream().filter(item->item.getTrader().getCity().equals("Cambridge")).map(item->item.getValue())
.forEach(System.out::println);
System.out.println("---------------");
// (7) 所有交易中,最高的交易额是多少?
Optional<Transaction> max = transactions.stream().max((o1, o2) -> o1.getValue()- o2.getValue());
System.out.println(max.get());
// Optional<Transaction> max =transactions.stream().max(Comparator.comparing(Transaction::getValue));
// System.out.println(max);
System.out.println("---------------");
// (8) 找到交易额最小的交易。
Optional<Transaction> min = transactions.stream().min((o1, o2) -> o1.getValue()- o2.getValue());
// Optional<Transaction> min =transactions.stream().min(Comparator.comparing(Transaction::getValue));
System.out.println(min);
}
// 交易员类
public static class Trader {
private final String name;
private final String city;
public Trader(String name, String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public String getCity() {
return city;
}
@Override
public String toString() {
return "Trader{" +
"name='" + name + '\'' +
", city='" + city + '\'' +
'}';
}
}
// Transaction(交易记录)
public static class Transaction {
private final Trader trader;
private final int year;
private final int value;
public Transaction(Trader trader, int year, int value){
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader(){
return this.trader;
}
public int getYear(){
return this.year;
}
public int getValue(){
return this.value;
}
public String toString(){
return "{" + this.trader + ", " +
"year: "+this.year+", " +
"value:" + this.value +"}";
}
}
}
5. 日期时间类
旧的日期时间的缺点:
设计比较乱: Date日期在java.util和java.sql也有,而且它的时间格式转换类在java.text包。
线程不安全。
新增加了哪些类?
LocalDate: 表示日期类。yyyy-MM-dd
LocalTime: 表示时间类。 HH:mm:ss
LocalDateTime: 表示日期时间类 yyyy-MM-dd t HH:mm:ss sss
DatetimeFormatter:日期时间格式转换类。
Instant: 时间戳类。
Duration: 用于计算两个日期类
public class Text01 {
public static void main(String[] args) {
LocalDate now = LocalDate.now();//获取当前日期
//指定日期
LocalDate date = LocalDate.of(2020,7,23);
// System.out.println(now);
// System.out.println(date);
//获取当前时间包括日期
LocalDateTime now1 = LocalDateTime.now();
// System.out.println(now1);
//计算日期差
LocalTime now2=LocalTime.now();//当前时间
LocalTime of = LocalTime.of(12,30,20,500);
LocalDateTime now3 = LocalDateTime.now();
LocalDateTime now4 = LocalDateTime.of(2022,7,1,12,30,30);
Duration between = Duration.between(now3, now4);
System.out.println(between.toDays());
///字符串转化为日期格式
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate parse = LocalDate.parse("2022-07-20", dateTimeFormatter);
String format = parse.format(dateTimeFormatter);
System.out.println(format);
}
}