Appearance
Java8特性
函数式编程
这是一种编程的范式。和命令式编程对应。 可以减少代码量。尽量多的使用函数和表达式。
函数式接口
java
/**
* 函数式接口
* default方法 java8出现的新接口方法,这种方式可以让方法实现多继承
* 提高程序的兼容性,默认方法是在原来的基础上进行扩展的
*/
@FunctionalInterface
public interface MyInterface {
void m1();
default void print(Object o){
System.out.println(o);
}
}
使用函数式接口可以在接口中增加使用default修饰的非抽象方法,利用这种方法可以实现多继承类似的功能。 测试上面的接口可以正常使用。
java
/* 测试代码 */
/**
* default方法测试
*/
public class FunctionTest implements MyInterface{
public static void main(String[] args) {
FunctionTest functionTest = new FunctionTest();
functionTest.print("dsada");
}
@Override
public void m1() {
System.out.println("s");
}
}
函数式接口只能包含一个抽象方法,多于一个就会报错。 实例化这些接口可以使用lambda表达式。
lambda表达式
函数式接口,的出现一个目的就是为了适应lambda表达式。 lambda可以看作是一个匿名函数。 ()->{}
可以十分精简的写代码,下面是例子。
java
/**
* lambda表达式,例子
*/
public class LambdaTest01 {
public static void main(String[] args) {
MyInterface myInterface = () -> System.out.println("1");
myInterface.m1();
/*使用lambda创建匿名内部类*/
/*看上去十分的简洁*/
MyInterface myInterface1 = () -> System.out.println("2");
myInterface1.m1();
MyInterface2 myInterface2 = Integer::sum;
System.out.println(myInterface2.m2(1,2));
}
}
使用lambda创建线程的例子
java
/**
* lambda表达式创建线程
*/
public class LambdaTest02 {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
System.out.println("1");
}
}.start();
/*使用Lambda创建线程*/
new Thread(() -> System.out.println("2")).start();
}
}
forEach遍历
java
import edu.princeton.cs.introcs.StdOut;
import java.util.Arrays;
import java.util.List;
/**
* 使用Foreach方法和lambda遍历集合
*/
public class ForEachTest {
public static void main(String[] args) {
Integer[] integers = new Integer[]{31, 32, 3, 312, 44, 35};
List<Integer> list = Arrays.asList(integers);
list.forEach((i) -> StdOut.print(i+" "));
System.out.println();
}
}
当lambda只有一个参数的时候可以省略小括号 如(i)->func(i)
等价于i->func(i)
。
方法引用
lambda只有一句的时候可以使用方法引用。方法引用的例子。
java
import java.util.Arrays;
/**
* 方法引用
*/
public class LambdaTest04 {
public static void main(String[] args) {
Integer[] integers = new Integer[]{31, 32, 3, 312, 44, 35};
/*Arrays.sort(integers, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
});*/
/*使用方法引用*/
Arrays.sort(integers, Integer::compare);
Arrays.stream(integers).forEach(System.out::println);
}
}
Stream API
下面的代码演示了流的使用
java
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Collection可以使用Stream进行操作
* Stream本身支持函数式编程
*/
public class StreamTest01 {
public static void main(String[] args) {
List<Student> studentList = getStudents();
testMethod1(studentList);
testMethod2(studentList);
}
private static void testMethod1(List<Student> studentList) {
/*实现找到成年人,并按照年龄降序排序*/
/*实现1*/
List<Student> resList = new ArrayList<>(6);
for (Student student : studentList) {
/*筛选出成年人*/
if (student.getAge() >= 18) {
resList.add(student);
}
}
resList.sort(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getAge() - o1.getAge();
}
});
System.out.println(resList);
/*实现2 使用Stream实现*/
/**
* 1.使用Stream API
* 2.过滤
* 3.排序
* 4.使用collect将Stream转换成List
*/
/*Stream内部实现了内部迭代,jdk8中的迭代速度比传统迭代慢*/
List<Student> arrayList = studentList.stream()
.filter((student -> student.getAge() >= 18))
//.sorted(((o1, o2) -> Integer.compare(o2.getAge(), o1.getAge())))
.sorted(Comparator.comparing(Student::getAge).reversed())
.collect(Collectors.toList());
System.out.println(arrayList);
/*Stream流是一次性的,是不能重复的*/
}
private static void testMethod2(List<Student> studentList){
/*流只能使用一次*/
Stream<Student> stream = studentList.stream();
stream.forEach(System.out::println);
/*此时流已经被关闭,无法被操作*/
stream.forEach(System.out::println);
}
private static List<Student> getStudents() {
List<Student> studentList = new ArrayList<Student>();
studentList.add(new Student("小明", 10));
studentList.add(new Student("小网", 18));
studentList.add(new Student("小的", 51));
studentList.add(new Student("小主", 34));
studentList.add(new Student("小哈哈", 61));
studentList.add(new Student("小大明", 12));
return studentList;
}
}
使用流API操作集合能减少遍历代码,代码写起来和看起来都会比较好。
map-reduce 计算数据
map-reduce可以比较优雅的操作数据计算,这个思想最初来源于谷歌,用于数据分析。
java
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* map-reduce 是谷歌提出的应用于大数据分析的方法
* map是数据映射 某一组数据
* reduce是数据计算 某一个值
*/
public class MapReduce {
public static void main(String[] args) {
List<Student> studentList = getStudents();
/*使用map获取学生的数学成绩*/
List<Double> mathMarks = studentList
.stream()
.map(Student::getMathMark)
.collect(Collectors.toList());
System.out.println(mathMarks);
/*使用map获取学生姓名的长度*/
List<Integer> nameLength = studentList.stream()
.map(Student::getName)
.map(String::length)
.collect(Collectors.toList());
System.out.println(nameLength);
/*将每个学生分数减少10*/
List<Double> math_10 = studentList.stream().map(Student::getMathMark)
.map(i -> i - 10)
.collect(Collectors.toList());
System.out.println(math_10);
/*Reduce方法*/
/*计算学生的数学总分*/
/*相当于 0 + sum([分数])*/
Double mathMarkSum = studentList.stream().map(Student::getMathMark)
.reduce((double) 0, Double::sum);
System.out.println(mathMarkSum);
/*Optional对象可以比较方便的判断类型是不是空,并且可以指定为空的时候的解决方案*/
Double mathMarkSum1 = studentList.stream().map(Student::getMathMark)
.reduce(Double::sum).orElse((double) 0);
System.out.println(mathMarkSum1);
/*计算最高分*/
double max = studentList.stream().map(Student::getMathMark).reduce(Double::max).orElse((double) 0);
System.out.println(max);
}
private static List<Student> getStudents() {
List<Student> studentList = new ArrayList<Student>();
studentList.add(new Student("小明", 121, 23, 45));
studentList.add(new Student("小网", 2, 4, 6));
studentList.add(new Student("小的", 3, 55, 66));
studentList.add(new Student("小主", 23, 56, 8));
studentList.add(new Student("小哈哈", 41, 24, 5));
studentList.add(new Student("小大明", 5, 6, 7));
return studentList;
}
}
数字流
数字流提供了可以方便操作数字的的API可以很简单的计算数据。
java
import java.util.List;
import java.util.stream.IntStream;
/**
* IntStream DoubleStream LongStream
* 数字流
*/
public class IntStreamTest {
public static void main(String[] args) {
List<Student> studentList = MapReduce.getStudents();
/*计算数学的总分和平均分*/
double sum = studentList.stream().mapToDouble(Student::getMathMark).sum();
/*计算平均分*/
double avg = studentList.stream().mapToDouble(Student::getMathMark).average().orElse(0);
System.out.println(sum);
System.out.println(avg);
/*生成数字流*/
/*不包含100*/
IntStream intStream = IntStream.range(0, 100);
/*包含100*/
IntStream intStream1 = IntStream.rangeClosed(0, 100);
/*计算1-100之间的偶数的个数*/
System.out.println(IntStream.rangeClosed(1, 100).filter(n -> n % 2 == 0).count());
}
}
自己创建流
这里有简单的代码示例
java
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* 自己创建一个流
*/
public class StreamTest {
public static void main(String[] args) {
String[] str = {"sd", "asd", "sdad"};
/*创建Stream.of方法*/
Stream.of(str).map(String::toUpperCase).forEach(System.out::println);
int[] arr = {1, 4, 5, 5};
//使用Arrays.stream
IntStream intStream = Arrays.stream(arr);
System.out.println(intStream.sum());
//使用函数创建流,无限流,limit可以只回去前n条数据
Stream.iterate(0, n -> n + 2)
.limit(50) /*获取前N条数据*/
.forEach(System.out::println);
}
}
Optional类
- 解决空指针
- 可以编写更精简的代码
示例代码
java
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* Optional可以帮助做数据判断输出解决空指针异常
*/
public class OptionalTest {
public static void main(String[] args) {
List<Student> studentList = MapReduce.getStudents();
/*计算分数在60下面的分数总和*/
Optional<Double> optional = studentList.stream().map(Student::getMathMark)
.filter(s -> s > 100) /*这里可能会导致解决为空,没有成绩大于100的情况下*/
.reduce(Double::sum);
/*在为空的时候使用0作为默认值*/
System.out.println(optional.orElse((double) 0));
/*取值的时候需要判断*/
Map<Integer,String> stringMap = new HashMap<>();
stringMap.put(1,"122");
/*可以为空的数据*/
System.out.println(Optional.ofNullable(stringMap.get(1)).orElse("kong"));
/*不可以为空的数据*/
System.out.println(Optional.of(stringMap.get(0)).orElse("kong"));
}
}
新增的日期类
LocalDate类可以操作日期
java
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
/**
* LocalDate: 只能处理日期相关的数据,没有时间
* Java8的日期处理类
*/
public class LocalDateTest {
public static void main(String[] args) {
LocalDate localDate = LocalDate.now();
System.out.println(localDate);
/*获取年*/
System.out.println(localDate.getYear());
/*获取月*/
System.out.println(localDate.getMonthValue());
/*获取天*/
System.out.println(localDate.getDayOfMonth());
/*日期格式化*/
System.out.println(localDate.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
/*判断闰年*/
System.out.println(localDate.isLeapYear());
/*判断当天月的天数*/
System.out.println(localDate.lengthOfMonth());
/*自己定义的日期*/
/*方式1*/
LocalDate date = LocalDate.parse("2018-12-03");
/*方式2*/
LocalDate date2 = LocalDate.of(2017,8,15);
/*判断日期是否相等*/
System.out.println(date.equals(date2));
/*日期偏移计算,如当前日期向后偏移一周*/
System.out.println(localDate.plus(1, ChronoUnit.WEEKS));
System.out.println(localDate.plus(-1, ChronoUnit.WEEKS));
}
}
新增的时间操作类
新增的LocalTime可以帮助更简单的操作时间。
java
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
/**
* localTime只能处理时间
*/
public class LocalTimeTest {
public static void main(String[] args) {
/*获取当前时间,不包含毫秒*/
LocalTime localTime = LocalTime.now();
System.out.println(localTime);
/*去除毫秒*/
System.out.println(localTime.withNano(0));
/*时间的偏移计算*/
/*下面的计算时间偏移一小时*/
localTime.plus(1, ChronoUnit.HOURS);
}
}
日期时间操作类
可以同时处理日期和时间的 LocalDateTime类
java
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* 同时处理日期和时间
*/
public class LocalDateTimeTest {
public static void main(String[] args) {
/*获取当前的日期和时间*/
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
System.out.println(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
/*创建日期和时间类*/
LocalDateTime localDateTime1 = LocalDateTime.of(2017,1,10,10,1);
System.out.println(localDateTime1);
}
}
日期和时间的差异计算类
Duration 类 Period类
java
/**
* Duration 时间
* Period 日期
*/
public class DurtionPeriodTest {
public static void main(String[] args) {
LocalDate date1 = LocalDate.parse("2017-10-20");
LocalDate date2 = LocalDate.parse("2017-09-01");
Period period = Period.between(date2,date1);
/*分别计算日期在月份日和年上面的差别*/
System.out.println(period.getMonths());
System.out.println(period.getDays());
System.out.println(period.getYears());
LocalTime localTime1 = LocalTime.parse("10:20:11");
LocalTime localTime2 = LocalTime.parse("10:20:12");
Duration duration = Duration.between(localTime1,localTime2);
/*用来计算时间差*/
System.out.println(duration.getNano());
System.out.println(duration.getSeconds());
}
}