网站制作想法,好看的手机网站推荐,宜兴市做网站,做网站内容来源java8根据某个id删选在编程时#xff0c;我们都面临着#xff08;最#xff09; 臭名昭著的NullPointerException 。 而且我相信我们所有人都同意#xff0c;遇到NullPointerException也是一种痛苦。 为了使读者了解最新情况#xff0c;著名的计算机科学家Tony Hoare引入了… java8根据某个id删选 在编程时我们都面临着最 臭名昭著的NullPointerException 。 而且我相信我们所有人都同意遇到NullPointerException也是一种痛苦。 为了使读者了解最新情况著名的计算机科学家Tony Hoare引入了空引用他认为这是一个百万美元的错误 。 众所周知这很容易实现但是也很难预测。 这就是为什么开发人员需要非常谨慎的原因。 平常的方式 让我们考虑以下3个简单的POJO。 public class Employee {private Car car;public Car getCar() {return car;}
}public class Car {private Insurance insurance;public Insurance getInsurance() {return insurance;}
}public class Insurance {private String name;public String getName() {return name;}
} 仅提供背景信息–员工可以拥有汽车虽然不是强制性的汽车可以具有保险不一定并且保险必须始终具有名称。 只要记住了解以下内容即可。 现在我们想通过提供人员实例来获得保险的名称。 public String getInsuranceName(Employee employee) {if (employee ! null) {Car car employee.getCar();if (car ! null) {Insurance insurance car.getInsurance();if (insurance ! null) {return insurance.getName();}}}return UNKNOWN;
} 这是我们通常采取的预防措施以免遇到可怕的NullPointerException异常。 我们还认为这也会污染源代码根据我的观点应将其视为反模式。 另一种惯用的方式 上一节中提到的对null检查的这种深层嵌套看起来有些晦涩。 有时人们会以不同的方式来做。 public String getInsuranceName(Employee employee) {if (employee null) {return UNKNOWN;}Car car employee.getCar();if (car null) {return UNKNOWN;}Insurance insurance car.getInsurance();if (insurance null) {return UNKNOWN;}return insurance.getName();
} 在我看来这还算不错因为它不包含深层嵌套的null检查。 但是它仍然遵循相同的反模式以某种不同的方式检查空值。 为什么NULL不好 这会降低源代码的可读性 呈现没有价值的东西在语义上是不正确的 它与Java的思想背道而驰因为Java会向开发人员隐藏指针除非存在空引用的情况 NULL的替代 很少有语言例如ScalaGroovy消除了对空引用的可怕使用以表示没有值。 可以以非常简洁的方式用Groovy编写类似的代码。 def name employee?.car?.insurance?.name 这在Groovy中被称为“ 安全导航”运算符 它清楚地显示了易读的代码同时消除了遇到可怕的空引用的可能性。 Java的努力 现在我们应该问Java开发人员可以做什么来实现类似的事情从而在保持可读性和可维护性源代码的同时防止NullPointerException的可能性。 Java语言设计人员选择了Groovy或Scala语言已经实现的类似方法但是引入了一个新类-Optional 可选的 public final class OptionalT {public staticT OptionalT empty() {}public static T OptionalT of(T value) {}public static T OptionalT ofNullable(T value) {}public T get() {}public boolean isPresent() {}public void ifPresent(Consumer? super T consumer) {}public OptionalT filter(Predicate? super T predicate) {}publicU OptionalU map(Function? super T, ? extends U mapper) {}publicU OptionalU flatMap(Function? super T, OptionalU mapper) {}public T orElse(T other) {}public T orElseGet(Supplier? extends T other) {}public X extends Throwable T orElseThrow(Supplier? extends X exceptionSupplier) throws X {}
} 此类主要用于表示值的不存在。 如果您认为一个值可以始终存在或不能始终存在则最好使用Optional类型。 在我们之前的示例中员工可能会或可能不会有汽车这就是为什么最好返回Optional Car而不是简单地返回Car 。 让我们看看我们如何设计上一个示例 public class Employee {private Car car;public OptionalCar getCar() {return Optional.ofNullable(car);}
}public class Car {private Insurance insurance;public OptionalInsurance getInsurance() {return Optional.ofNullable(insurance);}
}public class Insurance {private String name;public String getName() {return name;}
} 我没有讨论过静态工厂的Nullable..方法而只是将其视为包装值的包装实用程序方法而不管其引用如何。 只需查看API就可以轻松了解遇到可选类型时需要执行的操作。 对于开发人员而言遇到此类可选类型总是表示缺少值的可能性因此开发人员可以为此采取适当的措施。 可选创作 从类概述中我们可以清楚地看到可以以多种方式创建Optional 。 of.. 这允许创建包装非空值的Optional实例 empty 这将创建一个空的Optional ofNullable.. 这允许创建一个包装任何值空或非空的Optional实例 可选的提取和转换 到目前为止我们已经看到了如何创建Optional实例。 现在我们应该看看如何提取值或将其转换为另一个值。 get返回包含的值如果Optional实例为空则抛出NoSuchElementException 但是我们应该如何使用呢 Car car employee.getCar();
if (employee ! null) {car employee.getCar();
} 这是我们逃避NullPointerException的主要操作。 现在使用Java 8 Optional 我们可以编写如下代码 OptionalCar car employee.getCar();
if (!car.isEmpty()) {Car car car.get();
} 但是您是否认为这是对讨厌的空检查的改进 我曾经认为它是一种改进因为它隐藏了空指针但是后来我觉得它会污染源代码。 但是我不反对使用从方法或包装变量中返回Optional作为类型的方法。 我将在以下各节中讨论其背后的原因。 让我们考虑以前的方法 public String getInsuranceName(Employee employee) {return employee.getCar().getInsurance().getName();
} 这是一个非常干净的代码但是NullPointerException潜伏在后面这就是为什么我们需要合并几个空引用检查我们之前已经看到过的原因。 如果我们在设计一个好的API时合并了公共String Optional 则可以通过更简洁的方式实现 public String getInsuranceName(OptionalEmployee employee) {return employee.flatMap(Employee::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse(UNKNOWN);
} 这是不是真的好又干净的方法 我知道这会使一些对Java Streams API不满意的程序员感到困惑。 我强烈建议对Java 8 Streams有一个快速的了解以了解Optional的优点。 另一个示例是如果人名以“ P”开头则获得保险名称 public String getInsuranceName(OptionalEmployee employee) {return employee.filter(e- e.getName().startsWith(P)).flatMap(Employee::getCar).flatMap(Car::getInsurance).map(Insurance::getName).orElse(UNKNOWN);
}设计实践 现在我想以一些不同的方式分享一些有关设计我们先前讨论的POJO的想法。 API设计实践1 public class Employee {private OptionalCar car;public OptionalCar getCar() {return car;}
}public class Car {private OptionalInsurance insurance;public Insurance getInsurance() {return insurance;}
}public class Insurance {private String name;public String getName() {return name;}
} 在这里我已声明成员变量为Optional类型。 根据我的观点这也是非常用户友好的并且此类的用户或消费者可以轻松理解此类的性质。 在这种情况下员工的汽车是Optional的 也就是说员工可能也可能没有汽车。 API设计实践2 public class Employee {private Car car;public OptionalCar getCar() {return Optional.ofNullable(car);}
}public class Car {private Insurance insurance;public OptionalInsurance getInsurance() {return Optional.ofNullable(insurance);}
}public class Insurance {private String name;public String getName() {return name;}
} 这也是非常直观的但是缺乏清晰显示成员实例不存在的想法。 要了解任何系统开发人员总是需要首先了解对象模型而了解对象模型则需要我们了解领域对象。 在这种情况下员工是拥有汽车的域对象就像它对于员工是强制性的一样。 但实际上员工可能会或可能不会有汽车。 我们可以在获取或检索其值 getCar 时实现它然后当该方法返回Optional时 我们可能会注意到其缺少包含值的可能性。 使用什么 它完全取决于开发人员。 我个人更喜欢第一种方法因为很明显在理解领域模型方面很明显而第二种方法在序列化方面具有优势。 由于Optional不实现Serializable 因此在我们的第一种方法中它不可序列化。 如果我们使用DTO则可以使我们的实现适应第二种方法。 方法或构造函数参数中的可选 正如我之前提到的“ 可选”在班级中清楚地表明了消费者应该做的事情。 因此如果构造函数或方法接受Optional元素作为参数则意味着该参数不是必需的。 另一方面我们需要付出用Optional污染代码库的代价。 开发人员唯一要谨慎使用它。 我个人不希望在方法参数中使用Optional 但如果需要我们仍然可以将其包装在Optional实例中并对其执行必要的操作。 方法返回类型中的可选 Java语言架构师Brian Goetz还建议如果有可能返回null则在方法中返回Optional 。 我们已经在API设计规范2中看到了这一点。 从方法抛出异常或返回可选 多年来Java开发人员遵循通常的方法抛出异常来表示方法调用中的错误情况。 public static InputStream getInputStream(final String path) {checkNotNull(path, Path cannot be null);final URL url fileSystem.getEntry(path);InputStream xmlStream;try {xmlStream url.openStream();return xmlStream;} catch (final IOException ex) {throw new RuntimeException(ex);}
} 如果此方法的使用者遇到RuntimeException 那是由于打开与指定URL的连接时出现问题。 另一方面我们还可以通过以下方式使用Optional public static OptionalInputStream getInputStream(final String path) {checkNotNull(path, Path cannot be null);final URL url fileSystem.getEntry(path);InputStream xmlStream;try {xmlStream url.openStream();return Optional.of(xmlStream);} catch (final IOException ex) {return Optional.empty();}
} 我认为这很直观因为它清楚地表明它返回了一个可能有值也可能没有值的Optional实例。 这就是为什么我倾向于从可能具有这种null遇到可能性的方法中返回Optional的原因。 私有方法中的可选返回类型 私有方法显然不是要理解或分析项目的任何重要部分。 因此我认为我们仍然可以使用null检查来摆脱过多的Optional但是如果您认为仍然可以以更简洁明了的方式使用该方法则也可以返回Optional 。 为了更好地理解我编写了一个示例如下所示 private void process(final String data) {try {final ItemList nList doc.getChildNodes();for (int temp 0; temp nList.getLength(); temp) {final Node nNode nList.item(temp);final String key nNode.getName();final String value nNode.getValue();values.put(getAttribute(key).orElseThrow(IllegalArgumentException::new), value);}} catch (final Exception ex) {logger.error({}, ex.getMessage(), ex);}
}private OptionalAttribute getAttribute(final String key) {return Arrays.stream(Attribute.values()).filter(x - x.value().filter(y - y.equalsIgnoreCase(key)).isPresent()).findFirst();
}public static enum Attribute {A (Sample1),B (Sample2),C (Sample3);private String value;private Attribute(String value) {this.value value;}public OptionalString value() {return Optional.ofNullable(value);}} 我本可以以更常用的方式编写第二种方法 private Attribute getAttribute(final String key) {for (final Attribute attribute : Attribute.values()) {OptionalString value attribute.value();if (value.isPresent() value.get().equalsIgnoreCase(key)) {return attribute;}}throw new IllegalArgumentException();
}私有方法中返回返回Collection或其任何子类型的可选返回类型 作为第一个示例请考虑代码您需要实现一种方法来从Java中的指定路径列出文件 public static ListString listFiles(String file) {ListString files;try {files Files.list(Paths.get(path));} catch (IOException e) {files Arrays.asList(Could not list);}return files;
} 我们可以实现更简洁的代码如下所示 public static ListString listFiles(String path) {return Files.list(Paths.get(path)).filter(Files::isRegularFile).collect(toList());
} 注意简洁方法中的返回类型仍为List而不是Optional 。 最好遵循返回空列表的通常做法而不是使用Optional 。 使用Optional的流方式更加简洁是非常有专利的。 可选的是实用程序数据容器可帮助开发人员摆脱空引用。 此外它确实提供了许多有用的方法来简化程序员的任务。 但是如果开发人员不太了解Optional的主要用法则Optional可能会被严重滥用并可能污染代码库。 这就是为什么我强烈建议大家在Optional中使用面向流的方法以帮助开发人员编写简洁且可维护的代码 翻译自: https://www.javacodegeeks.com/2017/07/java-8-optionals.htmljava8根据某个id删选