I am trying to figure out how to pass a null argument in the constructor, but I am getting this error:
Don't explicitly initialize variables to null
class Dog {
final id int;
final String name;
final int age;
Dog({this.id=null, this.name, this.age});
}
I don't want to pass an id to the constructor. I want to call the constructor like this:
var dog = Dog(
name: 'Rex',
age: 15,
);
How do I accomplish this?
By not explicitly assigning to null
class Dog {
final id int;
final String name;
final int age;
Dog({this.id, this.name, this.age});
}
Remember, be default value of id is set to null. So if the consumer doesn't pass a value for id it will continue to have null and so will name
If you want to make any parameter mandatory then you should mark that with #required
If you don't set variable the default value will be null.
Related
When I compile the following code:
class Student {
int id;
Student() {
this.id = 12345;
}
}
void main() {
var student1 = new Student();
}
I get the following error:
Error: Field 'id' should be initialized because its type 'int' doesn't
allow null.
But why do I get this error? I did initialize id in the constructor!
In Dart, the creation of objects are split into two phases:
Initialization of all values.
Execution of constructor body.
So when you are running code inside the constructor body (between the {...} in the constructor definition) then all class defined variables must have been provided a default value that is valid for the type of variable.
In your case, the variable is typed int but are not provided a default value. In Dart, all variable will by default be set to null in case of no other value provided. But since int is a non-nullable type it does not allow null to be a value and the compiler are therefore giving you the error.
The solution are to provide a value before the constructor is running. You can do that like this:
class Student {
int id;
Student() : id = 12345;
}
Or:
class Student {
int id = 12345;
Student(); // The constructor can in theory just be removed here
}
In case you cannot define a value as part of the initialization phase, you can (but should be prevented if possible) mark the variable as late which makes it so you promise, the Dart compiler, that you are going to provide a value for the variable before the first time you are trying to read from that variable:
class Student {
late int id;
Student() {
this.id = 12345;
}
}
In case you are trying to read from id before it have been provided a value, the program will crash with a LateInitializationError at runtime.
And at last, you can set the type to be a nullable type, like int?, to allow the variable to have a default value of null. But doing so will require you to check for null when you are trying to do something with the value in a context where null is not allowed:
class Student {
int? id;
Student() {
this.id = 12345;
}
}
I have the following basic class with its constructor in Dart:
class ChartData {
String? name;
Color? color;
Duration? duration;
ChartData(
String name, List rgbo, Duration duration) {
this.name = name;
this.color = Color.fromRGBO(rgbo[0], rgbo[1], rgbo[2], rgbo[3]);
this.duration = duration;
}
}
How can I make it so that the constructor arguments are required, and the class arguments are non-nullable thus don't need any null safety? I'm aware of the keyword required, but from what I understand it works only for initializing formal class constructors.
How could we use initializing formal for this class, especially regarding constructing the color class argument?
First of all, you should use an initializer list to initialize the fields, not do assignments in the constructor body. Dart is like C++ in that regard, not Java.
class ChartData {
final String name;
final Color color;
final Duration duration;
ChartData(String name, List<int> rgbo, Duration duration)
: this.name = name,
this.color = Color.fromRGBO(rgbo[0], rgbo[1], rgbo[2], rgbo[3]),
this.duration = duration;
}
This change allows your fields to be final and non-nullable, because now they are initialized before they can ever be read. Your arguments are required. They already were, but they still are.
If you want to use initializing formals, and you do, you can replace an initializer list entry of the form this.name = name (or name = name, because the this is already optional) with a parameter of the form this.name:
class ChartData {
final String name;
final Color color;
final Duration duration;
ChartData(this.name, List<int> rgbo, this.duration)
: color = Color.fromRGBO(rgbo[0], rgbo[1], rgbo[2], rgbo[3]);
}
The color parameter cannot be an initializing formal because it doesn't store the argument directly into the field. Just keep that as an initializer list entry instead.
This works, the fields are final and non-nullable, the parameters are required and non-nullable, and you use initializing formals where possible.
You asked about required. That modifier works with named parameters, and your parameters are positional.
If you wanted them to be named instead, you could write it as:
class ChartData {
final String name;
final Color color;
final Duration duration;
ChartData(
{required this.name, required List<int> rgbo, required this.duration})
: color = Color.fromRGBO(rgbo[0], rgbo[1], rgbo[2], rgbo[3]);
}
The {...} surrounding the parameters makes them named. Required named parameters need a required in front, named parameters default to being optional.
Whether you like required named parameters or not is a matter of taste. Some hate writing and reading the extra name, others prefer it because they find it easier to read.
Either version works.
To set the arguments to non-null, you must add required to each argument in a constructor.
If you want to initialize the arguments, you could call the class and set the values. Also you can initialize in some initState()
For example:
class ChartData {
String name;
Color color;
Duration duration;
ChartData({
required this.name,
required this.color,
required this.duration
});
}
class OtherClass extends StatelessWidget {
//initialize
final chartData = ChartData(
name: "name1",
color: Color.fromRGBO(38, 38, 38, 0.4),
duration: const Duration(seconds:15));
#override
Widget build(BuildContext context) {
return Container();
}
}
why there is error while am trying to construct my constructor i want to have a named paramters but not required ones how i can fix this
class Task {
int id;
String title;
String description;
**Task({this.id , this.title , this.description}); // Giving me Errors here**
Map<String , dynamic> toMap()
{
return {
'id' : id,
'title' : title,
'description' : description,
};
}
#override
String toString() {
return 'Task{id: $id, name: $title, age: $description}';
}
}
If you don't want the arguments to be required, you have to allow them to be null by adding a question mark to their type, so Dart will know that they don't need to be initialized. Like this:
int? id;
String? title;
String? description;
Another solution is to give them a default value in the constructor, but be careful to assign them values that won't conflict with the rest of your code:
Task({this.id=-1, this.title='Title' , this.description = 'Description'});
Choose the approach that suits you best: you can also use a mix of the two solutions, like making some properties nullable and giving a default value to the others.
I encountered a problem when writing the constructor in dart. I have a class with two final variables, initialize them in the constructor, the following is wrong, because the final variable has no setter method:
class Person{
final String name;
final int age;
// Error
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
but this is correct, why
class Person{
final String name;
final int age;
// Correct
Person(String name, int age): this.name = name, this.age = age;
}
When the constructor body is executed, final fields are already sealed.
The constructor initializer list is executed before the constructor initializers of the super classes.
The constructor bodies are executed afterwards. Constructor body allows arbitrary code to be executed like reading from fields. This is why at this point the initialization of final fields has to be completed already, otherwise it would be possible to read from a not yet initialized final field.
The constructor initializer list is the supported window where final fields can be initialized. It does not allow reading from this (explicit or implicit) and is therefore safe.
This is just a measure to ensure object initialization always happens in predictable manner.
I get the following error when using a primitive attribute in my grails domain object:
Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
at grails.orm.HibernateCriteriaBuilder.invokeMethod(HibernateCriteriaBuilder.java:1077)
According to this SO thread, the solution is to use the non-primitive wrapper types; e.g., Integer instead of int.
A null value cannot be assigned to a primitive type, like int, long, boolean, etc. If the database column that corresponds to the field in your object can be null, then your field should be a wrapper class, like Integer, Long, Boolean, etc.
The danger is that your code will run fine if there are no nulls in the DB, but will fail once nulls are inserted.
And you can always return the primitive type from the getter. Ex:
private Integer num;
public void setNum(Integer i) {
this.num = i;
}
public int getNum() {
return this.num;
}
But in most cases you will want to return the wrapper class.
So either set your DB column to not allow nulls, or use a wrapper class.
A primitive type cannot be null. So the solution is replace primitive type with primitive wrapper class in your tableName.java file.
Such as:
#Column(nullable=true, name="client_os_id")
private Integer client_os_id;
public int getClient_os_id() {
return client_os_id;
}
public void setClient_os_id(int clientOsId) {
client_os_id = clientOsId;
}
reference http://en.wikipedia.org/wiki/Primitive_wrapper_class to find wrapper class of a primivite type.
I'll try to make you understand with the help of an example. Suppose you had a relational table (STUDENT) with two columns and ID(int) and NAME(String). Now as ORM you would've made an entity class somewhat like as follows:-
package com.kashyap.default;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* #author vaibhav.kashyap
*
*/
#Entity
#Table(name = "STUDENT")
public class Student implements Serializable {
/**
*
*/
private static final long serialVersionUID = -1354919370115428781L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "NAME")
private String name;
public Student(){
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Lets assume table already had entries. Now if somebody asks you add another column of "AGE" (int)
ALTER TABLE STUDENT ADD AGE int NULL
You'll have to set default values as NULL to add another column in a pre-filled table. This makes you add another field in the class. Now the question arises whether you'll be using a primitive data type or non primitive wrapper data type for declaring the field.
#Column(name = "AGE")
private int age;
or
#Column(name = "AGE")
private INTEGER age;
you'll have to declare the field as non primitive wrapper data type because the container will try to map the table with the entity. Hence it wouldn't able to map NULL values (default) if you won't declare field as wrapper & would eventually throw "Null value was assigned to a property of primitive type setter" Exception.
use Integer as the type and provide setter/getter accordingly..
private Integer num;
public Integer getNum()...
public void setNum(Integer num)...
#Column(name ="LEAD_ID")
private int leadId;
Change to
#Column(name ="LEAD_ID")
private Integer leadId;
There are two way
Make sure that db column is not allowed null
User Wrapper classes for the primitive type variable like private int var; can be initialized as private Integer var;
Do not use primitives in your Entity classes, use instead their respective wrappers. That will fix this problem.
Out of your Entity classes you can use the != null validation for the rest of your code flow.
Either fully avoid null in DB via NOT NULL and in Hibernate entity via #Column(nullable = false) accordingly or use Long wrapper instead of you long primitives.
A primitive is not an Object, therefore u can't assign null to it.
#Dinh Nhat, your setter method looks wrong because you put a primitive type there again and it should be:
public void setClient_os_id(Integer clientOsId) {
client_os_id = clientOsId;
}
Change the parameter type from primitive to Object and put a null check in the setter. See example below
public void setPhoneNumber(Long phoneNumber) {
if (phoneNumber != null)
this.phoneNumber = phoneNumber;
else
this.extension = 0l;
}
Make sure your database myAttribute field contains null instead of zero.