I'm new to drools and I succeded in creating a working application that uses the created rules. I have a simple class Message with two variables type and language.
public class Message {
private String type;
private String language;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
}
My rules are implemented as
rule "test_auto"
when
message:Message (( type == 'string1' ) && ( language == 'string2' ) )
then
...
end
If the user inserts some strange values for both type or language , I have a particular rule that returns an error. But on top of that I wanted to know if it is possible to return also the list of all the possible variables inserted in the rules: for example string1 and string2.
I guess you mean "string literals" and not variables?
There's a class for representing a rule; with classes for patterns and constraints. But these are "not stable", and it is generally not advisable to base an application on them.
If you have several rules catching some bad combination of Message.type and Message.language, you might consider inserting Facts according to
class BadMessage {
String type;
String language;
}
with all those "bad" combinations, and a single rule
rule "catch bad messages"
when
$m: Message'( $t: type, $l: language )
BadMessage( type == $t, language == $l )
then
// handle $m as a "bad" message
As an aside, note that you can write your pattern simply as
message: Message( type == "string1", language == "string2" )
Related
Is there a way to avoid calling this.field for every field in a class ?
public class Test {
private String name;
private String email;
public Test(String name, String email) {
// I want to avoid this
this.name = name;
this.email = email;
}
public Test(Test test) {
// Something like this would be perfect, setting both name and email to test
this(test);
}
}
The use of this is only required in cases of name collisions, to resolve the ambiguity.
Some programmers like me prefer using the this. prefix routinely, whereas other use only where necessary.
See Answer by Wasserman for an example of how to avoid naming collision.
Use the IDE, Luke
Your IDE will generate constructors, accessors (getters/setters), equals & hashCode, toString, and so on. So you need not type this.; let the machine do the typing.
Use custom settings to control whether you want the IDE to include or omit this. prefixes.
record
You may be interested in using the records feature, new in Java 16+. A record is a brief way to write a class whose main purpose is to communicate data transparently and immutably.
With a record, by default, the compiler implicitly writes the constructor, getters, equals & hashCode, and toString. The implicitly created constructor populates each and every member field on your behalf. You write none of that code.
Here is your entire example class when written as a record. No this required. All your member fields are automatically assigned.
public record Test ( String name , String email ) {}
Be cautious in using records. The reason for their invention was not writing less code. The reason was to provide an explicit mechanism for transmitting immutable data transparently, a “nominal tuple” in academic-speak. Less boilerplate coding is merely a nice side-effect. I highly recommend reading JEP 395 for more explanation.
Tip: You can combine the two points of this Answer. Ask your IDE to generate a full-blown class by starting with a record.
Write a record with all your member fields listed in the parentheses.
Invoke your IDE to convert from a record to a class.
Voilà, you have a complete class with constructor, accessors, equals & hashCode, and toString all written out with an absolute minimum of typing by you.
For example, in IntelliJ 2022, choosing Convert record to class from the light-bulb icon menu turns this:
public record Test ( String name , String email ) {}
… into this:
package work.basil.example.recs;
import java.util.Objects;
public final class Test
{
private final String name;
private final String email;
public Test ( String name , String email )
{
this.name = name;
this.email = email;
}
public String name ( ) { return name; }
public String email ( ) { return email; }
#Override
public boolean equals ( Object obj )
{
if ( obj == this ) { return true; }
if ( obj == null || obj.getClass() != this.getClass() ) { return false; }
var that = ( Test ) obj;
return Objects.equals( this.name , that.name ) &&
Objects.equals( this.email , that.email );
}
#Override
public int hashCode ( )
{
return Objects.hash( name , email );
}
#Override
public String toString ( )
{
return "Test[" +
"name=" + name + ", " +
"email=" + email + ']';
}
}
Caveat: That result may not be the default. I may have altered the settings in IntelliJ.
Sorry, the only way to avoid this is to have different names for your constructor parameters and for your class fields.
public Test(String _name, String _email) {
// I want to avoid this
name = _name;
email = _email;
}
That said, you might have better luck using Java 16+'s record syntax.
As suggested, using records is the easiest way:
public record Test (String name, String email) {
}
That's all you need. What you then get:
A constructor that takes all arguments, in the same order as the field list
A method for each field. This does not start with get. In this case, the methods are name() and email().
equals, hashCode and toString implementations that use all fields.
There is no need for a copy constructor, because every field is automatically final.
If you want, you can add extra constructors. However, they must delegate to the automatically generated constructor, because that's the one that sets the fields. Adding additional utility methods is also fine.
And if needed, you can add validation to the generated constructor. There's special syntax that allows you to omit all the field names:
public record Test (String name, String email) {
public Test {
Objects.requireNonNull(name);
Objects.requireNonNull(email);
}
}
The assignments are done for you, there's no need to type those either.
You need this.x everytime, if there are 2 or more variables, which are called x and you want to call the attribute variable x.
The this keyword is used, to point on an attribute variable of the created instance (object) of the class.
There could be an attribute, that is called x, and a local variable which is called x too.
Is there any option in java to Create an enum with true and false like below,
public enum options {
true,
false,
both
}
Now getting unexpected token error as I am using true and false. thank you
Regards
haru
No. From JLS 8.9.1, an enum constant is defined in the syntax to be
EnumConstant:
{EnumConstantModifier} Identifier [( [ArgumentList] )] [ClassBody]
So it's an Identifier. And from JLS 3.8, and Identifier is defined to be
Identifier:
IdentifierChars but not a Keyword or BooleanLiteral or NullLiteral
Hence, an identifier is any valid string of identifier characters (basically letters and numbers, but with Unicode support thrown in) that is not a keyword (like if) or the words true, false, or null.
Realistically, you should be capitalizing your enum names anyway, so it would look more like
public enum Options {
TRUE, FALSE, BOTH
}
which poses no issues as TRUE and FALSE aren't Boolean literals in Java.
The values of your enum should be formatted like constants; all-caps with underscores between words (if they are more than one word, which in your case, they are not). If you need to be able to convert them to/from strings that do not match the name and case of the enum constants, I would suggest adding a parameter with the string and methods to convert in each direction:
public enum Options {
TRUE("true"),
FALSE("false"),
BOTH("both");
private final String description;
private Options(final String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public static Options parse(String description) {
for (Options option : Options.values()) {
if (option.getDescription().equals(description)) {
return option;
}
}
throw new IllegalArgumentException("no such option: " + description);
}
}
If you call Options.parse("true") it will return Options.TRUE and if you call Options.TRUE.getDescription() it will return "true". If you call Options.parse("none") it will throw an IllegalArgumentException.
I have to do a little exercise (homework, like a friendlist) in Java, and i'm a little stuck on one of the tasks that i have to implement in my program.
The exercise is about storing some friend-objects with a variety of attributes in a container-class and implementing some methods in the container-class for various tasks on the friend-objects.
The overall exercise is not a problem at all, but i'm quite unconvinced that my solution is the way to go. I hope you can give me some tips here.
The method that is left over, should be something like a "updateFriend" method, with which you can set the value of a given attribute to a new value, straight from the container-class.
I've already set up my friend-class with a handfull of attributes (e.g. prename, lastname, date of birth, adress, and so on) an getters/setters for all of them. I've also implemented the container-class (as an ArrayList), but i can't seem to find an elegant way to implement this specific method. My updateFriend()-method right now takes three parameters.
1.The specific id of the friend-object
2.The name of the attribute that i want to change
3.The new value of the attribute
It uses an enum to check if the entered attribute is an existing attribute and if yes, the method searches the ArrayList for the object that contains that attribute and should overwrite the existing value. It gets a little bulky, as i have implemented a switch on the enum, that calls the fitting setter-method for each attribute of the friend, if the type in attribute exists at all.
So basically the friend-class looks like this:
public class Friend {
private static int friendCount = 1;
private String firstname;
private String lastname;
private LocalDate dateOfBirth;
private String phonenumber;
private String mobilenumber;
private String eMail;
private Adress home;
private int friendID;
//Getters & Setters
...
}
The method that gives me problems in the container-class looks something like this at the moment:
public void updateFriend(int id, String toChange, String newValue)
{
for(Attribute a : attribute.values())
{
if(String.valueOf(a).equalsIgnoreCase(toChange))
{
for(Friend f : friends)
{
int counter = 1;
if(f.getID() == id)
{
switch(a)
{
case FIRSTNAME:
{
f.setPreName(neuerWert);
break;
}
//a case for each attribute
}
I'm quite certain that my take on the given method is messy, slow, and cumbersome. What would be an elegant way of solving this?
Excuse my wording and thanks in advance, greets.
I would suggest 3 performance improvements.
Use HashMap instead of List with key as id. Since, id will be unique, it will take O(1) time to get the relevant object for modification instead of spending O(n) time on List iteration.
You can change the type of toChange parameter from String to enum. This will avoid enum to String conversion and then comparing it.
Since, you are already doing validation of the attribute to be modified and you must be following standard java convention while naming your getters and setters, you can use reflection to call the method on the Friend object by creating the method name from attribute name like set{Attributename}.
Okay, lets start using the enum Attribute to handle all the changes (Since you already holding the attribute values)
Attribute Enum
public enum Attribute {
FIRSTNAME("fname", (friend, name) -> friend.setFirstname(String.valueOf(name))),
LASTNAME("lname", (friend, lname) -> friend.setLastname(String.valueOf(lname))),
DATEOFBIRTH("dob", (friend, dob) -> friend.setDateOfBirth((LocalDate) dob)),
PHONENUMBER("pno", (friend, pno) -> friend.setFirstname(String.valueOf(pno))),
MOBILENUMBER("mno", (friend, mno) -> friend.setFirstname(String.valueOf(mno)));
private String attributeName;
private BiConsumer<Friend, Object> attributeSetter;
public static Attribute getAttributeSetterByName(String attributeName) {
return Arrays.stream(Attribute.values())
.filter(attribute -> attribute.getAttributeName().equalsIgnoreCase(attributeName))
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format("Invalid Attribute name - %s", attributeName)));
//.orElse(null);
}
//Getter, Setter & Args Constructor (Use Lombok to reduce Boiler Plate code)
}
Update Logic
public void updateFriend(int id, String toChange, String newValue) {
Attribute attribute = Attribute.getAttributeSetterByName(toChange);
for (Friend friend : friends) {
if (friend.getId() == id) {
attribute.getAttributeSetter().accept(friend, newValue);
break;
}
}
}
You can use a java.util.function.Consumer<T> object to change an object inside your container where you have all the type safety you get. Instead of having magic strings and string arguments for values, which might not be even for string fields, you can work directly on the objects type:
public void updateFriend(int id, Consumer<Friend> c) {
// find the friend object
Friend found = null;
for (Friend f: this.friends) {
if (f.getId() == id) {
found = f;
break;
}
}
if (found == null) {
throw new IllegalArgumentException("There is no friend object with the given id");
}
// use the friend object.
c.accept(found);
}
You can use this method like this:
container.updateFriend(42, f -> f.setVorName("abc"));
container.updateFriend(9, f -> f.setAddress(some_address_object));
I should take from a variable enum its value and transform it to string.how can i do?
here it is the type enum:
public enum State{
b,c,p;
};
now i have to insert into an object String one value.
You might use enum.name orenum.toString to get the name of the enum constant, or enum.ordinal to get the ordinal position.
you can use name() or toString(), so :
State aState = State.c;
String strState = aState.name();
See here the official java reference for more information...
State.b.toString() will return "b". The same goes for the other ones.
Usually,
State state = ...;
String string = state.toString();
should work, but it is not recommended since someone might override toString for some other purpose.
Instead the method you are looking for is
String string = state.name();
As an aside, your enumerated stated should always be all in capitals, and they should have descriptive names. It's not a language rule, but a convention. For example enum State { ON, OFF, PAUSED; }.
I tend to do something more complicated, but I find that it's more flexible:
public enum MyEnumeration {
SOME_NAME("Some Name"),
OTHER_THING("Other Thing"),
...
MORE_VALUES("More Values"),
private final String displayName;
private MyEnumeration(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
This way, I use standard capitalization for my enums in code, but can have a more presentable name for them.
This trick can also be used to replace ordinal, by initializing a number, and then you don't need to worry about rearranging your enums.
Method #1: Using the built-in toString() and name() methods
If you want to print a String that is the same as the value of the State, then you can use the toString() method, or the name() method.
System.out.println(State.b); // Prints "b"
System.out.println(State.c); // Prints "c"
System.out.println(State.p); // Prints "p"
Method #2: Using a constructor to create a custom mapping
If you want to have a custom String associated with each of those states, you can use a constructor to associate a particular value with each enum value:
public enum State{
b("State B"), c("State C"), p("State P");
private String longName;
private State(String longName) {
this.longName = longName;
}
#Override
public String toString() {
return this.longName;
}
};
Of course, if you don't want to break the default toString() usage, you can create a different method called getFullName(), for example, to return the custom value.
In Java I can do something like this:
enum Country {
IRELAND("Europe"),
FRANCE("Europe"),
NIGERIA("Africa"),
THAILAND("Asia");
private String continent;
Country(String continent) {
this.continent = continent;
}
public String getContinent() {
return continent;
}
}
which allows me to do something like:
Country country1 = getCountryFromSomewhere();
Country country2 = Country.FRANCE;
System.out.print("country1 is in " + country1.getContinent());
System.out.print("country2 is in " + country2.getContinent());
Is it possible to do the same thing in VB.NET i.e. add the continent attribute to the country enum?
(Apologies for using C# throughout - I believe the concepts are more about .NET than the language you happen to use; hopefully you're better at reading C# than I am at writing VB.)
Not directly - enums in .NET are just integer types with names for some of the values.
The closest you can come in .NET is to create a type with a fixed set of values. For example, in your case:
public sealed class Country
{
public static readonly Country Ireland = new Country("Europe");
public static readonly Country France = new Country("Europe");
public static readonly Country Nigeria = new Country("Africa");
public static readonly Country Thailand = new Country("Asia");
private readonly string continent;
public string Continent { get { return continent; } }
private Country(string continent)
{
this.continent = continent;
}
}
(I assume the VB.NET would be very similar.)
Note that this doesn't let you switch on the enum values.
If you want polymorphism, you can create nested subclasses which can still call the private constructor, which prevents any other subclasses being created.
One alternative to this is to use attributes on normal enums:
[AttributeUsageAttribute(AttributeTargets.Field)]
public class ContinentAttribute : Attribute
{
// etc
}
public enum Country
{
[Continent("Europe")] Ireland = 1,
[Continent("Europe")] France = 2,
...
}
You'd then need to use reflection to get at the ContinentAttribute and retrieve the string.
Note that here there isn't really a fixed set of values - you could write:
Country country = (Country) 15;
At that point you can't get the continent for it, and if you pass it to any methods which expect it to be a real country, you've got problems. That isn't the case with the earlier solution, where you really are restricted to those few values (and null).
Here is the code:
Imports System.ComponentModel
Imports System.Reflection
Public Enum enumOrderStatus
<Description("None")>
None
<Description("Sent")>
Sent
<Description("Accepted")>
Accepted
<Description("Cancelled")>
Cancelled
<Description("Declined")>
Declined
End Enum
Public Function GetEnumDescription(ByVal EnumConstant As [Enum]) As String
Dim fi As FieldInfo = EnumConstant.GetType().GetField(EnumConstant.ToString())
Dim aattr() As DescriptionAttribute = DirectCast(fi.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
If aattr.Length > 0 Then
Return aattr(0).Description
Else
Return EnumConstant.ToString()
End If
End Function
I used this solution instead:
Declare enum:
Private Enum Country
IRELAND
FRANCE
THAILAND
End Enum
Declare and initialise Dictionary (aka a map):
Dim countryContinentMap As IDictionary(Of Country, String) = New Dictionary(Of Country, String)
countryContinentMap.add(Country.IRELAND, "Europe")
countryContinentMap.add(Country.FRANCE, "Europe")
countryContinentMap.add(Country.THAILAND, "Asia")
which allows me to get the continent like this:
Dim franceContinent As String = countryContinentMap(Country.FRANCE)
Here is how I solved this in my application. Still looking for something even easier.
What do you think about it?
Public Sub Init()
Dim values() As Integer = CType([Enum].GetValues(GetType(MyEnum)), Integer())
For i As Integer = 0 To values.Count - 1
Me.contextMenuInGUI.Items.Add(Me.GetEnumDescription(i))
Next
End Sub
Private Function GetEnumDescription(ByVal i As Integer) As String
Select Case i
Case MyEnum.Comment
Return "Description for Comment"
Case MyEnum.SomeEnumValueInCamelCase
Return "Value without camel case (€)(%)(#)"
End Select
Return "Add a case in Class:GetEnumDescription"
End Function
Create an extension method for your Enum
Usage example:
dim description = TableTag.Important.GetDescription()
Definition example:
Imports System.ComponentModel
Imports System.Reflection
Imports System.Runtime.CompilerServices
Namespace Foo
Public Enum TableTag
<Description("Identifies tables that should be availible for writing as table or view to the model database")>
Important
<Description("Example for a table group that helps to select disctinct tables")>
CustomGroup
End Enum
Public Module TableTagExtensions
<Extension>
Public Function GetDescription(enumValue As TableTag) As String
Dim fieldInfo As FieldInfo = enumValue.GetType().GetField(enumValue.ToString())
Dim attributes = DirectCast(fieldInfo.GetCustomAttributes(GetType(DescriptionAttribute), False), DescriptionAttribute())
If attributes.Length > 0 Then
Return attributes(0).Description
Else
Return enumValue.ToString()
End If
End Function
End Module
End Namespace