java8新特性
Lambda(核心)
用于快速的实现匿名内部类中的方法。
例子:
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("do something.");
}
}
如果我们想要写一些线程,而每个线程中的实现很简单,就像例子中的只在控制台打印一句话,那么还需要多写4行代码,很麻烦,可读性也不高。下面,看下lambda的实现:
Runnable r = () -> System.out.println("do something.");
lambda的基础语法:
expression = (variable) -> action
-
variable:可以是一个变量,一个占位符,也可以是多个变量(x,y,z)。
-
action:实现的代码逻辑,如果一行处理不完,可以用“{}”将执行的代码包起来。
-
expression:返回的值。
使用姿势:
public class FunctionInterfaceDemo {
@FunctionalInterface
interface Predicate<T> {
boolean test(T t);
}
/**
* 执行Predicate判断
*
* @param age 年龄
* @param predicate Predicate函数式接口
* @return 返回布尔类型结果
*/
public static boolean doPredicate(int age, Predicate<Integer> predicate) {
return predicate.test(age);
}
public static void main(String[] args) {
boolean isAdult = doPredicate(20, x -> x >= 18);
System.out.println(isAdult);
}
}
如上述代码所示,当一个接口类中只有一个方法,且接口类作为变量传入函数中的时候,就可以使用lambda函数。
四大内置接口
java8为lambda提供了4大内置接口,分别消费型接口、供给型接口、函数型接口、断言型接口。其它的很多接口都是这四种接口衍生出来的,我们可以根据入参和出参类型的不同灵活使用。
消费型接口示例(只有入参):
//消费money
public static void donation(Integer money, Consumer<Integer> consumer){
consumer.accept(money);
}
public static void main(String[] args) {
donation(1000, money -> System.out.println("好心的麦乐迪为Blade捐赠了"+money+"元")) ;
}
供给型接口示例(只有出参):
//传入随机数,返回集合
public static List<Integer> supply(Integer num, Supplier<Integer> supplier){
List<Integer> resultList = new ArrayList<Integer>() ;
for(int x=0;x<num;x++)
resultList.add(supplier.get());
return resultList ;
}
public static void main(String[] args) {
List<Integer> list = supply(10,() -> (int)(Math.random()*100));
list.forEach(System.out::println);
}
函数型接口示例(入参出参都有):
//转换字符串为Integer
public static Integer convert(String str, Function<String, Integer> function) {
return function.apply(str);
}
public static void main(String[] args) {
Integer value = convert("28", x -> Integer.parseInt(x));
}
断言型接口示例(有入参,出参为boolean类型):
//筛选出只有两个字的水果
public static List<String> filter(List<String> fruit, Predicate<String> predicate){
List<String> f = new ArrayList<>();
for (String s : fruit) {
if(predicate.test(s)){
f.add(s);
}
}
return f;
}
public static void main(String[] args) {
List<String> fruit = Arrays.asList("香蕉", "哈密瓜", "榴莲", "火龙果", "水蜜桃");
List<String> newFruit = filter(fruit, (f) -> f.length() == 2);
System.out.println(newFruit);
}
stream流
用于快速处理集合的数据(一般用于查找过滤)
创建流
我们常用的创建流的方式有两种,一是集合创建流(最常用),二是数组创建流,也有其它方式创建流,但是一般不用。
//1. 通过集合创建stream(推荐)
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2. 通过Arrays中的静态方法
Integer[] intArray = new Integer[10];
Stream<Integer> stream2 = Arrays.stream(intArray);
处理过程
- 获取流。
- 中间操作。
- 终止操作。
常见的流处理函数
/**
* Stream的中间操作:
* filter:排除元素
* distinct:去重
* limit:给定数量
* skip:跳过几个数量
* map:实现函数
* flatMap:扁平化
* sorted:排序
* Stream的终止操作:
* allMatch,anyMatch,noneMatch:是否匹配元素
* findFirst,findAny:返回元素
* count,max,min:计数,最大,最小
* forEach:迭代
* reduce:归约
*/
并行流
java7中的Fork/Join框架,会将一个大任务拆分成多个小任务,并行的去执行,然后将各个小任务执行的结果进行合并,最终返回结果。缺点是代码太难写,每实现一次要写好多定制化的代码。
java8中提供了并行流的方式,底层用的就是Fork/Join框架,但只需要一句代码:
list.parallelStream()
与java7相比,人性化了很多。
总结
- stream流函数中需要传入的参数都是java8内置的lambda接口,因此,推荐在函数中直接写lambda。
- stream形式适用于集合数据快速的查找过滤等操作,当需要对集合中的数据进行很多的业务逻辑处理的时候,建议使用增强for循环。主要原因是lamdba写法不适合写的过长,处理过多业务逻辑,不利于后期维护。
练习
List<Transaction> transactions = null;
@Before
public void before(){
//交易员
Trader raoul = new Trader("Raoul", "Cambridge");
Trader mario = new Trader("Mario", "Milan");
Trader alan = new Trader("Alan", "Cambridge");
Trader brian = new Trader("Brian", "Cambridge");
//交易
transactions = Arrays.asList(
new Transaction(brian, 2011, 300),
new Transaction(raoul, 2011, 1000),
new Transaction(raoul, 2011, 400),
new Transaction(mario, 2012, 710),
new Transaction(mario, 2012, 700),
new Transaction(alan, 2012, 950)
);
}
/**
* 1. 找出2011年发生的所有交易, 并按交易额排序(从低到高)
*/
@Test
public void test1() {
transactions.stream()
.filter((t) -> t.getYear() == 2011)
.sorted(Comparator.comparingInt(Transaction::getValue))
.forEach(System.out::println);
}
/**
* 2. 交易员都在哪些不同的城市工作过?
*/
@Test
public void test2() {
transactions.stream()
.map((e) -> e.getTrader().getCity())
.distinct()
.forEach(System.out::println);
}
/**
* 3. 查找所有来自剑桥的交易员,并按姓名排序
*/
@Test
public void test3() {
transactions.stream()
.filter((e) -> e.getTrader().getCity().equals("Cambridge"))
.map((e) -> e.getTrader().getName())
.sorted(Comparator.naturalOrder())
.distinct()
.forEach(System.out::println);
}
/**
* 4. 返回所有交易员的姓名字符串,按字母顺序排序
*/
@Test
public void test4() {
transactions.stream()
.map((e) -> e.getTrader().getName())
.sorted(Comparator.naturalOrder())
.forEach(System.out::println);
}
/**
* 5. 有没有交易员是在米兰工作的
*/
@Test
public void test5() {
boolean b = transactions.stream()
.anyMatch((e) -> e.getTrader().getCity().equals("Milan"));
System.out.println(b);
}
/**
* 6. 打印生活在剑桥的交易员的所有交易额之和
*/
@Test
public void test6() {
Optional<Integer> optional = transactions.stream()
.filter((e) -> e.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.reduce(Integer::sum);
System.out.println(optional.get());
}
/**
* 7. 所有交易中,最高的交易额是多少
*/
@Test
public void test7() {
Optional<Integer> optional = transactions.stream()
.map(Transaction::getValue)
.max(Integer::compareTo);
System.out.println(optional.get());
}
/**
* 8. 找到交易额最小的交易
*/
@Test
public void test8() {
Optional<Transaction> optional = transactions.stream()
.min(Comparator.comparingInt(Transaction::getValue));
System.out.println(optional.get());
}
时间API
简介
- java8对时间的api做了整理,主要为下面这三个类:LocalDate, LocalTime, LocalDateTime。从类名就可以看出,一个是日期,一个是时间,一个是全有。
- 我们平时使用的时候,尽量使用LocalDateTime。
- 在java8之前,我们使用的时间戳日期转换工具SimpleDateFormat是线程不安全的,在使用的时候没法抽成一个静态工具类,需要在每一个线程下重新new一个SimpleDateFormat。java8中提供的DateTimeFormatter则是线程安全的。
开发中常用例子
1--获取当前时间戳
@Test
public void test1() {
//包含了日期和时间,可以转成秒,毫秒
Instant timestamp = Instant.now();
System.out.println(timestamp);
//毫秒
long milli = timestamp.toEpochMilli();
System.out.println(milli);
long second = timestamp.getEpochSecond();
System.out.println(second);
}
2--时间戳与需要的日期格式相互转换
/**
* 2.1 时间戳转成想要的日期格式
*/
@Test
public void test2() {
String pattern = "yyyy-MM-dd HH:mm:ss";
long time = Instant.now().toEpochMilli();
//时间戳转成日期
//1. 时间戳转成标准日期
LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault());
System.out.println(localDateTime);
//2. 标准日期转成我们需要的格式
DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
String format = df.format(localDateTime);
System.out.println(format);
}
/**
* 2.2 给定任意日期格式转成时间戳
*/
@Test
public void test3() {
String pattern = "yyyy-MM-dd HH:mm:ss";
//1. 将日期格式转成标准日期
DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
LocalDateTime localDateTime = LocalDateTime.parse("2018-12-17 10:00:00", df);
System.out.println(localDateTime);
//2. 转换成时间戳
long milli = localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
System.out.println(milli);
}
3--时间日期差计算
/**
* 3.1 计算时间差
*/
@Test
public void test4() throws InterruptedException {
Instant ins1 = Instant.now();
System.out.println(ins1.toEpochMilli());
Thread.sleep(1000);
Instant ins2 = Instant.now();
System.out.println(ins2.toEpochMilli());
long milli = Duration.between(ins1, ins2).toMillis();
System.out.println(milli);
}
/**
* 3.2 计算日期差
*/
@Test
public void test5() {
LocalDate now = LocalDate.now();
System.out.println(now);
LocalDate birth = LocalDate.of(1994, 11,26);
System.out.println(birth);
//相隔日期
Period period = Period.between(birth, now);
System.out.println(period.getYears() + "-" + period.getMonths() + "-" + period.getDays());
//相隔多少天
long dayDiff = ChronoUnit.DAYS.between(birth, now);
System.out.println(dayDiff);
}
4--日期加减
@Test
public void test6() {
LocalDateTime today = LocalDateTime.now();
LocalDateTime tor = today.plusDays(1);
LocalDateTime yes = today.minusDays(1);
System.out.println(yes);
System.out.println(today);
System.out.println(tor);
}
网友评论