I saw a lot of SO posts saying that Java set any uninitialized variable to null (like here, here or here...).
But lately, I went upon this code, written by Google here :
cur = cr.query(builder.build(), INSTANCE_PROJECTION, selection, selectionArgs, null);
while (cur.moveToNext()) {
String title = null;
long eventID = 0;
long beginVal = 0;
// Get the field values
eventID = cur.getLong(PROJECTION_ID_INDEX);
beginVal = cur.getLong(PROJECTION_BEGIN_INDEX);
title = cur.getString(PROJECTION_TITLE_INDEX);
// Do something with the values.
...
}
I would genuinely rather do this :
// Get the field values
long eventID = cur.getLong(PROJECTION_ID_INDEX);
long beginVal = cur.getLong(PROJECTION_BEGIN_INDEX);
String title = cur.getString(PROJECTION_TITLE_INDEX);
I assume Google developpers are somehow really qualified, so I wonder, since we are in the very same scope : what are the pros and cons of declaring the first way instead of the second ?
It's a question of style. I don't initialise unnecessarily for two reasons:
Doing so clobbers an extra check a Java compiler will give you as compilation will not be successful if a variable that is not initialised on all control paths is encountered.
It gives the impression that null is an acceptable value for the reference, which often it isn't.
Related
I have to analyze a huge data stream which often includes incomplete data. Currently the code is littered with null checks at multiple levels, as there could be incomplete data at any level.
So for example I might have to retrieve:
Model.getDestination().getDevice().getName()
I tried to create a method to try and reduce the null checks to a single method whereby I enter:
IsValid(Model.getDestination(), Model.getDestination().getDevice(), Model.getDestination().getDevice().getName())
this method fails because it evaluates all parameters before it sends them, rather than checking each at a time like
Model.getDestination() != null && Model.getDestination().getDevice() != null && etc
but is there a way I could pass in Model.getDestination().getDevice().getName() and do the check at each level without having to evaluate it or split it up before I pass it?
What I really want it to do is if there is a null/nullexception it should quietly return "", and continue processing incoming data
I know there are ways to do this elegantly in Java 8, but I am stuck with Java 7
I struggled with a similar problem with deeply nested structures, and if I'd have had the opportunity to introduce additional structures just to navigate the underlying data, I think, I had done that.
This was C# which in the meantime has a save navigation/Elvis operator, for which we'll wait in vain with Java (proposed for Java 7 but discarded. Groovy has it btw.). Also looks like there are arguments against using Elvis, even if you have it). Also lambdas (and extension methods) didn't improve things really. Also every other approach has been discredited as ugly in other posts here.
Therefore I propose a secondary structure purely for navigation, each element with a getValue() method to access the original structure (also the shortcuts proposed by #Michael are straight forward to add this way). Allowing you null save navigation like this:
Model model = new Model(new Destination(null));
Destination destination = model.getDestination().getValue(); // destination is not null
Device device = model.getDestination().getDevice().getValue(); // device will be null, no NPE
String name = destination.getDevice().getName().getValue(); // name will be null, no NPE
NavDevice navDevice = model.getDestination().getDevice(); // returns an ever non-null NavDevice, not a Device
String name = navDevice.getValue().getName(); // cause an NPE by circumventing the navigation structure
With straight forward original structures
class Destination {
private final Device device;
public Destination(Device device) {
this.device = device;
}
public Device getDevice() {
return device;
}
}
class Device {
private final String name;
private Device(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
And secondary structures for the purpose of save navigation.
Obviously this is debatable, since you always can access the original structure directly and run into a NPE. But in terms of readability perhaps I'd still take this, especially for large structures where a shrub of ifs or optionals really is an eyesore (which matters, if you have to tell, which business rules actually were implemented here).
A memory/speed argument could be countered by using only one navigation object per type and re-set their internals to approriate underlying objects as you navigate.
class Model {
private final Destination destination;
private Model(Destination destination) {
this.destination = destination;
}
public NavDestination getDestination() {
return new NavDestination(destination);
}
}
class NavDestination {
private final Destination value;
private NavDestination(Destination value) {
this.value = value;
}
public Destination getValue() {
return value;
}
public NavDevice getDevice() {
return new NavDevice(value == null ? null : value.getDevice());
}
}
class NavDevice {
private final Device value;
private NavDevice(Device value) {
this.value = value;
}
public Device getValue() {
return value;
}
public NavName getName() {
return new NavName(value == null ? null : value.getName());
}
}
class NavName {
private final String value;
private NavName(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
Option 1 - if statement
You already provided it in your question. I think using am if statementlike the following is perfectly acceptable:
Model.getDestination() != null && Model.getDestination().getDevice() != null && etc
Option 2 - javax Validation and checking the result - before sending
You could make use of javax validation.
See: https://www.baeldung.com/javax-validation
You would annotate the fields that you want with #NotNull.
Then you could use programmatic validation.
You could check the validation result to see if there is a problem.
Example:
So in your class you would do:
#NotNull
Public String Destination;
And you could feed your object to the validater:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Set<ConstraintViolation<Model>> violations = validator.validate(Model);
for (ConstraintViolation<User> violation : violations) {
log.error(violation.getMessage());
}
Option 3 - fromNullable and Maps ( if you have Java 8)
I'm taking this one from https://softwareengineering.stackexchange.com/questions/255503/null-checking-whilst-navigating-object-hierarchies . This is very simular to your question.
import java.util.Optional;
Optional.fromNullable(model)
.map(Model::getDestination)
.map(Lounge::getDevice)
.ifPresent(letter -> .... do what you want ...);
Option 4 - Just using a try/catch
Everyone hates this one due to the slowness of exception.
So you want to simplify Model.getDestination().getDevice().getName(). First, I want to list a few things that should not be done: Don't use exceptions. Don't write an IsValid method, because it just doesn't work, because all functions (or methods) are strict in Java: that means that every time you call a function, all arguments are evaluated before they are passed to the function.
In Swift I would just write let name = Model.getDestination()?.getDevice()?.getName() ?? "". In Haskell it would be like name <- (destination >>= getDevice >>= getName) <|> Just "" (assuming the Maybe monad). And this has different semantics from this Java code:
if(Model.getDestination() && Model.getDestination().getDevice() && Model.getDestination().getDevice().getName() {
String name = Model.getDestination().getDevice().getName();
System.out.println("We got a name: "+name);
}
because this snippet calls getDestination() 4 times, getDevice() 3 times, getName() 2 times. This has more than just performance implications: 1) It introduces race conditions. 2) If any of the methods have side-effects, you don't want them to be called multiple times. 3) It makes everything harder to debug.
The only correct way of doing it is something like this:
Destination dest = Model.getDestination();
Device device = null;
String name = null;
if(dest != null) {
device = dest.getDevice();
if(device != null) {
name = device.getName();
}
}
if(name == null) {
name = "";
}
This code sets name to Model.getDestination().getDevice().getName(), or if any of these method calls return null, it sets name to "". I think correctness is more important than readability, especially for production applications (and even for example code IMHO). The above Swift or Haskell code is equivalent to that Java code.
If you have a production app, I guess that something like that is what you are already doing, because everything that is fundamentally different than that is error-prone.
Every better solution has to provide the same semantics and it MUST not call any of the methods (getDestination, getDevice, getName) more than once.
That said, I don't think you can simplify the code much with Java 7.
What you can do of course, is shorten the call chains: E.g. you could create a method getDeviceName() on Destination, if you need this functionality often. If this makes the code more readable depends on the concrete situation.
Forcing you to code on this low level also has advantages: you can do common subexpression elimination, and you'll see the advantages of it, because it will make the code shorter. E.g. if you have:
String name1 = Model.getDevice().getConnection().getContext().getName();
String name2 = Model.getDevice().getConnection().getContext().getLabel();
you can simplify them to
Context ctx = Model.getDevice().getConnection().getContext();
String name1 = ctx.getName();
String name2 = ctx.getLabel();
The second snippet has 3 lines, while the first snippet has only two lines. But if you unroll the two snippets to include null-checks, you will see that the second version is in fact much shorter. (I'm not doing it now because I'm lazy.)
Therefore (regarding Optional-chaining), Java 7 will make the code of the performance-aware coder look better, while many more high-level languages create incentives to make slow code. (Of course you can also do common subexpression elimination in higher level languages (and you probably should), but in my experience most developers are more reluctant to do it in high level languages. Whereas in Assembler, everything is optimized, because better performance often means you have to write less code and the code that you write is easier to understand.)
In a perfect word, we would all use languages that have built-in optional chaining, and we would all use it responsibly, without creating performance problems and race conditions.
You can use try-catch. Because there is no processing required in your case, like
try{
if(IsValid(Model.getDestination(), Model.getDestination().getDevice(), Model.getDestination().getDevice().getName())){
}catch(Exception e){
//do nothing
}
Alternatively you can improve your isValid method by passing only Model object
boolean isValid(Model model){
return (model != null && model.getDestination() != null && model.getDestination().getDevice() != null && model.getDestination().getDevice().getName() != null)
}
See String uuids My CODE :
if (uuidExtra != null) {
for (Parcelable p : uuidExtra) {
String uuids = ""+p;
}
}
I'm not programmer. I just learning about it.
Can you underline you question here?
Do you want to know what is the result of your uuids variable?
If so, the result will be the latest data of your uuidExtra. Because in line 3, you make new variable of uuids.
To make it more clear, let me give some example :
You have a List of string. Let's say a,b,c,d,e. Then you access every index of that List using for. Inside that for, you make a new variable called uuids. The problem is, you make new variable everytime doing a loop. So the result is uuids = e.
If you want to have result like this uuids = a,b,c,d,e. You need to modify your code like this.
String uuids;
if (uuidExtra != null) {
for (Parcelable p : uuidExtra) {
uuids = ""+p;
}
}
This is my class reponsible for new item entries, and from the start it has been a complete nightmare, I can't seem to resolve the issues I am facing which are:
setStock(float) in Item cannot be applied to ()
Item entry:
private void writeItemRecord()
{
// Check to see if we can connect to database table
if ( DataBaseHandler.makeConnectionToitemDB() == -1)
{
JOptionPane.showMessageDialog (frame, "Unable to connect to database table (Item)");
}
else // Ok, so first read data from the text fields
{
// Read data from form and store data
String Itemname = ItemnameTxtField.getText();
String Itemcode = ItemcodeTxtField.getText();
String Description = DescriptionTxtField.getText();
String Unitprice = UnitpriceTxtField.getText();
String Style = StyleTxtField.getText();
String Finish = FinishTxtField.getText();
String Stock = StockTxtField.getText();
// Convert priceStr to a float
Float fvar = Float.valueOf(Unitprice);
float price = fvar.floatValue();
Float svar = Float.valueOf(Stock);
float stock = svar.floatValue();
// Create a Item oject
Item Item = new Item();
// Set the attributes for the Item object
Item.setItemname (Itemname);
Item.setItemcode (Itemcode);
Item.setDescription (Description);
Item.setUnitprice (price);
Item.setStock(stock);
Item.setStyle(Style);
Item.setFinish(Finish);
// Write Item record. Method writeToItemTable() returns
// 0 of OK writing record, -1 if there is a problem. I store
// the returned value in a variable called error.
int error = DataBaseHandler.writeToItemTable(Item.getItemname(),
Item.getItemcode(),
Item.getDescription(),
Item.getUnitprice(),
Item.setStock(),
Item.setStyle(Style),
Item.setFinish(Finish),
Item.setSuppliercode(Suppliercode),
Item.setSuppliername(Suppliername),
Item.setAddress(Address)
);
// Check if there is a problem writing the record, in
// which case error will contain -1
if (error == -1)
{
JOptionPane.showMessageDialog (frame, "Problem writing record to Item Table");
}
// Clear the form - actual method is coded below
clearForm();
// Close database connection. Report an error message
// if there is a problem.
if ( DataBaseHandler.closeConnection() == -1 )
{
JOptionPane.showMessageDialog (frame, "Problem closing data base conection");
}
}
} // End
Any help is much appreciated!
And item extracts:
public void setStock(float StockIn)
{
Stock = StockIn;
}
public float getStock()
{
return Stock;
}
For starters, adhere to Java naming conventions. Nothing except class/interface names is allowed to use CamelCase. Use lowerCamelCase. As for your "problem", you wrote
Item.setStock(),
so obviously it's giving you the error. It is also giving you the exact line number of the error, something that would obviously have helped us to diagnose your problem.
Solution: use Item.getStock() (i suppose, it's hard to tell). Calling Item.setStock at that position (as an argument to a method call) is meaningless anyway, given that setStock is a void method.
Java compiler errors come with a line number - pay attention to it. This is your problem:
Item.setStock()
setStock() requires a parameter, you are trying to call it without one. Perhaps you meant getStock()? And I suspect that all the calls to set methods in the parameter list to writeToItemTable are also wrong, as those set methods will have void as return value, so you can't use them that way.
The setStock method looks like this:
public void setStock(float StockIn)
To call it, you need to pass a float as an argument. Somewhere in your code, you call the method, like this:
Item.setStock(),
The method needs to be called with the float argument, but instead it's called with none, hence you see a compilation error.
In this code:
int error = DataBaseHandler.writeToItemTable(Item.getItemname(),
Item.getItemcode(),
Item.getDescription(),
Item.getUnitprice(),
// Right here --> Item.setStock(),
Item.setStyle(Style),
Item.setFinish(Finish),
Item.setSuppliercode(Suppliercode),
Item.setSuppliername(Suppliername),
Item.setAddress(Address)
);
Notice that you're calling Item.setStock(), Item.setStyle(Style), etc. instead of Item.getStock(), Item.getStyle(), etc. This is probably the source of your problem - you're trying to call the setStock() method with no arguments, hence the error.
Hope this helps!
This line
// Create a Item oject
Item Item = new Item();
Is problematic. Not only is it bad style in Java to use uppercase names for variables, this particular instance results in a compile error. Also, you're calling setStock without a parameter. You need to fix that as well.
Here is your error:
int error = DataBaseHandler.writeToItemTable(Item.getItemname(),
Item.getItemcode(),
Item.getDescription(),
Item.getUnitprice(),
Item.setStock(), // <<< here! should be getStock()
Item.setStyle(Style),
Item.setFinish(Finish),
Item.setSuppliercode(Suppliercode),
Item.setSuppliername(Suppliername),
Item.setAddress(Address));
But again... consider naming/coding conventions.
I need to bind at maximum 8 variables. Each one of them could be null.
Is there any recommended way to achieve this? I know that I could simply check for null, but this seems tedious.
Additional details:
I'm going to call this sql from java code. It may be written using JPA 2.0 Criteria API, but most likely it's going to be a native query. The database is Oracle 10g, so I think I could make use of PL/SQL as well.
Edit1:
Maybe the title is a bit misleading, so I'll try to elaborate.
The resulting SQL would be something like:
...
WHERE var1 = :var1
AND var2 = :var2
...
AND var = :var8
Now I need to bind parameters from java code in the way like:
nativeQuery.setParameter("var1", var1)
...
nativeQuery.setParameter("var8", var8)
Some parameters could be null, so there is no need to bind them. But I see no way I can omit them in SQL.
Edit2:
I'm expecting to see SQL or PL/SQL procedure in your answers (if it's ever possible without null checking).
In fact, all of these variables are of the same type. I think it's not possible to find a solution using ANSI SQL, but maybe there are some PL/SQL procedures which allow to work with varargs?
The use of a criteria query is appropriate in this case, because if I understood correctly, you need to construct the SQL query dynamically. If all the variables except var1 are null, the where clause would be
where var1 = :var1
and if all variables except var2 and var5 are non null you would have
where var2 = :var2 and var5 = :var5
Is that right?
If so, then do what you plan to do, and construct the query dynamically using a criteria query. Something like this must be done:
CriteriaBuilder builder = em.getCriteriaBuilder();
Predicate conjunction = builder.conjunction();
if (var1 != null) {
conjunction = builder.and(conjunction,
builder.equal(root.get(MyEntity_.var1),
var1));
}
if (var2 != null) {
conjunction = builder.and(conjunction,
builder.equal(root.get(MyEntity_.var2),
var2));
}
...
criteria.where(conjunction);
You don't specify the type of the objects you want to pass. So in this example I'm considering you will pass Object.
#Test(expected=IllegalArgumentException.class)
public void testMyMethod() {
List<Object> testList = new ArrayList<Object>();
testList.add("1");
testList.add("2");
testList.add(3);
myMethod(testList);
}
public void myMethod(List<Object> limitedList) {
final int MAX_SIZE = 2;
if (limitedList.size() > MAX_SIZE) {
throw new IllegalArgumentException("Size exceeded");
}
//my logic
}
In this example I'm passing the arguments as a List of Objects but you could use array (varargs) or another type of collection if you need to. If the client sends me more than the expected objects it will throw an IllegalArgumentException.
Also if you don't want to throw an exception you could just continue and iterate the list to bind the parameters but using the list size or MAX_SIZE as your limit. For example:
public void myMethod2(List<Object> limitedList) {
final int MAX_SIZE = 2;
int size = MAX_SIZE;
if (limitedList.size() < MAX_SIZE) {
size = limitedList.size();
}
//Iterate through the list
for (int i = 0; i < size; i++) {
Object obj = limitedList.get(i);
//Logic to bind the obj to the criteria.
}
}
I have the following code, which checks for the number of rows in the database.
private void checkMMSRows(){
Cursor curPdu = getContentResolver().query(Uri.parse("content://mms/part"), null, null, null, null);
if (curPdu.moveToNext()){
int number = curPdu.getCount();
System.out.println(number);
}
}
I will to run this code every second and do something when the value has changed. The problems is, how do I go about "detecting" the change? Any help would be appreciated.
Very basically, add a class variable - you can either make it static across all instances of the class, or an instance variable (by removing the static keyword).
Each time you get a number, you can compare it to oldNumber. After the comparison, set the oldNumber to the current number - so you have something to compare against next time:
private static int oldNumber = -1;
private void checkMMSRows(){
Cursor curPdu = getContentResolver().query(Uri.parse("content://mms/part"), null, null, null, null);
if (curPdu.moveToNext()){
int number = curPdu.getCount();
System.out.println(number);
if(number != oldNumber){
System.out.println("Changed");
// add any code here that you want to react to the change
}
oldNumber = number;
}
}
Update:
My answer's a straight code hack & slash solution, but I'd probably recommend amit's answer.
Depends on the context in which this is run.
Assuming that the Object which this method belongs to will live between different checks, all you need to do is to add a int currentValue field to the object, store the value in there first time you check, and then compare the value with the stored ones in subsequent checks (and update if necessary)
int currentValue = 0;
private void checkMMSRows(){
Cursor curPdu = getContentResolver().query(Uri.parse("content://mms/part"), null, null, null, null);
if (curPdu.moveToNext()){
int newValue = curPdu.getCount();
if (newvalue != currentValue) {
//detected a change
currentValue = newValue;
}
System.out.println(newValue);
}
}
Instead of checking every second if your element was changed, you might want to consider an alternative: allow only special access to this element, and do something once it is changed.
This this is a well known design pattern and is called the Observer Pattern.
This is a well-proven design pattern, which will make your code more readable, and will probably also enhance performance, and correctness of your application.
EDIT:
In java, you can use the Observer interface and Observable class in order to do so.
you can regsister a braodcastreceiver for new coming mms and this way you will come to know that the change has taken place..