public class MyParser implements Parser {private static Action DO_NOTHING = new Action() {public void doSomething() { /* do nothing */ }};
public Action findAction(String userInput) {// ...if ( /* we can't find any actions */ ) {return DO_NOTHING;}}}
比较:
Parser parser = ParserFactory.getParser();if (parser == null) {// now what?// this would be an example of where null isn't (or shouldn't be) a valid response}Action action = parser.findAction(someInput);if (action == null) {// do nothing} else {action.doSomething();}
public Action findAction(final String userInput) {/* Code to return requested Action if found */return new Action() {public void doSomething() {userConsole.err("Action not found: " + userInput);}}}
public Photo getPhotoOfThePerson(Person person) {if (person == null)return null;// Grabbing some resources or intensive calculation// using person object anyhow.}
This is rather theoretical case and in most cases you should prefer java null safe API (in case it will be released in another 10 years), but NullPointerException is subclass of an Exception. Thus it is a form of Throwable that indicates conditions that a reasonable application might want to catch (javadoc)! To use the first most advantage of exceptions and separate error-handling code from 'regular' code (according to creators of Java) it is appropriate, as for me, to catch NullPointerException.
public void updatePersonPhoneNumber(Long personId, String phoneNumber) {if (personId == null)return;DataSource dataSource = appContext.getStuffDataSource();Person person = dataSource.getPersonById(personId);if (person != null) {person.setPhoneNumber(phoneNumber);dataSource.updatePerson(person);} else {Person = new Person(personId);person.setPhoneNumber(phoneNumber);dataSource.insertPerson(person);}}
和
public void updatePersonPhoneNumber(Long personId, String phoneNumber) {if (personId == null)return;DataSource dataSource = appContext.getStuffDataSource();Person person = dataSource.getPersonById(personId);if (person == null)throw new SomeReasonableUserException("What are you thinking about ???");person.setPhoneNumber(phoneNumber);dataSource.updatePerson(person);}
class C {private final MyType mustBeSet;public C(MyType mything) {mustBeSet=Contract.notNull(mything);}private String name = "<unknown>";public void setName(String s) {name = Contract.notNull(s);}}
class Contract {public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }}
干净的代码。想要推理一段代码的行为,最重要的一点是它的编写方式要易于理解。根据变量所代表的内容命名变量,根据方法命名方法,应用Single responsibility principle(2中的S:http://en.wikipedia.org/wiki/SOLID_(对象-oriented_design)对于凌乱的代码,试图理解一个方法做了什么可能会让你忘记你为什么要阅读这个方法。(提示:阅读Robert C. Martin的“干净的代码”)
验证您的输入!确定您的应用程序的“入口点”。它们可以是Web服务、REST服务、远程EJB类、控制器等。对于这些入口点中的每个方法,问问自己:“如果此参数为空,此方法是否会正确执行?”如果答案是否定的,请添加Validate.notNull(someParam, "Can't function when someParam is null!");。如果缺少所需参数,这将抛出IllegalArgumentException。在入口点中进行这种类型的验证的好处是,您可以轻松地在从入口点执行的代码中假设此变量永远不会为空!此外,如果这失败了,在入口点,调试比你在代码深处得到NullPointerException要容易得多,因为这样的失败只能意味着一件事:客户端没有向你发送所有必需的信息。在大多数情况下,你想验证所有输入参数,如果你发现自己处于需要允许大量null值的位置,这可能是设计糟糕的接口的迹象,需要重构/添加来满足客户端的需求。
public class Car {
@NotNullprivate String manufacturer;
@NotNull@Size(min = 2, max = 14)private String licensePlate;
@Min(2)private int seatCount;
// ...}
if(someObject!=null){ // simply checking against null}
办法3:
@isNull @Nullable // using annotation based validation
办法4:
// by writing static method and calling it across whereever we needed to check the validation
static <T> T isNull(someObject e){if(e == null){throw new NullPointerException();}return e;}
import java.util.Optional;public class HomeServices {private static final int NOW = 0;private static Optional<HomeServices> service;
public static Optional<HomeServices> get() {service = Optional.of(service.orElse(new HomeServices()));return service;}
public Optional<Service> getRefrigertorControl() {Service s = new RefrigeratorService();//...return Optional.ofNullable(s);}
public static void main(String[] args) {/* Get Home Services handle */Optional<HomeServices> homeServices = HomeServices.get();if(homeServices != null) {Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();refrigertorControl.ifPresent(HomeServices::switchItOn);}}
public static void switchItOn(Service s){//...}}
void example() {Entry entry = new Entry();// This is the same as H-MANs solutionPerson person = getNullsafe(entry, e -> e.getPerson());// Get object in several stepsString givenName = getNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.getGivenName());// Call void methodsdoNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.nameIt());}
/** Return result of call to f1 with o1 if it is non-null, otherwise return null. */public static <R, T1> R getNullsafe(T1 o1, Function<T1, R> f1) {if (o1 != null) return f1.apply(o1);return null;}
public static <R, T0, T1> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, R> f2) {return getNullsafe(getNullsafe(o0, f1), f2);}
public static <R, T0, T1, T2> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Function<T2, R> f3) {return getNullsafe(getNullsafe(o0, f1, f2), f3);}
/** Call consumer f1 with o1 if it is non-null, otherwise do nothing. */public static <T1> void doNullsafe(T1 o1, Consumer<T1> f1) {if (o1 != null) f1.accept(o1);}
public static <T0, T1> void doNullsafe(T0 o0, Function<T0, T1> f1, Consumer<T1> f2) {doNullsafe(getNullsafe(o0, f1), f2);}
public static <T0, T1, T2> void doNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Consumer<T2> f3) {doNullsafe(getNullsafe(o0, f1, f2), f3);}
class Entry {Person getPerson() { return null; }}
class Person {Name getName() { return null; }}
class Name {void nameIt() {}String getGivenName() { return null; }}
// Avoida.getMap().put(key,value)
//recommended
public void addElement(Object key, Object value){// Have null checks for both key and value here : single placemap.put(key,value);}
And finally, use try{} catch{} finally{} blocks at right places effectively.
class SomeService {@Injectprivate CompanyDao companyDao;
// return Optional<String>public Optional<String> selectCeoCityByCompanyId0(int companyId) {return companyDao.selectById(companyId).map(Company::getCeo).flatMap(Person::getHomeAddress).flatMap(Address::getCity);}
// return String + default valuepublic String selectCeoCityByCompanyId1(int companyId) {return companyDao.selectById(companyId).map(Company::getCeo).flatMap(Person::getHomeAddress).flatMap(Address::getCity).orElse("UNKNOWN");}
// return String + exceptionpublic String selectCeoCityByCompanyId2(int companyId) throws NoSuchElementException {return companyDao.selectById(companyId).map(Company::getCeo).flatMap(Person::getHomeAddress).flatMap(Address::getCity).orElseThrow(NoSuchElementException::new);}}
interface CompanyDao {// real situation: no company for such id -> use Optional<Company>Optional<Company> selectById(int id);}
class Company {// company always has ceo -> use PersonPerson ceo;public Person getCeo() {return ceo;}}
class Person {// person always has name -> use StringString firstName;// person can be without address -> use Optional<Address>Optional<Address> homeAddress = Optional.empty();
public String getFirstName() {return firstName;}public Optional<Address> getHomeAddress() {return homeAddress;}}
class Address {// address always contains country -> use StringString country;// city field is optional -> use Optional<String>Optional<String> city = Optional.empty();
String getCountry() {return country;}Optional<String> getCity() {return city;}}
/*** Returns an {@code Optional} describing the specified value, if non-null,* otherwise returns an empty {@code Optional}.** @param <T> the class of the value* @param value the possibly-null value to describe* @return an {@code Optional} with a present value if the specified value* is non-null, otherwise an empty {@code Optional}*/public static <T> Optional<T> ofNullable(T value) {return value == null ? empty() : of(value);}
/*** Return {@code true} if there is a value present, otherwise {@code false}.** @return {@code true} if there is a value present, otherwise {@code false}*/public boolean isPresent() {return value != null;}
/*** If a value is present, invoke the specified consumer with the value,* otherwise do nothing.** @param consumer block to be executed if a value is present* @throws NullPointerException if value is present and {@code consumer} is* null*/public void ifPresent(Consumer<? super T> consumer) {if (value != null)consumer.accept(value);}
public class Null {
public static void main(String[] args) {String str1 = null;String str2 = "";
if(isNullOrEmpty(str1))System.out.println("First string is null or empty.");elseSystem.out.println("First string is not null or empty.");
if(isNullOrEmpty(str2))System.out.println("Second string is null or empty.");elseSystem.out.println("Second string is not null or empty.");}
public static boolean isNullOrEmpty(String str) {if(str != null && !str.isEmpty())return false;return true;}}
import lombok.NonNull;
public class NonNullExample extends Something {private String name;
public NonNullExample(@NonNull Person person) {super("Hello");this.name = person.getName();}}